summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/magic-number.txt25
-rw-r--r--Documentation/pnp.txt4
-rw-r--r--Makefile3
-rw-r--r--arch/alpha/kernel/irq.c2
-rw-r--r--arch/i386/kernel/cpu/mtrr/cyrix.c6
-rw-r--r--arch/i386/kernel/cpu/mtrr/main.c62
-rw-r--r--arch/i386/pci/visws.c7
-rw-r--r--arch/ia64/kernel/module.c4
-rw-r--r--arch/m68k/apollo/dn_ints.c4
-rw-r--r--arch/m68k/q40/q40ints.c2
-rw-r--r--arch/mips/mm/fault.c2
-rw-r--r--arch/mips/ramdisk/Makefile2
-rw-r--r--arch/ppc64/boot/Makefile2
-rw-r--r--arch/sparc/kernel/process.c12
-rw-r--r--arch/v850/Kconfig87
-rw-r--r--arch/v850/kernel/Makefile24
-rw-r--r--arch/v850/kernel/anna.c60
-rw-r--r--arch/v850/kernel/as85ep1.c26
-rw-r--r--arch/v850/kernel/fpga85e2c.c10
-rw-r--r--arch/v850/kernel/gbus_int.c8
-rw-r--r--arch/v850/kernel/head.S15
-rw-r--r--arch/v850/kernel/highres_timer.c26
-rw-r--r--arch/v850/kernel/intv.S4
-rw-r--r--arch/v850/kernel/ma.c8
-rw-r--r--arch/v850/kernel/me2.c74
-rw-r--r--arch/v850/kernel/rte_cb.c20
-rw-r--r--arch/v850/kernel/rte_ma1_cb.c8
-rw-r--r--arch/v850/kernel/rte_me2_cb.c308
-rw-r--r--arch/v850/kernel/rte_nb85e_cb.c4
-rw-r--r--arch/v850/kernel/sim85e2.c (renamed from arch/v850/kernel/sim85e2c.c)118
-rw-r--r--arch/v850/kernel/teg.c8
-rw-r--r--arch/v850/kernel/v850e2_cache.c127
-rw-r--r--arch/v850/kernel/v850e_cache.c (renamed from arch/v850/kernel/nb85e_cache.c)109
-rw-r--r--arch/v850/kernel/v850e_intc.c (renamed from arch/v850/kernel/nb85e_intc.c)34
-rw-r--r--arch/v850/kernel/v850e_timer_d.c (renamed from arch/v850/kernel/nb85e_timer_d.c)38
-rw-r--r--arch/v850/kernel/v850e_utils.c (renamed from arch/v850/kernel/nb85e_utils.c)13
-rw-r--r--arch/v850/rte_me2_cb.ld30
-rw-r--r--arch/v850/sim85e2.ld (renamed from arch/v850/sim85e2c.ld)34
-rw-r--r--arch/v850/vmlinux.lds.S9
-rw-r--r--drivers/block/Kconfig3
-rw-r--r--drivers/block/as-iosched.c17
-rw-r--r--drivers/block/cciss_scsi.c3
-rw-r--r--drivers/block/elevator.c13
-rw-r--r--drivers/block/ioctl.c6
-rw-r--r--drivers/block/ll_rw_blk.c18
-rw-r--r--drivers/block/nbd.c3
-rw-r--r--drivers/char/agp/i460-agp.c2
-rw-r--r--drivers/char/ftape/lowlevel/fdc-io.c40
-rw-r--r--drivers/char/ftape/lowlevel/ftape-calibr.c22
-rw-r--r--drivers/char/ftape/lowlevel/ftape-format.c6
-rw-r--r--drivers/char/ftape/zftape/zftape-init.c2
-rw-r--r--drivers/char/ip2.c18
-rw-r--r--drivers/char/ip2/i2lib.c2
-rw-r--r--drivers/char/ip2/i2os.h18
-rw-r--r--drivers/char/ip2main.c328
-rw-r--r--drivers/char/watchdog/acquirewdt.c2
-rw-r--r--drivers/char/watchdog/i810-tco.c12
-rw-r--r--drivers/char/watchdog/i810-tco.h4
-rw-r--r--drivers/char/watchdog/ib700wdt.c2
-rw-r--r--drivers/char/watchdog/indydog.c2
-rw-r--r--drivers/char/watchdog/machzwd.c2
-rw-r--r--drivers/char/watchdog/pcwd.c2
-rw-r--r--drivers/char/watchdog/sbc60xxwdt.c5
-rw-r--r--drivers/char/watchdog/sc520_wdt.c2
-rw-r--r--drivers/char/watchdog/shwdt.c2
-rw-r--r--drivers/char/watchdog/softdog.c5
-rw-r--r--drivers/char/watchdog/wdt977.c2
-rw-r--r--drivers/char/watchdog/wdt_pci.c2
-rw-r--r--drivers/ide/Kconfig30
-rw-r--r--drivers/md/Kconfig7
-rw-r--r--drivers/md/dm-ioctl-v1.c1160
-rw-r--r--drivers/md/dm-ioctl-v4.c1252
-rw-r--r--drivers/md/dm-ioctl.c1132
-rw-r--r--drivers/md/dm-table.c32
-rw-r--r--drivers/md/dm.c95
-rw-r--r--drivers/md/dm.h16
-rw-r--r--drivers/net/Kconfig2
-rw-r--r--drivers/net/ni65.c55
-rw-r--r--drivers/net/ni65.h103
-rw-r--r--drivers/net/pcmcia/Kconfig2
-rw-r--r--drivers/net/seeq8005.c5
-rw-r--r--drivers/parport/parport_pc.c6
-rw-r--r--drivers/pcmcia/ricoh.h33
-rw-r--r--drivers/pcmcia/ti113x.h90
-rw-r--r--drivers/pcmcia/yenta_socket.c2
-rw-r--r--drivers/pnp/isapnp/core.c10
-rw-r--r--drivers/scsi/53c700.c25
-rw-r--r--drivers/scsi/NCR_D700.c4
-rw-r--r--drivers/scsi/NCR_Q720.c11
-rw-r--r--drivers/scsi/aha152x.c15
-rw-r--r--drivers/scsi/aha1542.h1
-rw-r--r--drivers/scsi/aha1740.c26
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_osm.c3
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_osm.c3
-rw-r--r--drivers/scsi/arm/acornscsi.c8
-rw-r--r--drivers/scsi/arm/cumana_1.c8
-rw-r--r--drivers/scsi/arm/ecoscsi.c3
-rw-r--r--drivers/scsi/arm/fas216.c2
-rw-r--r--drivers/scsi/arm/oak.c8
-rw-r--r--drivers/scsi/dc395x.c3
-rw-r--r--drivers/scsi/hosts.c22
-rw-r--r--drivers/scsi/ide-scsi.c4
-rw-r--r--drivers/scsi/ips.h2
-rw-r--r--drivers/scsi/lasi700.c4
-rw-r--r--drivers/scsi/nsp32.c3
-rw-r--r--drivers/scsi/pas16.c1
-rw-r--r--drivers/scsi/pcmcia/aha152x_stub.c3
-rw-r--r--drivers/scsi/pcmcia/fdomain_stub.c3
-rw-r--r--drivers/scsi/pcmcia/nsp_cs.c3
-rw-r--r--drivers/scsi/pcmcia/qlogic_stub.c3
-rw-r--r--drivers/scsi/qla1280.c2
-rw-r--r--drivers/scsi/qlogicfas.c1
-rw-r--r--drivers/scsi/scsi.h5
-rw-r--r--drivers/scsi/scsi_debug.c5
-rw-r--r--drivers/scsi/scsi_lib.c28
-rw-r--r--drivers/scsi/scsi_module.c1
-rw-r--r--drivers/scsi/scsi_priv.h6
-rw-r--r--drivers/scsi/scsi_scan.c3
-rw-r--r--drivers/scsi/scsi_syms.c1
-rw-r--r--drivers/scsi/scsi_sysfs.c307
-rw-r--r--drivers/scsi/sd.c31
-rw-r--r--drivers/scsi/sim710.c3
-rw-r--r--drivers/scsi/sr.c2
-rw-r--r--drivers/scsi/sym53c8xx.c7
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_glue.c5
-rw-r--r--drivers/scsi/zalon.c13
-rw-r--r--drivers/serial/Kconfig19
-rw-r--r--drivers/serial/Makefile2
-rw-r--r--drivers/serial/core.c65
-rw-r--r--drivers/serial/nb85e_uart.c610
-rw-r--r--drivers/serial/v850e_uart.c549
-rw-r--r--drivers/telephony/Kconfig2
-rw-r--r--drivers/usb/image/hpusbscsi.c3
-rw-r--r--drivers/usb/image/microtek.c3
-rw-r--r--drivers/usb/storage/usb.c2
-rw-r--r--drivers/video/vesafb.c10
-rw-r--r--fs/binfmt_elf.c4
-rw-r--r--fs/devfs/base.c17
-rw-r--r--fs/ext3/acl.c4
-rw-r--r--fs/ext3/xattr.c9
-rw-r--r--fs/jbd/transaction.c17
-rw-r--r--fs/jffs2/Makefile1
-rw-r--r--fs/namespace.c10
-rw-r--r--fs/nfs/nfs3xdr.c2
-rw-r--r--fs/partitions/check.c4
-rw-r--r--include/asm-i386/thread_info.h4
-rw-r--r--include/asm-v850/anna.h63
-rw-r--r--include/asm-v850/as85ep1.h36
-rw-r--r--include/asm-v850/asm.h2
-rw-r--r--include/asm-v850/cacheflush.h33
-rw-r--r--include/asm-v850/entry.h4
-rw-r--r--include/asm-v850/fpga85e2c.h28
-rw-r--r--include/asm-v850/highres_timer.h6
-rw-r--r--include/asm-v850/ma.h25
-rw-r--r--include/asm-v850/ma1.h7
-rw-r--r--include/asm-v850/machdep.h13
-rw-r--r--include/asm-v850/me2.h182
-rw-r--r--include/asm-v850/nb85e.h21
-rw-r--r--include/asm-v850/nb85e_cache.h78
-rw-r--r--include/asm-v850/nb85e_timer_c.h48
-rw-r--r--include/asm-v850/nb85e_uart.h144
-rw-r--r--include/asm-v850/processor.h2
-rw-r--r--include/asm-v850/ptrace.h2
-rw-r--r--include/asm-v850/rte_cb.h56
-rw-r--r--include/asm-v850/rte_ma1_cb.h49
-rw-r--r--include/asm-v850/rte_me2_cb.h202
-rw-r--r--include/asm-v850/rte_nb85e_cb.h39
-rw-r--r--include/asm-v850/serial.h58
-rw-r--r--include/asm-v850/sim85e2.h79
-rw-r--r--include/asm-v850/sim85e2c.h70
-rw-r--r--include/asm-v850/sim85e2s.h28
-rw-r--r--include/asm-v850/stat.h2
-rw-r--r--include/asm-v850/system.h2
-rw-r--r--include/asm-v850/teg.h40
-rw-r--r--include/asm-v850/v850e.h21
-rw-r--r--include/asm-v850/v850e2.h69
-rw-r--r--include/asm-v850/v850e2_cache.h74
-rw-r--r--include/asm-v850/v850e_cache.h48
-rw-r--r--include/asm-v850/v850e_intc.h (renamed from include/asm-v850/nb85e_intc.h)76
-rw-r--r--include/asm-v850/v850e_timer_c.h48
-rw-r--r--include/asm-v850/v850e_timer_d.h (renamed from include/asm-v850/nb85e_timer_d.h)40
-rw-r--r--include/asm-v850/v850e_uart.h77
-rw-r--r--include/asm-v850/v850e_uarta.h278
-rw-r--r--include/asm-v850/v850e_uartb.h262
-rw-r--r--include/asm-v850/v850e_utils.h (renamed from include/asm-v850/nb85e_utils.h)14
-rw-r--r--include/linux/blkdev.h5
-rw-r--r--include/linux/dm-ioctl-v1.h149
-rw-r--r--include/linux/dm-ioctl-v4.h237
-rw-r--r--include/linux/dm-ioctl.h147
-rw-r--r--include/linux/elevator.h3
-rw-r--r--include/linux/elfcore.h4
-rw-r--r--include/linux/ext3_jbd.h7
-rw-r--r--include/linux/hfs_sysdep.h3
-rw-r--r--include/linux/namespace.h11
-rw-r--r--include/linux/sched.h1
-rw-r--r--include/linux/serial_core.h2
-rw-r--r--include/linux/tty.h64
-rw-r--r--include/pcmcia/ss.h5
-rw-r--r--include/scsi/scsi_device.h7
-rw-r--r--include/scsi/scsi_host.h24
-rw-r--r--include/scsi/scsi_request.h2
-rw-r--r--kernel/compat.c4
-rw-r--r--kernel/fork.c66
-rw-r--r--kernel/sched.c4
-rw-r--r--kernel/sys.c18
-rw-r--r--kernel/time.c15
-rw-r--r--mm/bootmem.c4
-rw-r--r--mm/slab.c12
-rw-r--r--scripts/ver_linux5
-rw-r--r--sound/isa/cmi8330.c2
-rw-r--r--sound/isa/es18xx.c2
-rw-r--r--sound/oss/Kconfig28
-rw-r--r--sound/oss/Makefile8
-rw-r--r--sound/oss/ac97_plugin_ad1980.c2
-rw-r--r--sound/oss/ad1889.c1
-rw-r--r--sound/oss/btaudio.c8
-rw-r--r--sound/oss/dmasound/dmasound_core.c14
-rw-r--r--sound/oss/emu10k1/8010.h127
-rw-r--r--sound/oss/emu10k1/audio.c62
-rw-r--r--sound/oss/emu10k1/cardmi.c8
-rw-r--r--sound/oss/emu10k1/cardmo.c8
-rw-r--r--sound/oss/emu10k1/cardwo.c148
-rw-r--r--sound/oss/emu10k1/efxmgr.c23
-rw-r--r--sound/oss/emu10k1/efxmgr.h23
-rw-r--r--sound/oss/emu10k1/hwaccess.c132
-rw-r--r--sound/oss/emu10k1/hwaccess.h23
-rw-r--r--sound/oss/emu10k1/irqmgr.h18
-rw-r--r--sound/oss/emu10k1/main.c872
-rw-r--r--sound/oss/emu10k1/midi.h23
-rw-r--r--sound/oss/emu10k1/mixer.c89
-rw-r--r--sound/oss/emu10k1/passthrough.c9
-rw-r--r--sound/oss/emu10k1/passthrough.h29
-rw-r--r--sound/oss/emu10k1/recmgr.c16
-rw-r--r--sound/oss/emu10k1/voicemgr.c46
-rw-r--r--sound/oss/emu10k1/voicemgr.h10
-rw-r--r--sound/oss/hal2.c1498
-rw-r--r--sound/oss/hal2.h328
-rw-r--r--sound/oss/harmony.c1307
-rw-r--r--sound/oss/kahlua.c227
239 files changed, 11653 insertions, 4404 deletions
diff --git a/Documentation/magic-number.txt b/Documentation/magic-number.txt
index e88149116b64..bd8eefa17587 100644
--- a/Documentation/magic-number.txt
+++ b/Documentation/magic-number.txt
@@ -51,6 +51,13 @@ kernel before 2.6.x yet.
<pasky@ucw.cz>
03 Nov 2002
+Updated the magic table to Linux 2.5.74.
+
+ Fabian Frederick
+ <ffrederick@users.sourceforge.net>
+ 09 Jul 2003
+
+
Magic Name Number Structure File
===========================================================================
PG_MAGIC 'P' pg_{read,write}_hdr include/linux/pg.h
@@ -62,10 +69,12 @@ AURORA_MAGIC 0x0A18 Aurora_port drivers/sbus/char/aurora.h
HDLC_MAGIC 0x239e n_hdlc drivers/char/n_hdlc.c
APM_BIOS_MAGIC 0x4101 apm_user arch/i386/kernel/apm.c
CYCLADES_MAGIC 0x4359 cyclades_port include/linux/cyclades.h
+DB_MAGIC 0x4442 fc_info drivers/net/iph5526_novram.c
+DL_MAGIC 0x444d fc_info drivers/net/iph5526_novram.c
FASYNC_MAGIC 0x4601 fasync_struct include/linux/fs.h
+FF_MAGIC 0x4646 fc_info drivers/net/iph5526_novram.c
ISICOM_MAGIC 0x4d54 isi_port include/linux/isicom.h
-PTY_MAGIC 0x5001 (none at the moment)
- drivers/char/pty.c
+PTY_MAGIC 0x5001 drivers/char/pty.c
PPP_MAGIC 0x5002 ppp include/linux/if_pppvar.h
SERIAL_MAGIC 0x5301 async_struct include/linux/serial.h
SSTATE_MAGIC 0x5302 serial_state include/linux/serial.h
@@ -81,9 +90,9 @@ TTY_DRIVER_MAGIC 0x5402 tty_driver include/linux/tty_driver.h
MGSLPC_MAGIC 0x5402 mgslpc_info drivers/char/pcmcia/synclink_cs.c
TTY_LDISC_MAGIC 0x5403 tty_ldisc include/linux/tty_ldisc.h
USB_SERIAL_MAGIC 0x6702 usb_serial drivers/usb/serial/usb-serial.h
+FULL_DUPLEX_MAGIC 0x6969 drivers/net/tulip/de2104x.c
USB_BLUETOOTH_MAGIC 0x6d02 usb_bluetooth drivers/usb/class/bluetty.c
-RFCOMM_TTY_MAGIC 0x6d02 (note at the moment)
- net/bluetooth/rfcomm/tty.c
+RFCOMM_TTY_MAGIC 0x6d02 net/bluetooth/rfcomm/tty.c
USB_SERIAL_PORT_MAGIC 0x7301 usb_serial_port drivers/usb/serial/usb-serial.h
CG_MAGIC 0x00090255 ufs_cylinder_group include/linux/ufs_fs.h
A2232_MAGIC 0x000a2232 gs_port drivers/char/ser_a2232.h
@@ -91,6 +100,7 @@ SOLARIS_SOCKET_MAGIC 0x000ADDED sol_socket_struct arch/sparc64/solaris/socksys
RPORT_MAGIC 0x00525001 r_port drivers/char/rocket_int.h
LSEMAGIC 0x05091998 lse drivers/fc4/fc.c
GDTIOCTL_MAGIC 0x06030f07 gdth_iowr_str drivers/scsi/gdth_ioctl.h
+RIEBL_MAGIC 0x09051990 drivers/net/atarilance.c
RIO_MAGIC 0x12345678 gs_port drivers/char/rio/rio_linux.c
SX_MAGIC 0x12345678 gs_port drivers/char/sx.h
NBD_REQUEST_MAGIC 0x12560953 nbd_request include/linux/nbd.h
@@ -120,6 +130,7 @@ SAVEKMSG_MAGIC1 0x53415645 savekmsg arch/*/amiga/config.c
GDA_MAGIC 0x58464552 gda include/asm-mips64/sn/gda.h
RED_MAGIC1 0x5a2cf071 (any) mm/slab.c
STL_PORTMAGIC 0x5a7182c9 stlport include/linux/stallion.h
+EEPROM_MAGIC_VALUE 0X5ab478d2 lanai_dev drivers/atm/lanai.c
HDLCDRV_MAGIC 0x5ac6e778 hdlcdrv_state include/linux/hdlcdrv.h
EPCA_MAGIC 0x5c6df104 channel include/linux/epca.h
PCXX_MAGIC 0x5c6df104 channel drivers/char/pcxx.h
@@ -127,9 +138,11 @@ KV_MAGIC 0x5f4b565f kernel_vars_s include/asm-mips64/sn/klkern
I810_STATE_MAGIC 0x63657373 i810_state sound/oss/i810_audio.c
TRIDENT_STATE_MAGIC 0x63657373 trient_state sound/oss/trident.c
M3_CARD_MAGIC 0x646e6f50 m3_card sound/oss/maestro3.c
+FW_HEADER_MAGIC 0x65726F66 fw_header drivers/atm/fore200e.h
SLOT_MAGIC 0x67267321 slot drivers/hotplug/cpqphp.h
SLOT_MAGIC 0x67267322 slot drivers/hotplug/acpiphp.h
LO_MAGIC 0x68797548 nbd_device include/linux/nbd.h
+OPROFILE_MAGIC 0x6f70726f super_block drivers/oprofile/oprofilefs.h
M3_STATE_MAGIC 0x734d724d m3_state sound/oss/maestro3.c
STL_PANELMAGIC 0x7ef621a1 stlpanel include/linux/stallion.h
VMALLOC_MAGIC 0x87654320 snd_alloc_track sound/core/memory.c
@@ -137,11 +150,15 @@ KMALLOC_MAGIC 0x87654321 snd_alloc_track sound/core/memory.c
PWC_MAGIC 0x89DC10AB pwc_device drivers/usb/media/pwc.h
NBD_REPLY_MAGIC 0x96744668 nbd_reply include/linux/nbd.h
STL_BOARDMAGIC 0xa2267f52 stlbrd include/linux/stallion.h
+ENI155_MAGIC 0xa54b872d midway_eprom drivers/atm/eni.h
SCI_MAGIC 0xbabeface gs_port drivers/char/sh-sci.h
CODA_MAGIC 0xC0DAC0DA coda_file_info include/linux/coda_fs_i.h
+DPMEM_MAGIC 0xc0ffee11 gdt_pci_sram drivers/scsi/gdth.h
STLI_PORTMAGIC 0xe671c7a1 stliport include/linux/istallion.h
YAM_MAGIC 0xF10A7654 yam_port drivers/net/hamradio/yam.c
CCB_MAGIC 0xf2691ad2 ccb drivers/scsi/ncr53c8xx.c
+QUEUE_MAGIC_FREE 0xf7e1c9a3 queue_entry drivers/scsi/arm/queue.c
+QUEUE_MAGIC_USED 0xf7e1cc33 queue_entry drivers/scsi/arm/queue.c
HTB_CMAGIC 0xFEFAFEF1 htb_class net/sched/sch_htb.c
NMI_MAGIC 0x48414d4d455201 nmi_s include/asm-mips64/sn/nmi.h
diff --git a/Documentation/pnp.txt b/Documentation/pnp.txt
index c9eb5dd64ff4..0a321e722c1c 100644
--- a/Documentation/pnp.txt
+++ b/Documentation/pnp.txt
@@ -22,7 +22,7 @@ user interface is integrated into driverfs.
In addition to the standard driverfs file the following are created in each
device's directory:
id - displays a list of support EISA IDs
-possible - displays possible resource configurations
+options - displays possible resource configurations
resources - displays currently allocated resources and allows resource changes
-activating a device
@@ -60,7 +60,7 @@ DISABLED
- Notice the string "DISABLED". THis means the device is not active.
3.) check the device's possible configurations (optional)
-# cat possible
+# cat options
Dependent: 01 - Priority acceptable
port 0x3f0-0x3f0, align 0x7, size 0x6, 16-bit address decoding
port 0x3f7-0x3f7, align 0x0, size 0x1, 16-bit address decoding
diff --git a/Makefile b/Makefile
index 675c1fb88cee..2bc170c087e4 100644
--- a/Makefile
+++ b/Makefile
@@ -781,7 +781,8 @@ rpm: clean spec
tar -cvz $(RCS_TAR_IGNORE) -f $(KERNELPATH).tar.gz $(KERNELPATH)/. ; \
rm $(KERNELPATH) ; \
cd $(TOPDIR) ; \
- $(CONFIG_SHELL) $(srctree)/scripts/mkversion > .version ; \
+ $(CONFIG_SHELL) $(srctree)/scripts/mkversion > .tmp_version ; \
+ mv -f .tmp_version .version; \
$(RPM) -ta $(TOPDIR)/../$(KERNELPATH).tar.gz ; \
rm $(TOPDIR)/../$(KERNELPATH).tar.gz
diff --git a/arch/alpha/kernel/irq.c b/arch/alpha/kernel/irq.c
index affde6b3cd0f..e45f36e0847d 100644
--- a/arch/alpha/kernel/irq.c
+++ b/arch/alpha/kernel/irq.c
@@ -601,7 +601,7 @@ handle_irq(int irq, struct pt_regs * regs)
if ((unsigned) irq > ACTUAL_NR_IRQS && illegal_count < MAX_ILLEGAL_IRQS ) {
irq_err_count++;
illegal_count++;
- printk(KERN_CRIT "device_interrupt: illegal interrupt %d\n",
+ printk(KERN_CRIT "device_interrupt: invalid interrupt %d\n",
irq);
return;
}
diff --git a/arch/i386/kernel/cpu/mtrr/cyrix.c b/arch/i386/kernel/cpu/mtrr/cyrix.c
index bc8bbfa50ef5..dec2b52759bb 100644
--- a/arch/i386/kernel/cpu/mtrr/cyrix.c
+++ b/arch/i386/kernel/cpu/mtrr/cyrix.c
@@ -330,16 +330,16 @@ cyrix_arr_init(void)
set_mtrr_done(&ctxt); /* flush cache and disable MAPEN */
if (ccrc[5])
- printk("mtrr: ARR usage was not enabled, enabled manually\n");
+ printk(KERN_INFO "mtrr: ARR usage was not enabled, enabled manually\n");
if (ccrc[3])
- printk("mtrr: ARR3 cannot be changed\n");
+ printk(KERN_INFO "mtrr: ARR3 cannot be changed\n");
/*
if ( ccrc[1] & 0x80) printk ("mtrr: SMM memory access through ARR3 disabled\n");
if ( ccrc[1] & 0x04) printk ("mtrr: SMM memory access disabled\n");
if ( ccrc[1] & 0x02) printk ("mtrr: SMM mode disabled\n");
*/
if (ccrc[6])
- printk("mtrr: ARR3 was write protected, unprotected\n");
+ printk(KERN_INFO "mtrr: ARR3 was write protected, unprotected\n");
}
static struct mtrr_ops cyrix_mtrr_ops = {
diff --git a/arch/i386/kernel/cpu/mtrr/main.c b/arch/i386/kernel/cpu/mtrr/main.c
index 3db7d11848a4..bfdb21671bc7 100644
--- a/arch/i386/kernel/cpu/mtrr/main.c
+++ b/arch/i386/kernel/cpu/mtrr/main.c
@@ -64,7 +64,7 @@ __initdata char *mtrr_if_name[] = {
static void set_mtrr(unsigned int reg, unsigned long base,
unsigned long size, mtrr_type type);
-static unsigned int arr3_protected;
+extern int arr3_protected;
void set_mtrr_ops(struct mtrr_ops * ops)
{
@@ -75,23 +75,25 @@ void set_mtrr_ops(struct mtrr_ops * ops)
/* Returns non-zero if we have the write-combining memory type */
static int have_wrcomb(void)
{
- struct pci_dev *dev = NULL;
-
- /* WTF is this?
- * Someone, please shoot me.
- */
-
- /* ServerWorks LE chipsets have problems with write-combining
- Don't allow it and leave room for other chipsets to be tagged */
-
+ struct pci_dev *dev;
+
if ((dev = pci_find_class(PCI_CLASS_BRIDGE_HOST << 8, NULL)) != NULL) {
- if ((dev->vendor == PCI_VENDOR_ID_SERVERWORKS) &&
- (dev->device == PCI_DEVICE_ID_SERVERWORKS_LE)) {
- printk(KERN_INFO
- "mtrr: Serverworks LE detected. Write-combining disabled.\n");
+ /* ServerWorks LE chipsets have problems with write-combining
+ Don't allow it and leave room for other chipsets to be tagged */
+ if (dev->vendor == PCI_VENDOR_ID_SERVERWORKS &&
+ dev->device == PCI_DEVICE_ID_SERVERWORKS_LE) {
+ printk(KERN_INFO "mtrr: Serverworks LE detected. Write-combining disabled.\n");
return 0;
}
- }
+ /* Intel 450NX errata # 23. Non ascending cachline evictions to
+ write combining memory may resulting in data corruption */
+ if (dev->vendor == PCI_VENDOR_ID_INTEL &&
+ dev->device == PCI_DEVICE_ID_INTEL_82451NX)
+ {
+ printk(KERN_INFO "mtrr: Intel 450NX MMC detected. Write-combining disabled.\n");
+ return 0;
+ }
+ }
return (mtrr_if->have_wrcomb ? mtrr_if->have_wrcomb() : 0);
}
@@ -121,7 +123,7 @@ static void init_table(void)
max = num_var_ranges;
if ((usage_table = kmalloc(max * sizeof *usage_table, GFP_KERNEL))
== NULL) {
- printk("mtrr: could not allocate\n");
+ printk(KERN_ERR "mtrr: could not allocate\n");
return;
}
for (i = 0; i < max; i++)
@@ -310,7 +312,7 @@ int mtrr_add_page(unsigned long base, unsigned long size,
return error;
if (type >= MTRR_NUM_TYPES) {
- printk("mtrr: type: %u illegal\n", type);
+ printk(KERN_WARNING "mtrr: type: %u invalid\n", type);
return -EINVAL;
}
@@ -322,7 +324,7 @@ int mtrr_add_page(unsigned long base, unsigned long size,
}
if (base & size_or_mask || size & size_or_mask) {
- printk("mtrr: base or size exceeds the MTRR width\n");
+ printk(KERN_WARNING "mtrr: base or size exceeds the MTRR width\n");
return -EINVAL;
}
@@ -348,7 +350,7 @@ int mtrr_add_page(unsigned long base, unsigned long size,
if (ltype != type) {
if (type == MTRR_TYPE_UNCACHABLE)
continue;
- printk ("mtrr: type mismatch for %lx000,%lx000 old: %s new: %s\n",
+ printk (KERN_WARNING "mtrr: type mismatch for %lx000,%lx000 old: %s new: %s\n",
base, size, attrib_to_str(ltype),
attrib_to_str(type));
goto out;
@@ -364,7 +366,7 @@ int mtrr_add_page(unsigned long base, unsigned long size,
set_mtrr(i, base, size, type);
usage_table[i] = 1;
} else
- printk("mtrr: no more MTRRs available\n");
+ printk(KERN_INFO "mtrr: no more MTRRs available\n");
error = i;
out:
up(&main_lock);
@@ -412,8 +414,8 @@ mtrr_add(unsigned long base, unsigned long size, unsigned int type,
char increment)
{
if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1))) {
- printk("mtrr: size and base must be multiples of 4 kiB\n");
- printk("mtrr: size: 0x%lx base: 0x%lx\n", size, base);
+ printk(KERN_WARNING "mtrr: size and base must be multiples of 4 kiB\n");
+ printk(KERN_DEBUG "mtrr: size: 0x%lx base: 0x%lx\n", size, base);
return -EINVAL;
}
return mtrr_add_page(base >> PAGE_SHIFT, size >> PAGE_SHIFT, type,
@@ -458,28 +460,28 @@ int mtrr_del_page(int reg, unsigned long base, unsigned long size)
}
}
if (reg < 0) {
- printk("mtrr: no MTRR for %lx000,%lx000 found\n", base,
+ printk(KERN_DEBUG "mtrr: no MTRR for %lx000,%lx000 found\n", base,
size);
goto out;
}
}
if (reg >= max) {
- printk("mtrr: register: %d too big\n", reg);
+ printk(KERN_WARNING "mtrr: register: %d too big\n", reg);
goto out;
}
if (is_cpu(CYRIX) && !use_intel()) {
if ((reg == 3) && arr3_protected) {
- printk("mtrr: ARR3 cannot be changed\n");
+ printk(KERN_WARNING "mtrr: ARR3 cannot be changed\n");
goto out;
}
}
mtrr_if->get(reg, &lbase, &lsize, &ltype);
if (lsize < 1) {
- printk("mtrr: MTRR %d not used\n", reg);
+ printk(KERN_WARNING "mtrr: MTRR %d not used\n", reg);
goto out;
}
if (usage_table[reg] < 1) {
- printk("mtrr: reg: %d has count=0\n", reg);
+ printk(KERN_WARNING "mtrr: reg: %d has count=0\n", reg);
goto out;
}
if (--usage_table[reg] < 1)
@@ -508,8 +510,8 @@ int
mtrr_del(int reg, unsigned long base, unsigned long size)
{
if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1))) {
- printk("mtrr: size and base must be multiples of 4 kiB\n");
- printk("mtrr: size: 0x%lx base: 0x%lx\n", size, base);
+ printk(KERN_INFO "mtrr: size and base must be multiples of 4 kiB\n");
+ printk(KERN_DEBUG "mtrr: size: 0x%lx base: 0x%lx\n", size, base);
return -EINVAL;
}
return mtrr_del_page(reg, base >> PAGE_SHIFT, size >> PAGE_SHIFT);
@@ -677,7 +679,7 @@ static int __init mtrr_init(void)
break;
}
}
- printk("mtrr: v%s\n",MTRR_VERSION);
+ printk(KERN_INFO "mtrr: v%s\n",MTRR_VERSION);
if (mtrr_if) {
set_num_var_ranges();
diff --git a/arch/i386/pci/visws.c b/arch/i386/pci/visws.c
index c6b4c17f10fa..3a359a7c45f1 100644
--- a/arch/i386/pci/visws.c
+++ b/arch/i386/pci/visws.c
@@ -17,7 +17,7 @@
int broken_hp_bios_irq9;
-extern struct pci_ops pci_direct_conf1;
+extern struct pci_raw_ops pci_direct_conf1;
static int pci_visws_enable_irq(struct pci_dev *dev) { return 0; }
@@ -101,8 +101,9 @@ static int __init pcibios_init(void)
printk(KERN_INFO "PCI: Lithium bridge A bus: %u, "
"bridge B (PIIX4) bus: %u\n", pci_bus1, pci_bus0);
- pci_scan_bus(pci_bus0, &pci_direct_conf1, NULL);
- pci_scan_bus(pci_bus1, &pci_direct_conf1, NULL);
+ raw_pci_ops = &pci_direct_conf1;
+ pci_scan_bus(pci_bus0, &pci_root_ops, NULL);
+ pci_scan_bus(pci_bus1, &pci_root_ops, NULL);
pci_fixup_irqs(visws_swizzle, visws_map_irq);
pcibios_resource_survey();
return 0;
diff --git a/arch/ia64/kernel/module.c b/arch/ia64/kernel/module.c
index 48fee66990f9..0a7ad2a30565 100644
--- a/arch/ia64/kernel/module.c
+++ b/arch/ia64/kernel/module.c
@@ -164,7 +164,7 @@ static int
apply_imm64 (struct module *mod, struct insn *insn, uint64_t val)
{
if (slot(insn) != 2) {
- printk(KERN_ERR "%s: illegal slot number %d for IMM64\n",
+ printk(KERN_ERR "%s: invalid slot number %d for IMM64\n",
mod->name, slot(insn));
return 0;
}
@@ -176,7 +176,7 @@ static int
apply_imm60 (struct module *mod, struct insn *insn, uint64_t val)
{
if (slot(insn) != 2) {
- printk(KERN_ERR "%s: illegal slot number %d for IMM60\n",
+ printk(KERN_ERR "%s: invalid slot number %d for IMM60\n",
mod->name, slot(insn));
return 0;
}
diff --git a/arch/m68k/apollo/dn_ints.c b/arch/m68k/apollo/dn_ints.c
index 4445b8f35cf9..71fd3ae35477 100644
--- a/arch/m68k/apollo/dn_ints.c
+++ b/arch/m68k/apollo/dn_ints.c
@@ -46,7 +46,7 @@ void dn_init_IRQ(void) {
int dn_request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *devname, void *dev_id) {
if((irq<0) || (irq>15)) {
- printk("Trying to request illegal IRQ\n");
+ printk("Trying to request invalid IRQ\n");
return -ENXIO;
}
@@ -72,7 +72,7 @@ int dn_request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct
void dn_free_irq(unsigned int irq, void *dev_id) {
if((irq<0) || (irq>15)) {
- printk("Trying to free illegal IRQ\n");
+ printk("Trying to free invalid IRQ\n");
return ;
}
diff --git a/arch/m68k/q40/q40ints.c b/arch/m68k/q40/q40ints.c
index 7c42debda5b5..464847ef0070 100644
--- a/arch/m68k/q40/q40ints.c
+++ b/arch/m68k/q40/q40ints.c
@@ -171,7 +171,7 @@ void q40_free_irq(unsigned int irq, void *dev_id)
{
case 1: case 2: case 8: case 9:
case 12: case 13:
- printk("%s: ISA IRQ %d from %x illegal\n", __FUNCTION__, irq, (unsigned)dev_id);
+ printk("%s: ISA IRQ %d from %x invalid\n", __FUNCTION__, irq, (unsigned)dev_id);
return;
case 11: irq=10;
default:
diff --git a/arch/mips/mm/fault.c b/arch/mips/mm/fault.c
index 38e2647248f3..b55f06087a37 100644
--- a/arch/mips/mm/fault.c
+++ b/arch/mips/mm/fault.c
@@ -162,7 +162,7 @@ bad_area:
tsk->thread.cp0_badvaddr = address;
tsk->thread.error_code = write;
#if 0
- printk("do_page_fault() #2: sending SIGSEGV to %s for illegal %s\n"
+ printk("do_page_fault() #2: sending SIGSEGV to %s for invalid %s\n"
"%08lx (epc == %08lx, ra == %08lx)\n",
tsk->comm,
write ? "write access to" : "read access from",
diff --git a/arch/mips/ramdisk/Makefile b/arch/mips/ramdisk/Makefile
index f5040bfb8eb3..aa7f0b14aaf3 100644
--- a/arch/mips/ramdisk/Makefile
+++ b/arch/mips/ramdisk/Makefile
@@ -2,7 +2,7 @@
# Makefile for a ramdisk image
#
-O_FORMAT = $(shell $(OBJDUMP) -i | head -2 | grep elf32)
+O_FORMAT = $(shell $(OBJDUMP) -i | head -n 2 | grep elf32)
img = $(CONFIG_EMBEDDED_RAMDISK_IMAGE)
ramdisk.o: $(subst ",,$(img)) ld.script
echo "O_FORMAT: " $(O_FORMAT)
diff --git a/arch/ppc64/boot/Makefile b/arch/ppc64/boot/Makefile
index 4bdb0d02b141..80192d5aefb2 100644
--- a/arch/ppc64/boot/Makefile
+++ b/arch/ppc64/boot/Makefile
@@ -118,7 +118,7 @@ $(obj)/imagesize.c: vmlinux
ls -l vmlinux | \
awk '{printf "/* generated -- do not edit! */\n" \
"unsigned long vmlinux_filesize = %d;\n", $$5}' > $(obj)/imagesize.c
- $(CROSS_COMPILE)nm -n vmlinux | tail -1 | \
+ $(CROSS_COMPILE)nm -n vmlinux | tail -n 1 | \
awk '{printf "unsigned long vmlinux_memsize = 0x%s;\n", substr($$1,8)}' \
>> $(obj)/imagesize.c
diff --git a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c
index f3fe5f6cad3b..d42c4a9ecb28 100644
--- a/arch/sparc/kernel/process.c
+++ b/arch/sparc/kernel/process.c
@@ -590,16 +590,20 @@ int dump_fpu (struct pt_regs * regs, elf_fpregset_t * fpregs)
put_psr(get_psr() | PSR_EF);
fpsave(&current->thread.float_regs[0], &current->thread.fsr,
&current->thread.fpqueue[0], &current->thread.fpqdepth);
- regs->psr &= ~(PSR_EF);
- current->flags &= ~(PF_USEDFPU);
+ if (regs != NULL) {
+ regs->psr &= ~(PSR_EF);
+ current->flags &= ~(PF_USEDFPU);
+ }
}
#else
if (current == last_task_used_math) {
put_psr(get_psr() | PSR_EF);
fpsave(&current->thread.float_regs[0], &current->thread.fsr,
&current->thread.fpqueue[0], &current->thread.fpqdepth);
- last_task_used_math = 0;
- regs->psr &= ~(PSR_EF);
+ if (regs != NULL) {
+ regs->psr &= ~(PSR_EF);
+ last_task_used_math = 0;
+ }
}
#endif
memcpy(&fpregs->pr_fr.pr_regs[0],
diff --git a/arch/v850/Kconfig b/arch/v850/Kconfig
index 2621213eaa85..011552ac0d2f 100644
--- a/arch/v850/Kconfig
+++ b/arch/v850/Kconfig
@@ -48,20 +48,24 @@ menu "Processor type and features"
choice
prompt "Platform"
default GDB
+ config V850E_SIM
+ bool "GDB"
config RTE_CB_MA1
bool "RTE-V850E/MA1-CB"
config RTE_CB_NB85E
bool "RTE-V850E/NB85E-CB"
- config V850E_SIM
- bool "GDB"
+ config RTE_CB_ME2
+ bool "RTE-V850E/ME2-CB"
+ config V850E_AS85EP1
+ bool "AS85EP1"
config V850E2_SIM85E2C
bool "sim85e2c"
+ config V850E2_SIM85E2S
+ bool "sim85e2s"
config V850E2_FPGA85E2C
bool "NA85E2C-FPGA"
config V850E2_ANNA
bool "Anna"
- config V850E_AS85EP1
- bool "AS85EP1"
endchoice
@@ -78,41 +82,32 @@ menu "Processor type and features"
bool
depends RTE_CB_MA1
default y
- # Similarly for the RTE-V850E/MA1-CB - V850E/TEG
+ # Similarly for the RTE-V850E/NB85E-CB - V850E/TEG
config V850E_TEG
bool
depends RTE_CB_NB85E
default y
-
- # NB85E processor core
- config V850E_NB85E
+ # ... and the RTE-V850E/ME2-CB - V850E/ME2
+ config V850E_ME2
bool
- depends V850E_MA1 || V850E_TEG
+ depends RTE_CB_ME2
default y
- config V850E_MA1_HIGHRES_TIMER
- bool "High resolution timer support"
- depends V850E_MA1
-
- #### V850E2 processor-specific config
+ #### sim85e2-specific config
- # V850E2 processors
- config V850E2
+ config V850E2_SIM85E2
bool
- depends V850E2_SIM85E2C || V850E2_FPGA85E2C || V850E2_ANNA
+ depends V850E2_SIM85E2C || V850E2_SIM85E2S
default y
- # Processors based on the NA85E2A core
- config V850E2_NA85E2A
- bool
- depends V850E2_ANNA
- default y
- # Processors based on the NA85E2C core
- config V850E2_NA85E2C
+ #### V850E2 processor-specific config
+
+ # V850E2 processors
+ config V850E2
bool
- depends V850E2_SIM85E2C || V850E2_FPGA85E2C
+ depends V850E2_SIM85E2 || V850E2_FPGA85E2C || V850E2_ANNA
default y
@@ -121,7 +116,7 @@ menu "Processor type and features"
# Boards in the RTE-x-CB series
config RTE_CB
bool
- depends RTE_CB_MA1 || RTE_CB_NB85E
+ depends RTE_CB_MA1 || RTE_CB_NB85E || RTE_CB_ME2
default y
config RTE_CB_MULTI
@@ -129,7 +124,7 @@ menu "Processor type and features"
# RTE_CB_NB85E can either have multi ROM support or not, but
# other platforms (currently only RTE_CB_MA1) require it.
prompt "Multi monitor ROM support" if RTE_CB_NB85E
- depends RTE_CB
+ depends RTE_CB_MA1 || RTE_CB_NB85E
default y
config RTE_CB_MULTI_DBTRAP
@@ -156,14 +151,42 @@ menu "Processor type and features"
# The only PCI bus we support is on the RTE-MOTHER-A board
config PCI
bool
- default y if RTE_MB_A_PCI
+ default RTE_MB_A_PCI
+
+
+ #### Some feature-specific configs
+
+ # Everything except for the GDB simulator uses the same interrupt controller
+ config V850E_INTC
+ bool
+ default !V850E_SIM
+
+ # Everything except for the various simulators uses the "Timer D" unit
+ config V850E_TIMER_D
+ bool
+ default !V850E_SIM && !V850E2_SIM85E2
+
+ # Cache control used on some v850e1 processors
+ config V850E_CACHE
+ bool
+ default V850E_TEG || V850E_ME2
+
+ # Cache control used on v850e2 processors; I think this should
+ # actually apply to more, but currently only the SIM85E2S uses it
+ config V850E2_CACHE
+ bool
+ default V850E2_SIM85E2S
+
+ config NO_CACHE
+ bool
+ default !V850E_CACHE && !V850E2_CACHE
#### Misc config
config ROM_KERNEL
bool "Kernel in ROM"
- depends V850E2_ANNA || (RTE_CB && !RTE_CB_MULTI)
+ depends V850E2_ANNA || V850E_AS85EP1 || RTE_CB_ME2
# Some platforms pre-zero memory, in which case the kernel doesn't need to
config ZERO_BSS
@@ -177,9 +200,12 @@ menu "Processor type and features"
int
default 8 if V850E2_SIM85E2C || V850E2_FPGA85E2C
+ config V850E_HIGHRES_TIMER
+ bool "High resolution timer support"
+ depends V850E_TIMER_D
config TIME_BOOTUP
bool "Time bootup"
- depends V850E_MA1_HIGHRES_TIMER
+ depends V850E_HIGHRES_TIMER
config RESET_GUARD
bool "Reset Guard"
@@ -241,6 +267,7 @@ config KCORE_AOUT
default y
config KCORE_ELF
+ bool
default y
source "fs/Kconfig.binfmt"
diff --git a/arch/v850/kernel/Makefile b/arch/v850/kernel/Makefile
index 073feff6afb9..b6c63352925d 100644
--- a/arch/v850/kernel/Makefile
+++ b/arch/v850/kernel/Makefile
@@ -15,24 +15,26 @@ obj-y += intv.o entry.o process.o syscalls.o time.o semaphore.o setup.o \
signal.o irq.o mach.o ptrace.o bug.o
obj-$(CONFIG_MODULES) += module.o v850_ksyms.o
# chip-specific code
-obj-$(CONFIG_V850E_NB85E) += nb85e_intc.o
-obj-$(CONFIG_V850E_MA1) += ma.o nb85e_utils.o nb85e_timer_d.o
-obj-$(CONFIG_V850E_TEG) += teg.o nb85e_utils.o nb85e_cache.o \
- nb85e_timer_d.o
-obj-$(CONFIG_V850E2_ANNA) += anna.o nb85e_intc.o nb85e_utils.o \
- nb85e_timer_d.o
-obj-$(CONFIG_V850E_AS85EP1) += as85ep1.o nb85e_intc.o nb85e_utils.o \
- nb85e_timer_d.o
+obj-$(CONFIG_V850E_MA1) += ma.o
+obj-$(CONFIG_V850E_ME2) += me2.o
+obj-$(CONFIG_V850E_TEG) += teg.o
+obj-$(CONFIG_V850E_AS85EP1) += as85ep1.o
+obj-$(CONFIG_V850E2_ANNA) += anna.o
# platform-specific code
obj-$(CONFIG_V850E_SIM) += sim.o simcons.o
-obj-$(CONFIG_V850E2_SIM85E2C) += sim85e2c.o nb85e_intc.o memcons.o
-obj-$(CONFIG_V850E2_FPGA85E2C) += fpga85e2c.o nb85e_intc.o memcons.o
+obj-$(CONFIG_V850E2_SIM85E2) += sim85e2.o memcons.o
+obj-$(CONFIG_V850E2_FPGA85E2C) += fpga85e2c.o memcons.o
obj-$(CONFIG_RTE_CB) += rte_cb.o rte_cb_leds.o
obj-$(CONFIG_RTE_CB_MA1) += rte_ma1_cb.o
+obj-$(CONFIG_RTE_CB_ME2) += rte_me2_cb.o
obj-$(CONFIG_RTE_CB_NB85E) += rte_nb85e_cb.o
obj-$(CONFIG_RTE_CB_MULTI) += rte_cb_multi.o
obj-$(CONFIG_RTE_MB_A_PCI) += rte_mb_a_pci.o
obj-$(CONFIG_RTE_GBUS_INT) += gbus_int.o
# feature-specific code
-obj-$(CONFIG_V850E_MA1_HIGHRES_TIMER) += highres_timer.o
+obj-$(CONFIG_V850E_INTC) += v850e_intc.o
+obj-$(CONFIG_V850E_TIMER_D) += v850e_timer_d.o v850e_utils.o
+obj-$(CONFIG_V850E_CACHE) += v850e_cache.o
+obj-$(CONFIG_V850E2_CACHE) += v850e2_cache.o
+obj-$(CONFIG_V850E_HIGHRES_TIMER) += highres_timer.o
obj-$(CONFIG_PROC_FS) += procfs.o
diff --git a/arch/v850/kernel/anna.c b/arch/v850/kernel/anna.c
index d364e775f5f2..6c542d0a0f9a 100644
--- a/arch/v850/kernel/anna.c
+++ b/arch/v850/kernel/anna.c
@@ -1,8 +1,8 @@
/*
* arch/v850/kernel/anna.c -- Anna V850E2 evaluation chip/board
*
- * Copyright (C) 2002 NEC Corporation
- * Copyright (C) 2002 Miles Bader <miles@gnu.org>
+ * Copyright (C) 2002,03 NEC Electronics Corporation
+ * Copyright (C) 2002,03 Miles Bader <miles@gnu.org>
*
* This file is subject to the terms and conditions of the GNU General
* Public License. See the file COPYING in the main directory of this
@@ -21,8 +21,8 @@
#include <asm/machdep.h>
#include <asm/atomic.h>
#include <asm/page.h>
-#include <asm/nb85e_timer_d.h>
-#include <asm/nb85e_uart.h>
+#include <asm/v850e_timer_d.h>
+#include <asm/v850e_uart.h>
#include "mach.h"
@@ -41,32 +41,34 @@ static void anna_led_tick (void);
void __init mach_early_init (void)
{
- ANNA_ILBEN = 0;
- ANNA_CSC(0) = 0x402F;
- ANNA_CSC(1) = 0x4000;
- ANNA_BPC = 0;
- ANNA_BSC = 0xAAAA;
- ANNA_BEC = 0;
- ANNA_BHC = 0xFFFF; /* icache all memory, dcache all */
- ANNA_BCT(0) = 0xB088;
- ANNA_BCT(1) = 0x0008;
- ANNA_DWC(0) = 0x0027;
- ANNA_DWC(1) = 0;
- ANNA_BCC = 0x0006;
- ANNA_ASC = 0;
- ANNA_LBS = 0x0089;
- ANNA_SCR3 = 0x21A9;
- ANNA_RFS3 = 0x8121;
-
- nb85e_intc_disable_irqs ();
+ ANNA_ILBEN = 0;
+
+ V850E2_CSC(0) = 0x402F;
+ V850E2_CSC(1) = 0x4000;
+ V850E2_BPC = 0;
+ V850E2_BSC = 0xAAAA;
+ V850E2_BEC = 0;
+
+#if 0
+ V850E2_BHC = 0xFFFF; /* icache all memory, dcache all */
+#else
+ V850E2_BHC = 0; /* cache no memory */
+#endif
+ V850E2_BCT(0) = 0xB088;
+ V850E2_BCT(1) = 0x0008;
+ V850E2_DWC(0) = 0x0027;
+ V850E2_DWC(1) = 0;
+ V850E2_BCC = 0x0006;
+ V850E2_ASC = 0;
+ V850E2_LBS = 0x0089;
+ V850E2_SCR(3) = 0x21A9;
+ V850E2_RFS(3) = 0x8121;
+
+ v850e_intc_disable_irqs ();
}
void __init mach_setup (char **cmdline)
{
-#ifdef CONFIG_V850E_NB85E_UART_CONSOLE
- nb85e_uart_cons_init (1);
-#endif
-
ANNA_PORT_PM (LEDS_PORT) = 0; /* Make all LED pins output pins. */
mach_tick = anna_led_tick;
}
@@ -95,12 +97,12 @@ void mach_gettimeofday (struct timespec *tv)
void __init mach_sched_init (struct irqaction *timer_action)
{
/* Start hardware timer. */
- nb85e_timer_d_configure (0, HZ);
+ v850e_timer_d_configure (0, HZ);
/* Install timer interrupt handler. */
setup_irq (IRQ_INTCMD(0), timer_action);
}
-static struct nb85e_intc_irq_init irq_inits[] = {
+static struct v850e_intc_irq_init irq_inits[] = {
{ "IRQ", 0, NUM_MACH_IRQS, 1, 7 },
{ "PIN", IRQ_INTP(0), IRQ_INTP_NUM, 1, 4 },
{ "CCC", IRQ_INTCCC(0), IRQ_INTCCC_NUM, 1, 5 },
@@ -118,7 +120,7 @@ static struct hw_interrupt_type hw_itypes[NUM_IRQ_INITS];
void __init mach_init_irqs (void)
{
- nb85e_intc_init_irq_types (irq_inits, hw_itypes);
+ v850e_intc_init_irq_types (irq_inits, hw_itypes);
}
void machine_restart (char *__unused)
diff --git a/arch/v850/kernel/as85ep1.c b/arch/v850/kernel/as85ep1.c
index d6dfac9d52d0..6529be52037a 100644
--- a/arch/v850/kernel/as85ep1.c
+++ b/arch/v850/kernel/as85ep1.c
@@ -1,8 +1,8 @@
/*
* arch/v850/kernel/as85ep1.c -- AS85EP1 V850E evaluation chip/board
*
- * Copyright (C) 2002 NEC Corporation
- * Copyright (C) 2002 Miles Bader <miles@gnu.org>
+ * Copyright (C) 2002,03 NEC Electronics Corporation
+ * Copyright (C) 2002,03 Miles Bader <miles@gnu.org>
*
* This file is subject to the terms and conditions of the GNU General
* Public License. See the file COPYING in the main directory of this
@@ -21,8 +21,8 @@
#include <asm/machdep.h>
#include <asm/atomic.h>
#include <asm/page.h>
-#include <asm/nb85e_timer_d.h>
-#include <asm/nb85e_uart.h>
+#include <asm/v850e_timer_d.h>
+#include <asm/v850e_uart.h>
#include "mach.h"
@@ -90,20 +90,14 @@ void __init mach_early_init (void)
AS85EP1_IRAMM = 0x0; /* $BFbB"L?Na(BRAM$B$O!V(Bread-mode$B!W$K$J$j$^$9(B */
#endif /* !CONFIG_ROM_KERNEL */
- nb85e_intc_disable_irqs ();
+ v850e_intc_disable_irqs ();
}
void __init mach_setup (char **cmdline)
{
-#ifdef CONFIG_V850E_NB85E_UART_CONSOLE
- nb85e_uart_cons_init (1);
-#endif
-
AS85EP1_PORT_PMC (LEDS_PORT) = 0; /* Make the LEDs port an I/O port. */
AS85EP1_PORT_PM (LEDS_PORT) = 0; /* Make all the bits output pins. */
mach_tick = as85ep1_led_tick;
-
- ROOT_DEV = MKDEV (BLKMEM_MAJOR, 0);
}
void __init mach_get_physical_ram (unsigned long *ram_start,
@@ -137,21 +131,21 @@ void __init mach_reserve_bootmem ()
root_fs_image_end - root_fs_image_start);
}
-void mach_gettimeofday (struct timeval *tv)
+void mach_gettimeofday (struct timespec *tv)
{
tv->tv_sec = 0;
- tv->tv_usec = 0;
+ tv->tv_nsec = 0;
}
void __init mach_sched_init (struct irqaction *timer_action)
{
/* Start hardware timer. */
- nb85e_timer_d_configure (0, HZ);
+ v850e_timer_d_configure (0, HZ);
/* Install timer interrupt handler. */
setup_irq (IRQ_INTCMD(0), timer_action);
}
-static struct nb85e_intc_irq_init irq_inits[] = {
+static struct v850e_intc_irq_init irq_inits[] = {
{ "IRQ", 0, NUM_MACH_IRQS, 1, 7 },
{ "CCC", IRQ_INTCCC(0), IRQ_INTCCC_NUM, 1, 5 },
{ "CMD", IRQ_INTCMD(0), IRQ_INTCMD_NUM, 1, 5 },
@@ -166,7 +160,7 @@ static struct hw_interrupt_type hw_itypes[NUM_IRQ_INITS];
void __init mach_init_irqs (void)
{
- nb85e_intc_init_irq_types (irq_inits, hw_itypes);
+ v850e_intc_init_irq_types (irq_inits, hw_itypes);
}
void machine_restart (char *__unused)
diff --git a/arch/v850/kernel/fpga85e2c.c b/arch/v850/kernel/fpga85e2c.c
index 6c65321bbff6..290d564855ca 100644
--- a/arch/v850/kernel/fpga85e2c.c
+++ b/arch/v850/kernel/fpga85e2c.c
@@ -2,8 +2,8 @@
* arch/v850/kernel/fpga85e2c.h -- Machine-dependent defs for
* FPGA implementation of V850E2/NA85E2C
*
- * Copyright (C) 2002 NEC Corporation
- * Copyright (C) 2002 Miles Bader <miles@gnu.org>
+ * Copyright (C) 2002,03 NEC Electronics Corporation
+ * Copyright (C) 2002,03 Miles Bader <miles@gnu.org>
*
* This file is subject to the terms and conditions of the GNU General
* Public License. See the file COPYING in the main directory of this
@@ -46,7 +46,7 @@ void __init mach_early_init (void)
/* Set bus sizes: CS0 32-bit, CS1 16-bit, CS7 8-bit,
everything else 32-bit. */
- BSC = 0x2AA6;
+ V850E2_BSC = 0x2AA6;
for (i = 2; i <= 6; i++)
CSDEV(i) = 0; /* 32 bit */
@@ -134,7 +134,7 @@ void machine_power_off (void)
/* Interrupts */
-struct nb85e_intc_irq_init irq_inits[] = {
+struct v850e_intc_irq_init irq_inits[] = {
{ "IRQ", 0, NUM_MACH_IRQS, 1, 7 },
{ "RPU", IRQ_RPU(0), IRQ_RPU_NUM, 1, 6 },
{ 0 }
@@ -146,7 +146,7 @@ struct hw_interrupt_type hw_itypes[NUM_IRQ_INITS];
/* Initialize interrupts. */
void __init mach_init_irqs (void)
{
- nb85e_intc_init_irq_types (irq_inits, hw_itypes);
+ v850e_intc_init_irq_types (irq_inits, hw_itypes);
}
diff --git a/arch/v850/kernel/gbus_int.c b/arch/v850/kernel/gbus_int.c
index cf96abc13889..92918b8d89ef 100644
--- a/arch/v850/kernel/gbus_int.c
+++ b/arch/v850/kernel/gbus_int.c
@@ -113,9 +113,7 @@ static irqreturn_t gbus_int_handle_irq (int irq, void *dev_id,
/* Only pay attention to enabled interrupts. */
status &= enable;
if (status) {
- unsigned base_irq
- = IRQ_GBUS_INT (w * GBUS_INT_BITS_PER_WORD);
- irq = base_irq;
+ irq = IRQ_GBUS_INT (w * GBUS_INT_BITS_PER_WORD);
do {
/* There's an active interrupt in word
W, find out which one, and call its
@@ -247,7 +245,7 @@ void __init gbus_int_init_irqs (void)
/* First initialize the shared gint interrupts. */
for (i = 0; i < NUM_USED_GINTS; i++) {
unsigned gint = used_gint[i].gint;
- struct nb85e_intc_irq_init gint_irq_init[2];
+ struct v850e_intc_irq_init gint_irq_init[2];
/* We initialize one GINT interrupt at a time. */
gint_irq_init[0].name = "GINT";
@@ -258,7 +256,7 @@ void __init gbus_int_init_irqs (void)
gint_irq_init[1].name = 0; /* Terminate the vector. */
- nb85e_intc_init_irq_types (gint_irq_init, gint_hw_itypes);
+ v850e_intc_init_irq_types (gint_irq_init, gint_hw_itypes);
}
/* Then the GBUS interrupts. */
diff --git a/arch/v850/kernel/head.S b/arch/v850/kernel/head.S
index 6fad68e5196d..c490b937ef14 100644
--- a/arch/v850/kernel/head.S
+++ b/arch/v850/kernel/head.S
@@ -1,8 +1,8 @@
/*
* arch/v850/kernel/head.S -- Lowest-level startup code
*
- * Copyright (C) 2001,02 NEC Corporation
- * Copyright (C) 2001,02 Miles Bader <miles@gnu.org>
+ * Copyright (C) 2001,02,03 NEC Electronics Corporation
+ * Copyright (C) 2001,02,03 Miles Bader <miles@gnu.org>
*
* This file is subject to the terms and conditions of the GNU General
* Public License. See the file COPYING in the main directory of this
@@ -115,7 +115,14 @@ C_ENTRY(start):
jarl CSYM(memset), lp
#endif
- // Start Linux kernel.
+ // What happens if the main kernel function returns (it shouldn't)
mov hilo(CSYM(machine_halt)), lp
- jr CSYM(start_kernel)
+
+ // Start the linux kernel. We use an indirect jump to get extra
+ // range, because on some platforms this initial startup code
+ // (and the associated platform-specific code in mach_early_init)
+ // are located far away from the main kernel, e.g. so that they
+ // can initialize RAM first and copy the kernel or something.
+ mov hilo(CSYM(start_kernel)), r12
+ jmp [r12]
C_END(start)
diff --git a/arch/v850/kernel/highres_timer.c b/arch/v850/kernel/highres_timer.c
index 2bf0d2d943ef..b16ad1eaf966 100644
--- a/arch/v850/kernel/highres_timer.c
+++ b/arch/v850/kernel/highres_timer.c
@@ -1,8 +1,8 @@
/*
* arch/v850/kernel/highres_timer.c -- High resolution timing routines
*
- * Copyright (C) 2001,02 NEC Corporation
- * Copyright (C) 2001,02 Miles Bader <miles@gnu.org>
+ * Copyright (C) 2001,02,03 NEC Electronics Corporation
+ * Copyright (C) 2001,02,03 Miles Bader <miles@gnu.org>
*
* This file is subject to the terms and conditions of the GNU General
* Public License. See the file COPYING in the main directory of this
@@ -12,7 +12,7 @@
*/
#include <asm/system.h>
-#include <asm/nb85e_timer_d.h>
+#include <asm/v850e_timer_d.h>
#include <asm/highres_timer.h>
#define HIGHRES_TIMER_USEC_SHIFT 12
@@ -42,7 +42,7 @@ void highres_timer_slow_tick_irq (void)
void highres_timer_reset (void)
{
- NB85E_TIMER_D_TMD (HIGHRES_TIMER_TIMER_D_UNIT) = 0;
+ V850E_TIMER_D_TMD (HIGHRES_TIMER_TIMER_D_UNIT) = 0;
HIGHRES_TIMER_SLOW_TICKS = 0;
}
@@ -51,12 +51,12 @@ void highres_timer_start (void)
u32 fast_tick_rate;
/* Start hardware timer. */
- nb85e_timer_d_configure (HIGHRES_TIMER_TIMER_D_UNIT,
+ v850e_timer_d_configure (HIGHRES_TIMER_TIMER_D_UNIT,
HIGHRES_TIMER_SLOW_TICK_RATE);
fast_tick_rate =
- (NB85E_TIMER_D_BASE_FREQ
- >> NB85E_TIMER_D_DIVLOG2 (HIGHRES_TIMER_TIMER_D_UNIT));
+ (V850E_TIMER_D_BASE_FREQ
+ >> V850E_TIMER_D_DIVLOG2 (HIGHRES_TIMER_TIMER_D_UNIT));
/* The obvious way of calculating microseconds from fast ticks
is to do:
@@ -77,16 +77,16 @@ void highres_timer_start (void)
/* Enable the interrupt (which is hardwired to this use), and
give it the highest priority. */
- NB85E_INTC_IC (IRQ_INTCMD (HIGHRES_TIMER_TIMER_D_UNIT)) = 0;
+ V850E_INTC_IC (IRQ_INTCMD (HIGHRES_TIMER_TIMER_D_UNIT)) = 0;
}
void highres_timer_stop (void)
{
/* Stop the timer. */
- NB85E_TIMER_D_TMCD (HIGHRES_TIMER_TIMER_D_UNIT) =
- NB85E_TIMER_D_TMCD_CAE;
+ V850E_TIMER_D_TMCD (HIGHRES_TIMER_TIMER_D_UNIT) =
+ V850E_TIMER_D_TMCD_CAE;
/* Disable its interrupt, just in case. */
- nb85e_intc_disable_irq (IRQ_INTCMD (HIGHRES_TIMER_TIMER_D_UNIT));
+ v850e_intc_disable_irq (IRQ_INTCMD (HIGHRES_TIMER_TIMER_D_UNIT));
}
inline void highres_timer_read_ticks (u32 *slow_ticks, u32 *fast_ticks)
@@ -95,9 +95,9 @@ inline void highres_timer_read_ticks (u32 *slow_ticks, u32 *fast_ticks)
u32 fast_ticks_1, fast_ticks_2, _slow_ticks;
local_irq_save (flags);
- fast_ticks_1 = NB85E_TIMER_D_TMD (HIGHRES_TIMER_TIMER_D_UNIT);
+ fast_ticks_1 = V850E_TIMER_D_TMD (HIGHRES_TIMER_TIMER_D_UNIT);
_slow_ticks = HIGHRES_TIMER_SLOW_TICKS;
- fast_ticks_2 = NB85E_TIMER_D_TMD (HIGHRES_TIMER_TIMER_D_UNIT);
+ fast_ticks_2 = V850E_TIMER_D_TMD (HIGHRES_TIMER_TIMER_D_UNIT);
local_irq_restore (flags);
if (fast_ticks_2 < fast_ticks_1)
diff --git a/arch/v850/kernel/intv.S b/arch/v850/kernel/intv.S
index 3ccdd2beed8b..671e4c6150dd 100644
--- a/arch/v850/kernel/intv.S
+++ b/arch/v850/kernel/intv.S
@@ -16,7 +16,7 @@
#include <asm/machdep.h>
#include <asm/entry.h>
-#ifdef CONFIG_V850E_MA1_HIGHRES_TIMER
+#ifdef CONFIG_V850E_HIGHRES_TIMER
#include <asm/highres_timer.h>
#endif
@@ -59,7 +59,7 @@
.section .intv.mach, "ax"
.org 0x0
-#if defined (CONFIG_V850E_MA1_HIGHRES_TIMER) && defined (IRQ_INTCMD)
+#if defined (CONFIG_V850E_HIGHRES_TIMER) && defined (IRQ_INTCMD)
/* Interrupts before the highres timer interrupt. */
.rept IRQ_INTCMD (HIGHRES_TIMER_TIMER_D_UNIT)
diff --git a/arch/v850/kernel/ma.c b/arch/v850/kernel/ma.c
index 05b82f61c04d..b3dfbc5d2f40 100644
--- a/arch/v850/kernel/ma.c
+++ b/arch/v850/kernel/ma.c
@@ -22,19 +22,19 @@
#include <asm/atomic.h>
#include <asm/page.h>
#include <asm/machdep.h>
-#include <asm/nb85e_timer_d.h>
+#include <asm/v850e_timer_d.h>
#include "mach.h"
void __init mach_sched_init (struct irqaction *timer_action)
{
/* Start hardware timer. */
- nb85e_timer_d_configure (0, HZ);
+ v850e_timer_d_configure (0, HZ);
/* Install timer interrupt handler. */
setup_irq (IRQ_INTCMD(0), timer_action);
}
-static struct nb85e_intc_irq_init irq_inits[] = {
+static struct v850e_intc_irq_init irq_inits[] = {
{ "IRQ", 0, NUM_MACH_IRQS, 1, 7 },
{ "CMD", IRQ_INTCMD(0), IRQ_INTCMD_NUM, 1, 5 },
{ "DMA", IRQ_INTDMA(0), IRQ_INTDMA_NUM, 1, 2 },
@@ -51,7 +51,7 @@ static struct hw_interrupt_type hw_itypes[NUM_IRQ_INITS];
/* Initialize MA chip interrupts. */
void __init ma_init_irqs (void)
{
- nb85e_intc_init_irq_types (irq_inits, hw_itypes);
+ v850e_intc_init_irq_types (irq_inits, hw_itypes);
}
/* Called before configuring an on-chip UART. */
diff --git a/arch/v850/kernel/me2.c b/arch/v850/kernel/me2.c
new file mode 100644
index 000000000000..6527c218f91d
--- /dev/null
+++ b/arch/v850/kernel/me2.c
@@ -0,0 +1,74 @@
+/*
+ * arch/v850/kernel/me2.c -- V850E/ME2 chip-specific support
+ *
+ * Copyright (C) 2003 NEC Corporation
+ * Copyright (C) 2003 Miles Bader <miles@gnu.org>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file COPYING in the main directory of this
+ * archive for more details.
+ *
+ * Written by Miles Bader <miles@gnu.org>
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/swap.h>
+#include <linux/bootmem.h>
+#include <linux/irq.h>
+
+#include <asm/atomic.h>
+#include <asm/page.h>
+#include <asm/machdep.h>
+#include <asm/v850e_timer_d.h>
+
+#include "mach.h"
+
+void __init mach_sched_init (struct irqaction *timer_action)
+{
+ /* Start hardware timer. */
+ v850e_timer_d_configure (0, HZ);
+ /* Install timer interrupt handler. */
+ setup_irq (IRQ_INTCMD(0), timer_action);
+}
+
+static struct v850e_intc_irq_init irq_inits[] = {
+ { "IRQ", 0, NUM_CPU_IRQS, 1, 7 },
+ { "INTP", IRQ_INTP(0), IRQ_INTP_NUM, 1, 5 },
+ { "CMD", IRQ_INTCMD(0), IRQ_INTCMD_NUM, 1, 3 },
+ { "UBTIRE", IRQ_INTUBTIRE(0), IRQ_INTUBTIRE_NUM, 5, 4 },
+ { "UBTIR", IRQ_INTUBTIR(0), IRQ_INTUBTIR_NUM, 5, 4 },
+ { "UBTIT", IRQ_INTUBTIT(0), IRQ_INTUBTIT_NUM, 5, 4 },
+ { "UBTIF", IRQ_INTUBTIF(0), IRQ_INTUBTIF_NUM, 5, 4 },
+ { "UBTITO", IRQ_INTUBTITO(0), IRQ_INTUBTITO_NUM, 5, 4 },
+ { 0 }
+};
+#define NUM_IRQ_INITS ((sizeof irq_inits / sizeof irq_inits[0]) - 1)
+
+static struct hw_interrupt_type hw_itypes[NUM_IRQ_INITS];
+
+/* Initialize V850E/ME2 chip interrupts. */
+void __init me2_init_irqs (void)
+{
+ v850e_intc_init_irq_types (irq_inits, hw_itypes);
+}
+
+/* Called before configuring an on-chip UART. */
+void me2_uart_pre_configure (unsigned chan, unsigned cflags, unsigned baud)
+{
+ if (chan == 0) {
+ /* Specify that the relevent pins on the chip should do
+ serial I/O, not direct I/O. */
+ ME2_PORT1_PMC |= 0xC;
+ /* Specify that we're using the UART, not the CSI device. */
+ ME2_PORT1_PFC |= 0xC;
+ } else if (chan == 1) {
+ /* Specify that the relevent pins on the chip should do
+ serial I/O, not direct I/O. */
+ ME2_PORT2_PMC |= 0x6;
+ /* Specify that we're using the UART, not the CSI device. */
+ ME2_PORT2_PFC |= 0x6;
+ }
+}
diff --git a/arch/v850/kernel/rte_cb.c b/arch/v850/kernel/rte_cb.c
index 234ebeb3fd28..45c1b1197c1b 100644
--- a/arch/v850/kernel/rte_cb.c
+++ b/arch/v850/kernel/rte_cb.c
@@ -17,7 +17,7 @@
#include <linux/fs.h>
#include <asm/machdep.h>
-#include <asm/nb85e_uart.h>
+#include <asm/v850e_uart.h>
#include "mach.h"
@@ -34,7 +34,7 @@ extern void multi_init (void);
void __init rte_cb_early_init (void)
{
- nb85e_intc_disable_irqs ();
+ v850e_intc_disable_irqs ();
#ifdef CONFIG_RTE_CB_MULTI
multi_init ();
@@ -43,6 +43,7 @@ void __init rte_cb_early_init (void)
void __init mach_setup (char **cmdline)
{
+#ifdef CONFIG_RTE_MB_A_PCI
/* Probe for Mother-A, and print a message if we find it. */
*(volatile unsigned long *)MB_A_SRAM_ADDR = 0xDEADBEEF;
if (*(volatile unsigned long *)MB_A_SRAM_ADDR == 0xDEADBEEF) {
@@ -52,23 +53,11 @@ void __init mach_setup (char **cmdline)
" NEC SolutionGear/Midas lab"
" RTE-MOTHER-A motherboard\n");
}
-
-#if defined (CONFIG_V850E_NB85E_UART_CONSOLE) && !defined (CONFIG_TIME_BOOTUP)
- nb85e_uart_cons_init (0);
-#endif
+#endif /* CONFIG_RTE_MB_A_PCI */
mach_tick = led_tick;
}
-#ifdef CONFIG_TIME_BOOTUP
-void initial_boot_done (void)
-{
-#ifdef CONFIG_V850E_NB85E_UART_CONSOLE
- nb85e_uart_cons_init (0);
-#endif
-}
-#endif
-
void machine_restart (char *__unused)
{
#ifdef CONFIG_RESET_GUARD
@@ -194,6 +183,7 @@ static struct hw_interrupt_type gbus_hw_itypes[NUM_GBUS_IRQ_INITS];
#endif /* CONFIG_RTE_GBUS_INT */
+
void __init rte_cb_init_irqs (void)
{
#ifdef CONFIG_RTE_GBUS_INT
diff --git a/arch/v850/kernel/rte_ma1_cb.c b/arch/v850/kernel/rte_ma1_cb.c
index 8df4a894622b..3873e276392f 100644
--- a/arch/v850/kernel/rte_ma1_cb.c
+++ b/arch/v850/kernel/rte_ma1_cb.c
@@ -20,7 +20,7 @@
#include <asm/page.h>
#include <asm/ma1.h>
#include <asm/rte_ma1_cb.h>
-#include <asm/nb85e_timer_c.h>
+#include <asm/v850e_timer_c.h>
#include "mach.h"
@@ -89,14 +89,14 @@ void __init mach_init_irqs (void)
rte_cb_init_irqs ();
/* Use falling-edge-sensitivity for interrupts . */
- NB85E_TIMER_C_SESC (0) &= ~0xC;
- NB85E_TIMER_C_SESC (1) &= ~0xF;
+ V850E_TIMER_C_SESC (0) &= ~0xC;
+ V850E_TIMER_C_SESC (1) &= ~0xF;
/* INTP000-INTP011 are shared with `Timer C', so we have to set
up Timer C to pass them through as raw interrupts. */
for (tc = 0; tc < 2; tc++)
/* Turn on the timer. */
- NB85E_TIMER_C_TMCC0 (tc) |= NB85E_TIMER_C_TMCC0_CAE;
+ V850E_TIMER_C_TMCC0 (tc) |= V850E_TIMER_C_TMCC0_CAE;
/* Make sure the relevant port0/port1 pins are assigned
interrupt duty. We used INTP001-INTP011 (don't screw with
diff --git a/arch/v850/kernel/rte_me2_cb.c b/arch/v850/kernel/rte_me2_cb.c
new file mode 100644
index 000000000000..25ae5f6d01c3
--- /dev/null
+++ b/arch/v850/kernel/rte_me2_cb.c
@@ -0,0 +1,308 @@
+/*
+ * arch/v850/kernel/rte_me2_cb.c -- Midas labs RTE-V850E/ME2-CB board
+ *
+ * Copyright (C) 2001,02,03 NEC Electronics Corporation
+ * Copyright (C) 2001,02,03 Miles Bader <miles@gnu.org>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file COPYING in the main directory of this
+ * archive for more details.
+ *
+ * Written by Miles Bader <miles@gnu.org>
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/bootmem.h>
+#include <linux/irq.h>
+#include <linux/fs.h>
+#include <linux/major.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+
+#include <asm/atomic.h>
+#include <asm/page.h>
+#include <asm/me2.h>
+#include <asm/rte_me2_cb.h>
+#include <asm/machdep.h>
+#include <asm/v850e_intc.h>
+#include <asm/v850e_cache.h>
+#include <asm/irq.h>
+
+#include "mach.h"
+
+extern unsigned long *_intv_start;
+extern unsigned long *_intv_end;
+
+/* LED access routines. */
+extern unsigned read_leds (int pos, char *buf, int len);
+extern unsigned write_leds (int pos, const char *buf, int len);
+
+
+/* SDRAM are almost contiguous (with a small hole in between;
+ see mach_reserve_bootmem for details), so just use both as one big area. */
+#define RAM_START SDRAM_ADDR
+#define RAM_END (SDRAM_ADDR + SDRAM_SIZE)
+
+
+void __init mach_get_physical_ram (unsigned long *ram_start,
+ unsigned long *ram_len)
+{
+ *ram_start = RAM_START;
+ *ram_len = RAM_END - RAM_START;
+}
+
+void __init mach_reserve_bootmem ()
+{
+ extern char _root_fs_image_start, _root_fs_image_end;
+ u32 root_fs_image_start = (u32)&_root_fs_image_start;
+ u32 root_fs_image_end = (u32)&_root_fs_image_end;
+
+ /* Reserve the memory used by the root filesystem image if it's
+ in RAM. */
+ if (root_fs_image_start >= RAM_START && root_fs_image_start < RAM_END)
+ reserve_bootmem (root_fs_image_start,
+ root_fs_image_end - root_fs_image_start);
+}
+
+void mach_gettimeofday (struct timespec *tv)
+{
+ tv->tv_sec = 0;
+ tv->tv_nsec = 0;
+}
+
+/* Called before configuring an on-chip UART. */
+void rte_me2_cb_uart_pre_configure (unsigned chan,
+ unsigned cflags, unsigned baud)
+{
+ /* The RTE-V850E/ME2-CB connects some general-purpose I/O
+ pins on the CPU to the RTS/CTS lines of UARTB channel 0's
+ serial connection.
+ I/O pins P21 and P22 are RTS and CTS respectively. */
+ if (chan == 0) {
+ /* Put P21 & P22 in I/O port mode. */
+ ME2_PORT2_PMC &= ~0x6;
+ /* Make P21 and output, and P22 an input. */
+ ME2_PORT2_PM = (ME2_PORT2_PM & ~0xC) | 0x4;
+ }
+
+ me2_uart_pre_configure (chan, cflags, baud);
+}
+
+void __init mach_init_irqs (void)
+{
+ /* Initialize interrupts. */
+ me2_init_irqs ();
+ rte_me2_cb_init_irqs ();
+}
+
+#ifdef CONFIG_ROM_KERNEL
+/* Initialization for kernel in ROM. */
+static inline rom_kernel_init (void)
+{
+ /* If the kernel is in ROM, we have to copy any initialized data
+ from ROM into RAM. */
+ extern unsigned long _data_load_start, _sdata, _edata;
+ register unsigned long *src = &_data_load_start;
+ register unsigned long *dst = &_sdata, *end = &_edata;
+
+ while (dst != end)
+ *dst++ = *src++;
+}
+#endif /* CONFIG_ROM_KERNEL */
+
+static void install_interrupt_vectors (void)
+{
+ unsigned long *p1, *p2;
+
+ ME2_IRAMM = 0x03; /* V850E/ME2 iRAM write mode */
+
+ /* vector copy to iRAM */
+ p1 = (unsigned long *)0; /* v85x vector start */
+ p2 = (unsigned long *)&_intv_start;
+ while (p2 < (unsigned long *)&_intv_end)
+ *p1++ = *p2++;
+
+ ME2_IRAMM = 0x00; /* V850E/ME2 iRAM read mode */
+}
+
+/* CompactFlash */
+
+static void cf_power_on (void)
+{
+ /* CF card detected? */
+ if (CB_CF_STS0 & 0x0030)
+ return;
+
+ CB_CF_REG0 = 0x0002; /* reest on */
+ mdelay (10);
+ CB_CF_REG0 = 0x0003; /* power on */
+ mdelay (10);
+ CB_CF_REG0 = 0x0001; /* reset off */
+ mdelay (10);
+}
+
+static void cf_power_off (void)
+{
+ CB_CF_REG0 = 0x0003; /* power on */
+ mdelay (10);
+ CB_CF_REG0 = 0x0002; /* reest on */
+ mdelay (10);
+}
+
+void __init mach_early_init (void)
+{
+ install_interrupt_vectors ();
+
+ /* CS1 SDRAM instruction cache enable */
+ v850e_cache_enable (0x04, 0x03, 0);
+
+ rte_cb_early_init ();
+
+ /* CompactFlash power on */
+ cf_power_on ();
+
+#if defined (CONFIG_ROM_KERNEL)
+ rom_kernel_init ();
+#endif
+}
+
+
+/* RTE-V850E/ME2-CB Programmable Interrupt Controller. */
+
+static struct cb_pic_irq_init cb_pic_irq_inits[] = {
+ { "CB_EXTTM0", IRQ_CB_EXTTM0, 1, 1, 6 },
+ { "CB_EXTSIO", IRQ_CB_EXTSIO, 1, 1, 6 },
+ { "CB_TOVER", IRQ_CB_TOVER, 1, 1, 6 },
+ { "CB_GINT0", IRQ_CB_GINT0, 1, 1, 6 },
+ { "CB_USB", IRQ_CB_USB, 1, 1, 6 },
+ { "CB_LANC", IRQ_CB_LANC, 1, 1, 6 },
+ { "CB_USB_VBUS_ON", IRQ_CB_USB_VBUS_ON, 1, 1, 6 },
+ { "CB_USB_VBUS_OFF", IRQ_CB_USB_VBUS_OFF, 1, 1, 6 },
+ { "CB_EXTTM1", IRQ_CB_EXTTM1, 1, 1, 6 },
+ { "CB_EXTTM2", IRQ_CB_EXTTM2, 1, 1, 6 },
+ { 0 }
+};
+#define NUM_CB_PIC_IRQ_INITS \
+ ((sizeof cb_pic_irq_inits / sizeof cb_pic_irq_inits[0]) - 1)
+
+static struct hw_interrupt_type cb_pic_hw_itypes[NUM_CB_PIC_IRQ_INITS];
+static unsigned char cb_pic_active_irqs = 0;
+
+void __init rte_me2_cb_init_irqs (void)
+{
+ cb_pic_init_irq_types (cb_pic_irq_inits, cb_pic_hw_itypes);
+
+ /* Initalize on board PIC1 (not PIC0) enable */
+ CB_PIC_INT0M = 0x0000;
+ CB_PIC_INT1M = 0x0000;
+ CB_PIC_INTR = 0x0000;
+ CB_PIC_INTEN |= CB_PIC_INT1EN;
+
+ ME2_PORT2_PMC |= 0x08; /* INTP23/SCK1 mode */
+ ME2_PORT2_PFC &= ~0x08; /* INTP23 mode */
+ ME2_INTR(2) &= ~0x08; /* INTP23 falling-edge detect */
+ ME2_INTF(2) &= ~0x08; /* " */
+
+ rte_cb_init_irqs (); /* gbus &c */
+}
+
+
+/* Enable interrupt handling for interrupt IRQ. */
+void cb_pic_enable_irq (unsigned irq)
+{
+ CB_PIC_INT1M |= 1 << (irq - CB_PIC_BASE_IRQ);
+}
+
+void cb_pic_disable_irq (unsigned irq)
+{
+ CB_PIC_INT1M &= ~(1 << (irq - CB_PIC_BASE_IRQ));
+}
+
+void cb_pic_shutdown_irq (unsigned irq)
+{
+ cb_pic_disable_irq (irq);
+
+ if (--cb_pic_active_irqs == 0)
+ free_irq (IRQ_CB_PIC, 0);
+
+ CB_PIC_INT1M &= ~(1 << (irq - CB_PIC_BASE_IRQ));
+}
+
+static void cb_pic_handle_irq (int irq, void *dev_id, struct pt_regs *regs)
+{
+ unsigned status = CB_PIC_INTR;
+ unsigned enable = CB_PIC_INT1M;
+
+ /* Only pay attention to enabled interrupts. */
+ status &= enable;
+
+ CB_PIC_INTEN &= ~CB_PIC_INT1EN;
+
+ if (status) {
+ unsigned mask = 1;
+
+ irq = CB_PIC_BASE_IRQ;
+ do {
+ /* There's an active interrupt, find out which one,
+ and call its handler. */
+ while (! (status & mask)) {
+ irq++;
+ mask <<= 1;
+ }
+ status &= ~mask;
+
+ CB_PIC_INTR = mask;
+
+ /* Recursively call handle_irq to handle it. */
+ handle_irq (irq, regs);
+ } while (status);
+ }
+
+ CB_PIC_INTEN |= CB_PIC_INT1EN;
+}
+
+
+static void irq_nop (unsigned irq) { }
+
+static unsigned cb_pic_startup_irq (unsigned irq)
+{
+ int rval;
+
+ if (cb_pic_active_irqs == 0) {
+ rval = request_irq (IRQ_CB_PIC, cb_pic_handle_irq,
+ SA_INTERRUPT, "cb_pic_handler", 0);
+ if (rval != 0)
+ return rval;
+ }
+
+ cb_pic_active_irqs++;
+
+ cb_pic_enable_irq (irq);
+
+ return 0;
+}
+
+/* Initialize HW_IRQ_TYPES for INTC-controlled irqs described in array
+ INITS (which is terminated by an entry with the name field == 0). */
+void __init cb_pic_init_irq_types (struct cb_pic_irq_init *inits,
+ struct hw_interrupt_type *hw_irq_types)
+{
+ struct cb_pic_irq_init *init;
+ for (init = inits; init->name; init++) {
+ struct hw_interrupt_type *hwit = hw_irq_types++;
+
+ hwit->typename = init->name;
+
+ hwit->startup = cb_pic_startup_irq;
+ hwit->shutdown = cb_pic_shutdown_irq;
+ hwit->enable = cb_pic_enable_irq;
+ hwit->disable = cb_pic_disable_irq;
+ hwit->ack = irq_nop;
+ hwit->end = irq_nop;
+
+ /* Initialize kernel IRQ infrastructure for this interrupt. */
+ init_irq_handlers(init->base, init->num, init->interval, hwit);
+ }
+}
diff --git a/arch/v850/kernel/rte_nb85e_cb.c b/arch/v850/kernel/rte_nb85e_cb.c
index 0fcf233b7083..74074fb3a2f4 100644
--- a/arch/v850/kernel/rte_nb85e_cb.c
+++ b/arch/v850/kernel/rte_nb85e_cb.c
@@ -21,7 +21,7 @@
#include <asm/atomic.h>
#include <asm/page.h>
-#include <asm/nb85e.h>
+#include <asm/v850e.h>
#include <asm/rte_nb85e_cb.h>
#include "mach.h"
@@ -41,7 +41,7 @@ void __init mach_early_init (void)
Unfortunately, the dcache seems to be buggy, so we only use the
icache for now. */
- nb85e_cache_enable (0x0040 /* BHC */, 0x0000 /* DCC */);
+ v850e_cache_enable (0x0040 /*BHC*/, 0x0003 /*ICC*/, 0x0000 /*DCC*/);
rte_cb_early_init ();
}
diff --git a/arch/v850/kernel/sim85e2c.c b/arch/v850/kernel/sim85e2.c
index 3eaf4fe72ef3..9dbb35482ba5 100644
--- a/arch/v850/kernel/sim85e2c.c
+++ b/arch/v850/kernel/sim85e2.c
@@ -1,9 +1,9 @@
/*
- * arch/v850/kernel/sim85e2c.c -- Machine-specific stuff for
+ * arch/v850/kernel/sim85e2.c -- Machine-specific stuff for
* V850E2 RTL simulator
*
- * Copyright (C) 2002 NEC Corporation
- * Copyright (C) 2002 Miles Bader <miles@gnu.org>
+ * Copyright (C) 2002,03 NEC Electronics Corporation
+ * Copyright (C) 2002,03 Miles Bader <miles@gnu.org>
*
* This file is subject to the terms and conditions of the GNU General
* Public License. See the file COPYING in the main directory of this
@@ -26,17 +26,47 @@
#include "mach.h"
+
+/* There are 4 possible areas we can use:
+
+ IRAM (1MB) is fast for instruction fetches, but slow for data
+ DRAM (1020KB) is fast for data, but slow for instructions
+ ERAM is cached, so should be fast for both insns and data
+ SDRAM is external DRAM, similar to ERAM
+*/
+
+#define INIT_MEMC_FOR_SDRAM
+#define USE_SDRAM_AREA
+#define KERNEL_IN_SDRAM_AREA
+
+#define DCACHE_MODE V850E2_CACHE_BTSC_DCM_WT
+/*#define DCACHE_MODE V850E2_CACHE_BTSC_DCM_WB_ALLOC*/
+
+#ifdef USE_SDRAM_AREA
+#define RAM_START SDRAM_ADDR
+#define RAM_END (SDRAM_ADDR + SDRAM_SIZE)
+#else
+/* When we use DRAM, we need to account for the fact that the end of it is
+ used for R0_RAM. */
+#define RAM_START DRAM_ADDR
+#define RAM_END R0_RAM_ADDR
+#endif
+
+
extern void memcons_setup (void);
-void __init mach_early_init (void)
+#ifdef KERNEL_IN_SDRAM_AREA
+#define EARLY_INIT_SECTION_ATTR __attribute__ ((section (".early.text")))
+#else
+#define EARLY_INIT_SECTION_ATTR __init
+#endif
+
+void EARLY_INIT_SECTION_ATTR mach_early_init (void)
{
extern int panic_timeout;
- /* Don't stop the simulator at `halt' instructions. */
- NOTHAL = 1;
-
- /* The sim85e2c simulator tracks `undefined' values, so to make
+ /* The sim85e2 simulator tracks `undefined' values, so to make
debugging easier, we begin by zeroing out all otherwise
undefined registers. This is not strictly necessary.
@@ -67,10 +97,41 @@ void __init mach_early_init (void)
asm volatile ("ldsr r0, 16; ldsr r0, 17; ldsr r0, 18; ldsr r0, 19");
asm volatile ("ldsr r0, 20");
+
+#ifdef INIT_MEMC_FOR_SDRAM
+ /* Settings for SDRAM controller. */
+ V850E2_VSWC = 0x0042;
+ V850E2_BSC = 0x9286;
+ V850E2_BCT(0) = 0xb000; /* was: 0 */
+ V850E2_BCT(1) = 0x000b;
+ V850E2_ASC = 0;
+ V850E2_LBS = 0xa9aa; /* was: 0xaaaa */
+ V850E2_LBC(0) = 0;
+ V850E2_LBC(1) = 0; /* was: 0x3 */
+ V850E2_BCC = 0;
+ V850E2_RFS(4) = 0x800a; /* was: 0xf109 */
+ V850E2_SCR(4) = 0x2091; /* was: 0x20a1 */
+ V850E2_RFS(3) = 0x800c;
+ V850E2_SCR(3) = 0x20a1;
+ V850E2_DWC(0) = 0;
+ V850E2_DWC(1) = 0;
+#endif
+
+#if 0
+#ifdef CONFIG_V850E2_SIM85E2S
/* Turn on the caches. */
- NA85E2C_CACHE_BTSC
- |= (NA85E2C_CACHE_BTSC_ICM | NA85E2C_CACHE_BTSC_DCM0);
- NA85E2C_BUSM_BHC = 0xFFFF;
+ V850E2_CACHE_BTSC = V850E2_CACHE_BTSC_ICM | DCACHE_MODE;
+ V850E2_BHC = 0x1010;
+#elif CONFIG_V850E2_SIM85E2C
+ V850E2_CACHE_BTSC |= (V850E2_CACHE_BTSC_ICM | V850E2_CACHE_BTSC_DCM0);
+ V850E2_BUSM_BHC = 0xFFFF;
+#endif
+#else
+ V850E2_BHC = 0;
+#endif
+
+ /* Don't stop the simulator at `halt' instructions. */
+ SIM85E2_NOTHAL = 1;
/* Ensure that the simulator halts on a panic, instead of going
into an infinite loop inside the panic function. */
@@ -84,18 +145,23 @@ void __init mach_setup (char **cmdline)
void mach_get_physical_ram (unsigned long *ram_start, unsigned long *ram_len)
{
- /* There are 3 possible areas we can use:
- IRAM (1MB) is fast for instruction fetches, but slow for data
- DRAM (1020KB) is fast for data, but slow for instructions
- ERAM is cached, so should be fast for both insns and data,
- _but_ currently only supports write-through caching, so
- writes are slow.
- Since there's really no area that's good for general kernel
- use, we use DRAM -- it won't be good for user programs
- (which will be loaded into kernel allocated memory), but
- currently we're more concerned with testing the kernel. */
- *ram_start = DRAM_ADDR;
- *ram_len = R0_RAM_ADDR - DRAM_ADDR;
+ *ram_start = RAM_START;
+ *ram_len = RAM_END - RAM_START;
+}
+
+void __init mach_reserve_bootmem ()
+{
+ extern char _root_fs_image_start, _root_fs_image_end;
+ u32 root_fs_image_start = (u32)&_root_fs_image_start;
+ u32 root_fs_image_end = (u32)&_root_fs_image_end;
+
+ /* Reserve the memory used by the root filesystem image if it's
+ in RAM. */
+ if (root_fs_image_end > root_fs_image_start
+ && root_fs_image_start >= RAM_START
+ && root_fs_image_start < RAM_END)
+ reserve_bootmem (root_fs_image_start,
+ root_fs_image_end - root_fs_image_start);
}
void __init mach_sched_init (struct irqaction *timer_action)
@@ -114,7 +180,7 @@ void mach_gettimeofday (struct timespec *tv)
/* Interrupts */
-struct nb85e_intc_irq_init irq_inits[] = {
+struct v850e_intc_irq_init irq_inits[] = {
{ "IRQ", 0, NUM_MACH_IRQS, 1, 7 },
{ 0 }
};
@@ -123,14 +189,14 @@ struct hw_interrupt_type hw_itypes[1];
/* Initialize interrupts. */
void __init mach_init_irqs (void)
{
- nb85e_intc_init_irq_types (irq_inits, hw_itypes);
+ v850e_intc_init_irq_types (irq_inits, hw_itypes);
}
void machine_halt (void) __attribute__ ((noreturn));
void machine_halt (void)
{
- SIMFIN = 0; /* Halt immediately. */
+ SIM85E2_SIMFIN = 0; /* Halt immediately. */
for (;;) {}
}
diff --git a/arch/v850/kernel/teg.c b/arch/v850/kernel/teg.c
index af87b1c72ffc..495cf8f37bcb 100644
--- a/arch/v850/kernel/teg.c
+++ b/arch/v850/kernel/teg.c
@@ -22,7 +22,7 @@
#include <asm/atomic.h>
#include <asm/page.h>
#include <asm/machdep.h>
-#include <asm/nb85e_timer_d.h>
+#include <asm/v850e_timer_d.h>
#include "mach.h"
@@ -31,12 +31,12 @@ void __init mach_sched_init (struct irqaction *timer_action)
/* Select timer interrupt instead of external pin. */
TEG_ISS |= 0x1;
/* Start hardware timer. */
- nb85e_timer_d_configure (0, HZ);
+ v850e_timer_d_configure (0, HZ);
/* Install timer interrupt handler. */
setup_irq (IRQ_INTCMD(0), timer_action);
}
-static struct nb85e_intc_irq_init irq_inits[] = {
+static struct v850e_intc_irq_init irq_inits[] = {
{ "IRQ", 0, NUM_CPU_IRQS, 1, 7 },
{ "CMD", IRQ_INTCMD(0), IRQ_INTCMD_NUM, 1, 5 },
{ "SER", IRQ_INTSER(0), IRQ_INTSER_NUM, 1, 3 },
@@ -51,7 +51,7 @@ static struct hw_interrupt_type hw_itypes[NUM_IRQ_INITS];
/* Initialize MA chip interrupts. */
void __init teg_init_irqs (void)
{
- nb85e_intc_init_irq_types (irq_inits, hw_itypes);
+ v850e_intc_init_irq_types (irq_inits, hw_itypes);
}
/* Called before configuring an on-chip UART. */
diff --git a/arch/v850/kernel/v850e2_cache.c b/arch/v850/kernel/v850e2_cache.c
new file mode 100644
index 000000000000..4570312c689c
--- /dev/null
+++ b/arch/v850/kernel/v850e2_cache.c
@@ -0,0 +1,127 @@
+/*
+ * arch/v850/kernel/v850e2_cache.c -- Cache control for V850E2 cache
+ * memories
+ *
+ * Copyright (C) 2003 NEC Electronics Corporation
+ * Copyright (C) 2003 Miles Bader <miles@gnu.org>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file COPYING in the main directory of this
+ * archive for more details.
+ *
+ * Written by Miles Bader <miles@gnu.org>
+ */
+
+#include <linux/mm.h>
+
+#include <asm/v850e2_cache.h>
+
+/* Cache operations we can do. The encoding corresponds directly to the
+ value we need to write into the COPR register. */
+enum cache_op {
+ OP_SYNC_IF_DIRTY = V850E2_CACHE_COPR_CFC(0), /* 000 */
+ OP_SYNC_IF_VALID = V850E2_CACHE_COPR_CFC(1), /* 001 */
+ OP_SYNC_IF_VALID_AND_CLEAR = V850E2_CACHE_COPR_CFC(3), /* 011 */
+ OP_WAY_CLEAR = V850E2_CACHE_COPR_CFC(4), /* 100 */
+ OP_FILL = V850E2_CACHE_COPR_CFC(5), /* 101 */
+ OP_CLEAR = V850E2_CACHE_COPR_CFC(6), /* 110 */
+ OP_CREATE_DIRTY = V850E2_CACHE_COPR_CFC(7) /* 111 */
+};
+
+/* Which cache to use. This encoding also corresponds directly to the
+ value we need to write into the COPR register. */
+enum cache {
+ ICACHE = 0,
+ DCACHE = V850E2_CACHE_COPR_LBSL
+};
+
+/* Returns ADDR rounded down to the beginning of its cache-line. */
+#define CACHE_LINE_ADDR(addr) \
+ ((addr) & ~(V850E2_CACHE_LINE_SIZE - 1))
+/* Returns END_ADDR rounded up to the `limit' of its cache-line. */
+#define CACHE_LINE_END_ADDR(end_addr) \
+ CACHE_LINE_ADDR(end_addr + (V850E2_CACHE_LINE_SIZE - 1))
+
+
+/* Low-level cache ops. */
+
+/* Apply cache-op OP to all entries in CACHE. */
+static inline void cache_op_all (enum cache_op op, enum cache cache)
+{
+ int cmd = op | cache | V850E2_CACHE_COPR_WSLE | V850E2_CACHE_COPR_STRT;
+
+ if (op != OP_WAY_CLEAR) {
+ /* The WAY_CLEAR operation does the whole way, but other
+ ops take begin-index and count params; we just indicate
+ the entire cache. */
+ V850E2_CACHE_CADL = 0;
+ V850E2_CACHE_CADH = 0;
+ V850E2_CACHE_CCNT = V850E2_CACHE_WAY_SIZE - 1;
+ }
+
+ V850E2_CACHE_COPR = cmd | V850E2_CACHE_COPR_WSL(0); /* way 0 */
+ V850E2_CACHE_COPR = cmd | V850E2_CACHE_COPR_WSL(1); /* way 1 */
+ V850E2_CACHE_COPR = cmd | V850E2_CACHE_COPR_WSL(2); /* way 2 */
+ V850E2_CACHE_COPR = cmd | V850E2_CACHE_COPR_WSL(3); /* way 3 */
+}
+
+/* Apply cache-op OP to all entries in CACHE covering addresses ADDR
+ through ADDR+LEN. */
+static inline void cache_op_range (enum cache_op op, u32 addr, u32 len,
+ enum cache cache)
+{
+ u32 start = CACHE_LINE_ADDR (addr);
+ u32 end = CACHE_LINE_END_ADDR (addr + len);
+ u32 num_lines = (end - start) >> V850E2_CACHE_LINE_SIZE_BITS;
+
+ V850E2_CACHE_CADL = start & 0xFFFF;
+ V850E2_CACHE_CADH = start >> 16;
+ V850E2_CACHE_CCNT = num_lines - 1;
+
+ V850E2_CACHE_COPR = op | cache | V850E2_CACHE_COPR_STRT;
+}
+
+
+/* High-level ops. */
+
+static void cache_exec_after_store_all (void)
+{
+ cache_op_all (OP_SYNC_IF_DIRTY, DCACHE);
+ cache_op_all (OP_WAY_CLEAR, ICACHE);
+}
+
+static void cache_exec_after_store_range (u32 start, u32 len)
+{
+ cache_op_range (OP_SYNC_IF_DIRTY, start, len, DCACHE);
+ cache_op_range (OP_CLEAR, start, len, ICACHE);
+}
+
+
+/* Exported functions. */
+
+void flush_icache (void)
+{
+ cache_exec_after_store_all ();
+}
+
+void flush_icache_range (unsigned long start, unsigned long end)
+{
+ cache_exec_after_store_range (start, end - start);
+}
+
+void flush_icache_page (struct vm_area_struct *vma, struct page *page)
+{
+ cache_exec_after_store_range (page_to_virt (page), PAGE_SIZE);
+}
+
+void flush_icache_user_range (struct vm_area_struct *vma, struct page *page,
+ unsigned long addr, int len)
+{
+ cache_exec_after_store_range (addr, len);
+}
+
+void flush_cache_sigtramp (unsigned long addr)
+{
+ /* For the exact size, see signal.c, but 16 bytes should be enough. */
+ cache_exec_after_store_range (addr, 16);
+}
diff --git a/arch/v850/kernel/nb85e_cache.c b/arch/v850/kernel/v850e_cache.c
index c7c35312b9a3..6ab5cee48ddd 100644
--- a/arch/v850/kernel/nb85e_cache.c
+++ b/arch/v850/kernel/v850e_cache.c
@@ -1,6 +1,5 @@
/*
- * arch/v850/kernel/nb85e_cache.c -- Cache control for NB85E_CACHE212 and
- * NB85E_CACHE213 cache memories
+ * arch/v850/kernel/v850e_cache.c -- Cache control for V850E cache memories
*
* Copyright (C) 2003 NEC Electronics Corporation
* Copyright (C) 2003 Miles Bader <miles@gnu.org>
@@ -12,19 +11,31 @@
* Written by Miles Bader <miles@gnu.org>
*/
+/* This file implements cache control for the rather simple cache used on
+ some V850E CPUs, specifically the NB85E/TEG CPU-core and the V850E/ME2
+ CPU. V850E2 processors have their own (better) cache
+ implementation. */
+
#include <asm/entry.h>
-#include <asm/nb85e_cache.h>
+#include <asm/v850e_cache.h>
#define WAIT_UNTIL_CLEAR(value) while (value) {}
/* Set caching params via the BHC and DCC registers. */
-void nb85e_cache_enable (u16 bhc, u16 dcc)
+void v850e_cache_enable (u16 bhc, u16 icc, u16 dcc)
{
unsigned long *r0_ram = (unsigned long *)R0_RAM_ADDR;
register u16 bhc_val asm ("r6") = bhc;
+ /* Read the instruction cache control register (ICC) and confirm
+ that bits 0 and 1 (TCLR0, TCLR1) are all cleared. */
+ WAIT_UNTIL_CLEAR (V850E_CACHE_ICC & 0x3);
+ V850E_CACHE_ICC = icc;
+
+#ifdef V850E_CACHE_DCC
/* Configure data-cache. */
- NB85E_CACHE_DCC = dcc;
+ V850E_CACHE_DCC = dcc;
+#endif /* V850E_CACHE_DCC */
/* Configure caching for various memory regions by writing the BHC
register. The documentation says that an instruction _cannot_
@@ -32,9 +43,12 @@ void nb85e_cache_enable (u16 bhc, u16 dcc)
instruction itself exists; to work around this, we store
appropriate instructions into the on-chip RAM area (which is never
cached), and briefly jump there to do the work. */
- r0_ram[0] = 0xf0720760; /* st.h r0, 0xfffff072[r0] */
- r0_ram[1] = 0xf06a3760; /* st.h r6, 0xfffff06a[r0] */
- r0_ram[2] = 0x5640006b; /* jmp [r11] */
+#ifdef V850E_CACHE_WRITE_IBS
+ *r0_ram++ = 0xf0720760; /* st.h r0, 0xfffff072[r0] */
+#endif
+ *r0_ram++ = 0xf06a3760; /* st.h r6, 0xfffff06a[r0] */
+ *r0_ram = 0x5640006b; /* jmp [r11] */
+
asm ("mov hilo(1f), r11; jmp [%1]; 1:;"
:: "r" (bhc_val), "r" (R0_RAM_ADDR) : "r11");
}
@@ -43,11 +57,11 @@ static void clear_icache (void)
{
/* 1. Read the instruction cache control register (ICC) and confirm
that bits 0 and 1 (TCLR0, TCLR1) are all cleared. */
- WAIT_UNTIL_CLEAR (NB85E_CACHE_ICC & 0x3);
+ WAIT_UNTIL_CLEAR (V850E_CACHE_ICC & 0x3);
/* 2. Read the ICC register and confirm that bit 12 (LOCK0) is
cleared. Bit 13 of the ICC register is always cleared. */
- WAIT_UNTIL_CLEAR (NB85E_CACHE_ICC & 0x1000);
+ WAIT_UNTIL_CLEAR (V850E_CACHE_ICC & 0x1000);
/* 3. Set the TCLR0 and TCLR1 bits of the ICC register as follows,
when clearing way 0 and way 1 at the same time:
@@ -55,13 +69,17 @@ static void clear_icache (void)
(b) Read the TCLR0 and TCLR1 bits to confirm that these bits
are cleared.
(c) Perform (a) and (b) above again. */
- NB85E_CACHE_ICC |= 0x3;
- WAIT_UNTIL_CLEAR (NB85E_CACHE_ICC & 0x3);
+ V850E_CACHE_ICC |= 0x3;
+ WAIT_UNTIL_CLEAR (V850E_CACHE_ICC & 0x3);
+
+#ifdef V850E_CACHE_REPEAT_ICC_WRITE
/* Do it again. */
- NB85E_CACHE_ICC |= 0x3;
- WAIT_UNTIL_CLEAR (NB85E_CACHE_ICC & 0x3);
+ V850E_CACHE_ICC |= 0x3;
+ WAIT_UNTIL_CLEAR (V850E_CACHE_ICC & 0x3);
+#endif
}
+#ifdef V850E_CACHE_DCC
/* Flush or clear (or both) the data cache, depending on the value of FLAGS;
the procedure is the same for both, just the control bits used differ (and
both may be performed simultaneously). */
@@ -69,47 +87,54 @@ static void dcache_op (unsigned short flags)
{
/* 1. Read the data cache control register (DCC) and confirm that bits
0, 1, 4, and 5 (DC00, DC01, DC04, DC05) are all cleared. */
- WAIT_UNTIL_CLEAR (NB85E_CACHE_DCC & 0x33);
+ WAIT_UNTIL_CLEAR (V850E_CACHE_DCC & 0x33);
/* 2. Clear DCC register bit 12 (DC12), bit 13 (DC13), or both
depending on the way for which tags are to be cleared. */
- NB85E_CACHE_DCC &= ~0xC000;
+ V850E_CACHE_DCC &= ~0xC000;
/* 3. Set DCC register bit 0 (DC00), bit 1 (DC01) or both depending on
the way for which tags are to be cleared.
...
Set DCC register bit 4 (DC04), bit 5 (DC05), or both depending
on the way to be data flushed. */
- NB85E_CACHE_DCC |= flags;
+ V850E_CACHE_DCC |= flags;
/* 4. Read DCC register bit DC00, DC01 [DC04, DC05], or both depending
on the way for which tags were cleared [flushed] and confirm
that that bit is cleared. */
- WAIT_UNTIL_CLEAR (NB85E_CACHE_DCC & flags);
+ WAIT_UNTIL_CLEAR (V850E_CACHE_DCC & flags);
}
+#endif /* V850E_CACHE_DCC */
/* Flushes the contents of the dcache to memory. */
static inline void flush_dcache (void)
{
+#ifdef V850E_CACHE_DCC
/* We only need to do something if in write-back mode. */
- if (NB85E_CACHE_DCC & 0x0400)
+ if (V850E_CACHE_DCC & 0x0400)
dcache_op (0x30);
+#endif /* V850E_CACHE_DCC */
}
/* Flushes the contents of the dcache to memory, and then clears it. */
static inline void clear_dcache (void)
{
+#ifdef V850E_CACHE_DCC
/* We only need to do something if the dcache is enabled. */
- if (NB85E_CACHE_DCC & 0x0C00)
+ if (V850E_CACHE_DCC & 0x0C00)
dcache_op (0x33);
+#endif /* V850E_CACHE_DCC */
}
/* Clears the dcache without flushing to memory first. */
static inline void clear_dcache_no_flush (void)
{
+#ifdef V850E_CACHE_DCC
/* We only need to do something if the dcache is enabled. */
- if (NB85E_CACHE_DCC & 0x0C00)
+ if (V850E_CACHE_DCC & 0x0C00)
dcache_op (0x3);
+#endif /* V850E_CACHE_DCC */
}
static inline void cache_exec_after_store (void)
@@ -121,58 +146,28 @@ static inline void cache_exec_after_store (void)
/* Exported functions. */
-void inline nb85e_cache_flush_all (void)
-{
- clear_icache ();
- clear_dcache ();
-}
-
-void nb85e_cache_flush_mm (struct mm_struct *mm)
-{
- /* nothing */
-}
-
-void nb85e_cache_flush_range (struct mm_struct *mm,
- unsigned long start, unsigned long end)
-{
- /* nothing */
-}
-
-void nb85e_cache_flush_page (struct vm_area_struct *vma,
- unsigned long page_addr)
-{
- /* nothing */
-}
-
-void nb85e_cache_flush_dcache_page (struct page *page)
-{
- /* nothing */
-}
-
-void nb85e_cache_flush_icache (void)
+void flush_icache (void)
{
cache_exec_after_store ();
}
-void nb85e_cache_flush_icache_range (unsigned long start, unsigned long end)
+void flush_icache_range (unsigned long start, unsigned long end)
{
cache_exec_after_store ();
}
-void nb85e_cache_flush_icache_page (struct vm_area_struct *vma,
- struct page *page)
+void flush_icache_page (struct vm_area_struct *vma, struct page *page)
{
cache_exec_after_store ();
}
-void nb85e_cache_flush_icache_user_range (struct vm_area_struct *vma,
- struct page *page,
- unsigned long adr, int len)
+void flush_icache_user_range (struct vm_area_struct *vma, struct page *page,
+ unsigned long adr, int len)
{
cache_exec_after_store ();
}
-void nb85e_cache_flush_sigtramp (unsigned long addr)
+void flush_cache_sigtramp (unsigned long addr)
{
cache_exec_after_store ();
}
diff --git a/arch/v850/kernel/nb85e_intc.c b/arch/v850/kernel/v850e_intc.c
index 7e562195e8d9..8d39a52ee6d1 100644
--- a/arch/v850/kernel/nb85e_intc.c
+++ b/arch/v850/kernel/v850e_intc.c
@@ -1,5 +1,5 @@
/*
- * arch/v850/kernel/nb85e_intc.c -- NB85E cpu core interrupt controller (INTC)
+ * arch/v850/kernel/v850e_intc.c -- V850E interrupt controller (INTC)
*
* Copyright (C) 2001,02,03 NEC Electronics Corporation
* Copyright (C) 2001,02,03 Miles Bader <miles@gnu.org>
@@ -15,18 +15,18 @@
#include <linux/init.h>
#include <linux/irq.h>
-#include <asm/nb85e_intc.h>
+#include <asm/v850e_intc.h>
static void irq_nop (unsigned irq) { }
-static unsigned nb85e_intc_irq_startup (unsigned irq)
+static unsigned v850e_intc_irq_startup (unsigned irq)
{
- nb85e_intc_clear_pending_irq (irq);
- nb85e_intc_enable_irq (irq);
+ v850e_intc_clear_pending_irq (irq);
+ v850e_intc_enable_irq (irq);
return 0;
}
-static void nb85e_intc_end_irq (unsigned irq)
+static void v850e_intc_end_irq (unsigned irq)
{
unsigned long psw, temp;
@@ -64,22 +64,22 @@ static void nb85e_intc_end_irq (unsigned irq)
/* Initialize HW_IRQ_TYPES for INTC-controlled irqs described in array
INITS (which is terminated by an entry with the name field == 0). */
-void __init nb85e_intc_init_irq_types (struct nb85e_intc_irq_init *inits,
+void __init v850e_intc_init_irq_types (struct v850e_intc_irq_init *inits,
struct hw_interrupt_type *hw_irq_types)
{
- struct nb85e_intc_irq_init *init;
+ struct v850e_intc_irq_init *init;
for (init = inits; init->name; init++) {
unsigned i;
struct hw_interrupt_type *hwit = hw_irq_types++;
hwit->typename = init->name;
- hwit->startup = nb85e_intc_irq_startup;
- hwit->shutdown = nb85e_intc_disable_irq;
- hwit->enable = nb85e_intc_enable_irq;
- hwit->disable = nb85e_intc_disable_irq;
+ hwit->startup = v850e_intc_irq_startup;
+ hwit->shutdown = v850e_intc_disable_irq;
+ hwit->enable = v850e_intc_enable_irq;
+ hwit->disable = v850e_intc_disable_irq;
hwit->ack = irq_nop;
- hwit->end = nb85e_intc_end_irq;
+ hwit->end = v850e_intc_end_irq;
/* Initialize kernel IRQ infrastructure for this interrupt. */
init_irq_handlers(init->base, init->num, init->interval, hwit);
@@ -92,13 +92,13 @@ void __init nb85e_intc_init_irq_types (struct nb85e_intc_irq_init *inits,
interrupts are initially disabled), then
assume whoever enabled it has set things up
properly, and avoid messing with it. */
- if (! nb85e_intc_irq_enabled (irq))
+ if (! v850e_intc_irq_enabled (irq))
/* This write also (1) disables the
interrupt, and (2) clears any pending
interrupts. */
- NB85E_INTC_IC (irq)
- = (NB85E_INTC_IC_PR (init->priority)
- | NB85E_INTC_IC_MK);
+ V850E_INTC_IC (irq)
+ = (V850E_INTC_IC_PR (init->priority)
+ | V850E_INTC_IC_MK);
}
}
}
diff --git a/arch/v850/kernel/nb85e_timer_d.c b/arch/v850/kernel/v850e_timer_d.c
index 356675fcbbd5..d2a4ece2574c 100644
--- a/arch/v850/kernel/nb85e_timer_d.c
+++ b/arch/v850/kernel/v850e_timer_d.c
@@ -1,9 +1,9 @@
/*
- * include/asm-v850/nb85e_timer_d.c -- `Timer D' component often used
- * with the NB85E cpu core
+ * include/asm-v850/v850e_timer_d.c -- `Timer D' component often used
+ * with V850E CPUs
*
- * Copyright (C) 2001,02 NEC Corporation
- * Copyright (C) 2001,02 Miles Bader <miles@gnu.org>
+ * Copyright (C) 2001,02,03 NEC Electronics Corporation
+ * Copyright (C) 2001,02,03 Miles Bader <miles@gnu.org>
*
* This file is subject to the terms and conditions of the GNU General
* Public License. See the file COPYING in the main directory of this
@@ -14,41 +14,41 @@
#include <linux/kernel.h>
-#include <asm/nb85e_utils.h>
-#include <asm/nb85e_timer_d.h>
+#include <asm/v850e_utils.h>
+#include <asm/v850e_timer_d.h>
/* Start interval timer TIMER (0-3). The timer will issue the
corresponding INTCMD interrupt RATE times per second.
This function does not enable the interrupt. */
-void nb85e_timer_d_configure (unsigned timer, unsigned rate)
+void v850e_timer_d_configure (unsigned timer, unsigned rate)
{
unsigned divlog2, count;
/* Calculate params for timer. */
if (! calc_counter_params (
- NB85E_TIMER_D_BASE_FREQ, rate,
- NB85E_TIMER_D_TMCD_CS_MIN, NB85E_TIMER_D_TMCD_CS_MAX, 16,
+ V850E_TIMER_D_BASE_FREQ, rate,
+ V850E_TIMER_D_TMCD_CS_MIN, V850E_TIMER_D_TMCD_CS_MAX, 16,
&divlog2, &count))
printk (KERN_WARNING
"Cannot find interval timer %d setting suitable"
" for rate of %dHz.\n"
"Using rate of %dHz instead.\n",
timer, rate,
- (NB85E_TIMER_D_BASE_FREQ >> divlog2) >> 16);
+ (V850E_TIMER_D_BASE_FREQ >> divlog2) >> 16);
/* Do the actual hardware timer initialization: */
/* Enable timer. */
- NB85E_TIMER_D_TMCD(timer) = NB85E_TIMER_D_TMCD_CAE;
+ V850E_TIMER_D_TMCD(timer) = V850E_TIMER_D_TMCD_CAE;
/* Set clock divider. */
- NB85E_TIMER_D_TMCD(timer)
- = NB85E_TIMER_D_TMCD_CAE
- | NB85E_TIMER_D_TMCD_CS(divlog2);
+ V850E_TIMER_D_TMCD(timer)
+ = V850E_TIMER_D_TMCD_CAE
+ | V850E_TIMER_D_TMCD_CS(divlog2);
/* Set timer compare register. */
- NB85E_TIMER_D_CMD(timer) = count;
+ V850E_TIMER_D_CMD(timer) = count;
/* Start counting. */
- NB85E_TIMER_D_TMCD(timer)
- = NB85E_TIMER_D_TMCD_CAE
- | NB85E_TIMER_D_TMCD_CS(divlog2)
- | NB85E_TIMER_D_TMCD_CE;
+ V850E_TIMER_D_TMCD(timer)
+ = V850E_TIMER_D_TMCD_CAE
+ | V850E_TIMER_D_TMCD_CS(divlog2)
+ | V850E_TIMER_D_TMCD_CE;
}
diff --git a/arch/v850/kernel/nb85e_utils.c b/arch/v850/kernel/v850e_utils.c
index e826cb76d177..e6807ef8dee6 100644
--- a/arch/v850/kernel/nb85e_utils.c
+++ b/arch/v850/kernel/v850e_utils.c
@@ -1,9 +1,9 @@
/*
- * include/asm-v850/nb85e_utils.h -- Utility functions associated with
- * the NB85E cpu core
+ * include/asm-v850/v850e_utils.h -- Utility functions associated with
+ * V850E CPUs
*
- * Copyright (C) 2001,02 NEC Corporation
- * Copyright (C) 2001,02 Miles Bader <miles@gnu.org>
+ * Copyright (C) 2001,02,03 NEC Electronics Corporation
+ * Copyright (C) 2001,02,03 Miles Bader <miles@gnu.org>
*
* This file is subject to the terms and conditions of the GNU General
* Public License. See the file COPYING in the main directory of this
@@ -12,10 +12,7 @@
* Written by Miles Bader <miles@gnu.org>
*/
-/* Note: these functions are often associated with the N85E cpu core,
- but not always, which is why they're not in `nb85e.c'. */
-
-#include <asm/nb85e_utils.h>
+#include <asm/v850e_utils.h>
/* Calculate counter clock-divider and count values to attain the
desired frequency RATE from the base frequency BASE_FREQ. The
diff --git a/arch/v850/rte_me2_cb.ld b/arch/v850/rte_me2_cb.ld
new file mode 100644
index 000000000000..e6df7fe1aeae
--- /dev/null
+++ b/arch/v850/rte_me2_cb.ld
@@ -0,0 +1,30 @@
+/* Linker script for the Midas labs RTE-V850E/ME2-CB evaluation board
+ (CONFIG_RTE_CB_ME2), with kernel in SDRAM. */
+
+MEMORY {
+ /* 128Kbyte of IRAM */
+ IRAM : ORIGIN = 0x00000000, LENGTH = 0x00020000
+
+ /* 32MB of SDRAM. */
+ SDRAM : ORIGIN = 0x00800000, LENGTH = 0x02000000
+}
+
+#define KRAM SDRAM
+
+SECTIONS {
+ .text : {
+ __kram_start = . ;
+ TEXT_CONTENTS
+ INTV_CONTENTS /* copy to iRAM (0x0-0x620) */
+ } > KRAM
+
+ .data : {
+ DATA_CONTENTS
+ BSS_CONTENTS
+ RAMK_INIT_CONTENTS
+ __kram_end = . ;
+ BOOTMAP_CONTENTS
+ } > KRAM
+
+ .root ALIGN (4096) : { ROOT_FS_CONTENTS } > SDRAM
+}
diff --git a/arch/v850/sim85e2c.ld b/arch/v850/sim85e2.ld
index b10cb1f38ebf..26b8bad11e81 100644
--- a/arch/v850/sim85e2c.ld
+++ b/arch/v850/sim85e2.ld
@@ -5,40 +5,40 @@ MEMORY {
/* 1MB of `instruction RAM', starting at 0.
Instruction fetches are much faster from IRAM than from DRAM.
This should match IRAM_ADDR in "include/asm-v580/sim85e2c.h". */
- IRAM : ORIGIN = 0x00000000, LENGTH = 0x00100000
+ IRAM : ORIGIN = 0x00000000, LENGTH = 0x00100000
/* 1MB of `data RAM', below and contiguous with the I/O space.
Data fetches are much faster from DRAM than from IRAM.
This should match DRAM_ADDR in "include/asm-v580/sim85e2c.h". */
- DRAM : ORIGIN = 0xfff00000, LENGTH = 0x000ff000
+ DRAM : ORIGIN = 0xfff00000, LENGTH = 0x000ff000
/* We have to load DRAM at a mirror-address of 0x1ff00000,
because the simulator's preprocessing script isn't smart
enough to deal with the above LMA. */
- DRAM_LOAD : ORIGIN = 0x1ff00000, LENGTH = 0x000ff000
+ DRAM_LOAD : ORIGIN = 0x1ff00000, LENGTH = 0x000ff000
/* `external ram' (CS1 area), comes after IRAM.
This should match ERAM_ADDR in "include/asm-v580/sim85e2c.h". */
- ERAM : ORIGIN = 0x00100000, LENGTH = 0x07f00000
+ ERAM : ORIGIN = 0x00100000, LENGTH = 0x07f00000
+
+ /* Dynamic RAM; uses memory controller. */
+ /* SDRAM : ORIGIN = 0x10000000, LENGTH = 0x01000000 */
+ SDRAM : ORIGIN = 0x10000000, LENGTH = 0x00200000/*use 2MB*/
}
SECTIONS {
.iram : {
INTV_CONTENTS
- TEXT_CONTENTS
- RAMK_INIT_CONTENTS
+ *arch/v850/kernel/head.o
+ *(.early.text)
} > IRAM
- .data : {
- __kram_start = . ;
- DATA_CONTENTS
- BSS_CONTENTS
- ROOT_FS_CONTENTS
-
- /* We stick console output into a buffer here. */
+ .dram : {
_memcons_output = . ;
. = . + 0x8000 ;
_memcons_output_end = . ;
-
- __kram_end = . ;
- BOOTMAP_CONTENTS
- } > DRAM AT> DRAM_LOAD
+ } > DRAM
+ .sdram : {
+ /* We stick console output into a buffer here. */
+ RAMK_KRAM_CONTENTS
+ ROOT_FS_CONTENTS
+ } > SDRAM
}
diff --git a/arch/v850/vmlinux.lds.S b/arch/v850/vmlinux.lds.S
index 7391ab36f1a9..3396649e92ac 100644
--- a/arch/v850/vmlinux.lds.S
+++ b/arch/v850/vmlinux.lds.S
@@ -206,8 +206,8 @@ _jiffies = _jiffies_64 ;
# include "sim.ld"
#endif
-#ifdef CONFIG_V850E2_SIM85E2C
-# include "sim85e2c.ld"
+#ifdef CONFIG_V850E2_SIM85E2
+# include "sim85e2.ld"
#endif
#ifdef CONFIG_V850E2_FPGA85E2C
@@ -247,3 +247,8 @@ _jiffies = _jiffies_64 ;
# include "rte_nb85e_cb.ld"
# endif
#endif
+
+#ifdef CONFIG_RTE_CB_ME2
+# include "rte_me2_cb.ld"
+#endif
+
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
index a710e2a55609..0d59682dd618 100644
--- a/drivers/block/Kconfig
+++ b/drivers/block/Kconfig
@@ -264,6 +264,7 @@ config BLK_DEV_LOOP
config BLK_DEV_CRYPTOLOOP
tristate "Cryptoloop Support"
+ select CRYPTO
depends on BLK_DEV_LOOP
---help---
Say Y here if you want to be able to use the ciphers that are
@@ -339,7 +340,7 @@ config BLK_DEV_INITRD
config LBD
bool "Support for Large Block Devices"
- depends on X86
+ depends on X86 || MIPS32 || PPC32 || ARCH_S390_31 || SUPERH
help
Say Y here if you want to attach large (bigger than 2TB) discs to
your machine, or if you want to have a raid or loopback device
diff --git a/drivers/block/as-iosched.c b/drivers/block/as-iosched.c
index 1482512ff24e..41a355124cbf 100644
--- a/drivers/block/as-iosched.c
+++ b/drivers/block/as-iosched.c
@@ -833,10 +833,11 @@ static void as_update_iohist(struct as_io_context *aic, struct request *rq)
+ 2*1024*64);
aic->seek_samples += 256;
- aic->seek_total += 256*seek_dist;
+ aic->seek_total += (u64)256*seek_dist;
if (aic->seek_samples) {
- aic->seek_mean = aic->seek_total + 128;
- sector_div(aic->seek_mean, aic->seek_samples);
+ u64 total = aic->seek_total + (aic->seek_samples>>1);
+ do_div(total, aic->seek_samples);
+ aic->seek_mean = (sector_t)total;
}
aic->seek_samples = (aic->seek_samples>>1)
+ (aic->seek_samples>>2);
@@ -1305,6 +1306,15 @@ static void as_add_request(struct as_data *ad, struct as_rq *arq)
as_update_arq(ad, arq); /* keep state machine up to date */
}
+/*
+ * FIXME: HACK for AS requeue problems
+ */
+static void as_requeue_request(request_queue_t *q, struct request *rq)
+{
+ elv_completed_request(q, rq);
+ __elv_add_request(q, rq, 0, 0);
+}
+
static void
as_insert_request(request_queue_t *q, struct request *rq,
struct list_head *insert_here)
@@ -1820,6 +1830,7 @@ elevator_t iosched_as = {
.elevator_next_req_fn = as_next_request,
.elevator_add_req_fn = as_insert_request,
.elevator_remove_req_fn = as_remove_request,
+ .elevator_requeue_req_fn = as_requeue_request,
.elevator_queue_empty_fn = as_queue_empty,
.elevator_completed_req_fn = as_completed_request,
.elevator_former_req_fn = as_former_request,
diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c
index 8ad5d01e4d42..6951231d4ed5 100644
--- a/drivers/block/cciss_scsi.c
+++ b/drivers/block/cciss_scsi.c
@@ -712,7 +712,8 @@ cciss_scsi_detect(int ctlr)
sh->hostdata[0] = (unsigned long) hba[ctlr];
sh->irq = hba[ctlr]->intr;
sh->unique_id = sh->irq;
- scsi_add_host(sh, &hba[ctlr]->pdev->dev);
+ scsi_add_host(sh, &hba[ctlr]->pdev->dev); /* XXX handle failure */
+ scsi_scan_host(sh);
return 1;
}
diff --git a/drivers/block/elevator.c b/drivers/block/elevator.c
index a9bbb2f3d15a..85630fbb37ad 100644
--- a/drivers/block/elevator.c
+++ b/drivers/block/elevator.c
@@ -213,6 +213,18 @@ void elv_merge_requests(request_queue_t *q, struct request *rq,
e->elevator_merge_req_fn(q, rq, next);
}
+void elv_requeue_request(request_queue_t *q, struct request *rq)
+{
+ /*
+ * if iosched has an explicit requeue hook, then use that. otherwise
+ * just put the request at the front of the queue
+ */
+ if (q->elevator.elevator_requeue_req_fn)
+ q->elevator.elevator_requeue_req_fn(q, rq);
+ else
+ __elv_add_request(q, rq, 0, 0);
+}
+
void __elv_add_request(request_queue_t *q, struct request *rq, int at_end,
int plug)
{
@@ -416,6 +428,7 @@ EXPORT_SYMBOL(elevator_noop);
EXPORT_SYMBOL(elv_add_request);
EXPORT_SYMBOL(__elv_add_request);
+EXPORT_SYMBOL(elv_requeue_request);
EXPORT_SYMBOL(elv_next_request);
EXPORT_SYMBOL(elv_remove_request);
EXPORT_SYMBOL(elv_queue_empty);
diff --git a/drivers/block/ioctl.c b/drivers/block/ioctl.c
index ac31cbe720f1..9f3f411f2389 100644
--- a/drivers/block/ioctl.c
+++ b/drivers/block/ioctl.c
@@ -166,13 +166,11 @@ int blkdev_ioctl(struct inode *inode, struct file *file, unsigned cmd,
return -EINVAL;
if (get_user(n, (int *) arg))
return -EFAULT;
- if (n > PAGE_SIZE || n < 512 || (n & (n - 1)))
- return -EINVAL;
if (bd_claim(bdev, &holder) < 0)
return -EBUSY;
- set_blocksize(bdev, n);
+ ret = set_blocksize(bdev, n);
bd_release(bdev);
- return 0;
+ return ret;
case BLKPG:
return blkpg_ioctl(bdev, (struct blkpg_ioctl_arg *) arg);
case BLKRRPART:
diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c
index 180ac3e95a66..f9678d95a043 100644
--- a/drivers/block/ll_rw_blk.c
+++ b/drivers/block/ll_rw_blk.c
@@ -1494,6 +1494,23 @@ struct request *blk_get_request(request_queue_t *q, int rw, int gfp_mask)
return rq;
}
+/**
+ * blk_requeue_request - put a request back on queue
+ * @q: request queue where request should be inserted
+ * @rq: request to be inserted
+ *
+ * Description:
+ * Drivers often keep queueing requests until the hardware cannot accept
+ * more, when that condition happens we need to put the request back
+ * on the queue. Must be called with queue lock held.
+ */
+void blk_requeue_request(request_queue_t *q, struct request *rq)
+{
+ if (blk_rq_tagged(rq))
+ blk_queue_end_tag(q, rq);
+
+ elv_requeue_request(q, rq);
+}
/**
* blk_insert_request - insert a special request in to a request queue
@@ -2730,6 +2747,7 @@ EXPORT_SYMBOL(blk_hw_contig_segment);
EXPORT_SYMBOL(blk_get_request);
EXPORT_SYMBOL(blk_put_request);
EXPORT_SYMBOL(blk_insert_request);
+EXPORT_SYMBOL(blk_requeue_request);
EXPORT_SYMBOL(blk_queue_prep_rq);
EXPORT_SYMBOL(blk_queue_merge_bvec);
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index cc9c34b09839..d57f3abf6e5e 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -258,7 +258,8 @@ void nbd_send_req(struct nbd_device *lo, struct request *req)
dprintk(DBG_TX, "%s: request %p: sending control (%s@%llu,%luB)\n",
lo->disk->disk_name, req,
nbdcmd_to_ascii(nbd_cmd(req)),
- req->sector << 9, req->nr_sectors << 9);
+ (unsigned long long)req->sector << 9,
+ req->nr_sectors << 9);
result = sock_xmit(sock, 1, &request, sizeof(request),
(nbd_cmd(req) == NBD_CMD_WRITE)? MSG_MORE: 0);
if (result <= 0) {
diff --git a/drivers/char/agp/i460-agp.c b/drivers/char/agp/i460-agp.c
index 263e7de4f115..23f5cece5634 100644
--- a/drivers/char/agp/i460-agp.c
+++ b/drivers/char/agp/i460-agp.c
@@ -608,7 +608,7 @@ static struct pci_driver agp_intel_i460_pci_driver = {
.name = "agpgart-intel-i460",
.id_table = agp_intel_i460_pci_table,
.probe = agp_intel_i460_probe,
- .remove = agp_intel_i460_remove,
+ .remove = __devexit_p(agp_intel_i460_remove),
};
static int __init agp_intel_i460_init(void)
diff --git a/drivers/char/ftape/lowlevel/fdc-io.c b/drivers/char/ftape/lowlevel/fdc-io.c
index 7b4a260a12f3..1f1363a03564 100644
--- a/drivers/char/ftape/lowlevel/fdc-io.c
+++ b/drivers/char/ftape/lowlevel/fdc-io.c
@@ -66,6 +66,7 @@ int ft_mach2 = CONFIG_FT_MACH2;
/* Local vars.
*/
+static spinlock_t fdc_io_lock;
static unsigned int fdc_calibr_count;
static unsigned int fdc_calibr_time;
static int fdc_status;
@@ -89,14 +90,13 @@ void fdc_catch_stray_interrupts(int count)
{
unsigned long flags;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&fdc_io_lock, flags);
if (count == 0) {
ft_expected_stray_interrupts = 0;
} else {
ft_expected_stray_interrupts += count;
}
- restore_flags(flags);
+ spin_unlock_irqrestore(&fdc_io_lock, flags);
}
/* Wait during a timeout period for a given FDC status.
@@ -194,8 +194,7 @@ int fdc_command(const __u8 * cmd_data, int cmd_len)
TRACE_FUN(ft_t_any);
fdc_usec_wait(FT_RQM_DELAY); /* wait for valid RQM status */
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&fdc_io_lock, flags);
if (!in_interrupt())
/* Yes, I know, too much comments inside this function
* ...
@@ -242,12 +241,11 @@ int fdc_command(const __u8 * cmd_data, int cmd_len)
}
fdc_usec_wait(FT_RQM_DELAY); /* wait for valid RQM status */
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&fdc_io_lock, flags);
}
fdc_status = inb(fdc.msr);
if ((fdc_status & FDC_DATA_READY_MASK) != FDC_DATA_IN_READY) {
- restore_flags(flags);
+ spin_unlock_irqrestore(&fdc_io_lock, flags);
TRACE_ABORT(-EBUSY, ft_t_err, "fdc not ready");
}
fdc_mode = *cmd_data; /* used by isr */
@@ -289,7 +287,7 @@ int fdc_command(const __u8 * cmd_data, int cmd_len)
last_time = ftape_timestamp();
}
#endif
- restore_flags(flags);
+ spin_unlock_irqrestore(&fdc_io_lock, flags);
TRACE_EXIT result;
}
@@ -305,15 +303,14 @@ int fdc_result(__u8 * res_data, int res_len)
int retry = 0;
TRACE_FUN(ft_t_any);
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&fdc_io_lock, flags);
fdc_status = inb(fdc.msr);
if ((fdc_status & FDC_DATA_READY_MASK) != FDC_DATA_OUT_READY) {
TRACE(ft_t_err, "fdc not ready");
result = -EBUSY;
} else while (count) {
if (!(fdc_status & FDC_BUSY)) {
- restore_flags(flags);
+ spin_unlock_irqrestore(&fdc_io_lock, flags);
TRACE_ABORT(-EIO, ft_t_err, "premature end of result phase");
}
result = fdc_read(res_data);
@@ -336,7 +333,7 @@ int fdc_result(__u8 * res_data, int res_len)
++res_data;
}
}
- restore_flags(flags);
+ spin_unlock_irqrestore(&fdc_io_lock, flags);
fdc_usec_wait(FT_RQM_DELAY); /* allow FDC to negate BSY */
TRACE_EXIT result;
}
@@ -609,8 +606,7 @@ void fdc_reset(void)
unsigned long flags;
TRACE_FUN(ft_t_any);
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&fdc_io_lock, flags);
fdc_dor_reset(1); /* keep unit selected */
@@ -629,7 +625,7 @@ void fdc_reset(void)
*/
fdc_update_dsr(); /* restore data rate and precomp */
- restore_flags(flags);
+ spin_unlock_irqrestore(&fdc_io_lock, flags);
/*
* Wait for first polling cycle to complete
@@ -928,8 +924,7 @@ int fdc_setup_formatting(buffer_struct * buff)
*/
TRACE(ft_t_fdc_dma,
"phys. addr. = %lx", virt_to_bus((void*) buff->ptr));
- save_flags(flags);
- cli(); /* could be called from ISR ! */
+ spin_lock_irqsave(&fdc_io_lock, flags);
fdc_setup_dma(DMA_MODE_WRITE, buff->ptr, FT_SECTORS_PER_SEGMENT * 4);
/* Issue FDC command to start reading/writing.
*/
@@ -937,7 +932,7 @@ int fdc_setup_formatting(buffer_struct * buff)
out[4] = buff->gap3;
TRACE_CATCH(fdc_setup_error = fdc_command(out, sizeof(out)),
restore_flags(flags); fdc_mode = fdc_idle);
- restore_flags(flags);
+ spin_unlock_irqrestore(&fdc_io_lock, flags);
TRACE_EXIT 0;
}
@@ -977,11 +972,10 @@ int fdc_setup_read_write(buffer_struct * buff, __u8 operation)
break;
default:
TRACE_ABORT(-EIO,
- ft_t_bug, "bug: illegal operation parameter");
+ ft_t_bug, "bug: invalid operation parameter");
}
TRACE(ft_t_fdc_dma, "phys. addr. = %lx",virt_to_bus((void*)buff->ptr));
- save_flags(flags);
- cli(); /* could be called from ISR ! */
+ spin_lock_irqsave(&fdc_io_lock, flags);
if (operation != FDC_VERIFY) {
fdc_setup_dma(dma_mode, buff->ptr,
FT_SECTOR_SIZE * buff->sector_count);
@@ -999,7 +993,7 @@ int fdc_setup_read_write(buffer_struct * buff, __u8 operation)
out[8] = 0xff; /* No limit to transfer size. */
TRACE(ft_t_fdc_dma, "C: 0x%02x, H: 0x%02x, R: 0x%02x, cnt: 0x%02x",
out[2], out[3], out[4], out[6] - out[4] + 1);
- restore_flags(flags);
+ spin_unlock_irqrestore(&fdc_io_lock, flags);
TRACE_CATCH(fdc_setup_error = fdc_command(out, 9),fdc_mode = fdc_idle);
TRACE_EXIT 0;
}
diff --git a/drivers/char/ftape/lowlevel/ftape-calibr.c b/drivers/char/ftape/lowlevel/ftape-calibr.c
index 25ed389deb6c..34f0e69d3542 100644
--- a/drivers/char/ftape/lowlevel/ftape-calibr.c
+++ b/drivers/char/ftape/lowlevel/ftape-calibr.c
@@ -49,6 +49,8 @@
static unsigned long ps_per_cycle = 0;
#endif
+static spinlock_t calibr_lock;
+
/*
* Note: On Intel PCs, the clock ticks at 100 Hz (HZ==100) which is
* too slow for certain timeouts (and that clock doesn't even tick
@@ -75,13 +77,12 @@ unsigned int ftape_timestamp(void)
__u16 lo;
__u16 hi;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&calibr_lock, flags);
outb_p(0x00, 0x43); /* latch the count ASAP */
lo = inb_p(0x40); /* read the latched count */
lo |= inb(0x40) << 8;
hi = jiffies;
- restore_flags(flags);
+ spin_unlock_irqrestore(&calibr_lock, flags);
return ((hi + 1) * (unsigned int) LATCH) - lo; /* downcounter ! */
#endif
}
@@ -94,12 +95,11 @@ static unsigned int short_ftape_timestamp(void)
unsigned int count;
unsigned long flags;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&calibr_lock, flags);
outb_p(0x00, 0x43); /* latch the count ASAP */
count = inb_p(0x40); /* read the latched count */
count |= inb(0x40) << 8;
- restore_flags(flags);
+ spin_unlock_irqrestore(&calibr_lock, flags);
return (LATCH - count); /* normal: downcounter */
#endif
}
@@ -150,14 +150,13 @@ static void time_inb(void)
int status;
TRACE_FUN(ft_t_any);
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&calibr_lock, flags);
t0 = short_ftape_timestamp();
for (i = 0; i < 1000; ++i) {
status = inb(fdc.msr);
}
t1 = short_ftape_timestamp();
- restore_flags(flags);
+ spin_unlock_irqrestore(&calibr_lock, flags);
TRACE(ft_t_info, "inb() duration: %d nsec", ftape_timediff(t0, t1));
TRACE_EXIT;
}
@@ -241,8 +240,7 @@ void ftape_calibrate(char *name,
*calibr_count =
*calibr_time = count; /* set TC to 1 */
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&calibr_lock, flags);
fun(0); /* dummy, get code into cache */
t0 = short_ftape_timestamp();
fun(0); /* overhead + one test */
@@ -252,7 +250,7 @@ void ftape_calibrate(char *name,
fun(count); /* overhead + count tests */
t1 = short_ftape_timestamp();
multiple = diff(t0, t1);
- restore_flags(flags);
+ spin_unlock_irqrestore(&calibr_lock, flags);
time = ftape_timediff(0, multiple - once);
tc = (1000 * time) / (count - 1);
TRACE(ft_t_any, "once:%3d us,%6d times:%6d us, TC:%5d ns",
diff --git a/drivers/char/ftape/lowlevel/ftape-format.c b/drivers/char/ftape/lowlevel/ftape-format.c
index 41f43dffb097..5dd4c59a3f34 100644
--- a/drivers/char/ftape/lowlevel/ftape-format.c
+++ b/drivers/char/ftape/lowlevel/ftape-format.c
@@ -44,6 +44,8 @@
#define FT_FMT_SEGS_PER_BUF (FT_BUFF_SIZE/(4*FT_SECTORS_PER_SEGMENT))
#endif
+static spinlock_t ftape_format_lock;
+
/*
* first segment of the new buffer
*/
@@ -129,9 +131,9 @@ int ftape_format_track(const unsigned int track, const __u8 gap3)
head->status = formatting;
TRACE_CATCH(ftape_seek_head_to_track(track),);
TRACE_CATCH(ftape_command(QIC_LOGICAL_FORWARD),);
- save_flags(flags); cli();
+ spin_lock_irqsave(&ftape_format_lock, flags);
TRACE_CATCH(fdc_setup_formatting(head), restore_flags(flags));
- restore_flags(flags);
+ spin_unlock_irqrestore(&ftape_format_lock, flags);
TRACE_EXIT 0;
}
diff --git a/drivers/char/ftape/zftape/zftape-init.c b/drivers/char/ftape/zftape/zftape-init.c
index f329f86a4dd1..788e032f379d 100644
--- a/drivers/char/ftape/zftape/zftape-init.c
+++ b/drivers/char/ftape/zftape/zftape-init.c
@@ -118,7 +118,7 @@ static int zft_open(struct inode *ino, struct file *filep)
>
FTAPE_SEL_D) {
clear_bit(0,&busy_flag);
- TRACE_ABORT(-ENXIO, ft_t_err, "failed: illegal unit nr");
+ TRACE_ABORT(-ENXIO, ft_t_err, "failed: invalid unit nr");
}
orig_sigmask = current->blocked;
sigfillset(&current->blocked);
diff --git a/drivers/char/ip2.c b/drivers/char/ip2.c
index 334d40c18572..28aefc023688 100644
--- a/drivers/char/ip2.c
+++ b/drivers/char/ip2.c
@@ -38,16 +38,14 @@ static int irq[IP2_MAX_BOARDS] = { -1, -1, -1, -1 };
static int poll_only = 0;
-# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
- MODULE_AUTHOR("Doug McNash");
- MODULE_DESCRIPTION("Computone IntelliPort Plus Driver");
- MODULE_PARM(irq,"1-"__MODULE_STRING(IP2_MAX_BOARDS) "i");
- MODULE_PARM_DESC(irq,"Interrupts for IntelliPort Cards");
- MODULE_PARM(io,"1-"__MODULE_STRING(IP2_MAX_BOARDS) "i");
- MODULE_PARM_DESC(io,"I/O ports for IntelliPort Cards");
- MODULE_PARM(poll_only,"1i");
- MODULE_PARM_DESC(poll_only,"Do not use card interrupts");
-# endif /* LINUX_VERSION */
+MODULE_AUTHOR("Doug McNash");
+MODULE_DESCRIPTION("Computone IntelliPort Plus Driver");
+MODULE_PARM(irq,"1-"__MODULE_STRING(IP2_MAX_BOARDS) "i");
+MODULE_PARM_DESC(irq,"Interrupts for IntelliPort Cards");
+MODULE_PARM(io,"1-"__MODULE_STRING(IP2_MAX_BOARDS) "i");
+MODULE_PARM_DESC(io,"I/O ports for IntelliPort Cards");
+MODULE_PARM(poll_only,"1i");
+MODULE_PARM_DESC(poll_only,"Do not use card interrupts");
//======================================================================
diff --git a/drivers/char/ip2/i2lib.c b/drivers/char/ip2/i2lib.c
index 1b3e7e0ecec4..2da7545fe3d1 100644
--- a/drivers/char/ip2/i2lib.c
+++ b/drivers/char/ip2/i2lib.c
@@ -1089,7 +1089,7 @@ i2Output(i2ChanStrPtr pCh, const char *pSource, int count, int user )
// Move the data
if ( user ) {
- COPY_FROM_USER(rc, (char*)(DATA_OF(pInsert)), pSource,
+ rc = copy_from_user((char*)(DATA_OF(pInsert)), pSource,
amountToMove );
} else {
memcpy( (char*)(DATA_OF(pInsert)), pSource, amountToMove );
diff --git a/drivers/char/ip2/i2os.h b/drivers/char/ip2/i2os.h
index c83e901ea63f..92d0d63d755d 100644
--- a/drivers/char/ip2/i2os.h
+++ b/drivers/char/ip2/i2os.h
@@ -19,8 +19,6 @@
#ifndef I2OS_H /* To prevent multiple includes */
#define I2OS_H 1
-#define VERSION(ver,rel,seq) (((ver)<<16) | ((rel)<<8) | (seq))
-
//-------------------------------------------------
// Required Includes
//-------------------------------------------------
@@ -46,22 +44,6 @@
// Interrupt control
//--------------------------------------------
-#if LINUX_VERSION_CODE < 0x00020100
-typedef int spinlock_t;
-#define spin_lock_init()
-#define spin_lock(a)
-#define spin_unlock(a)
-#define spin_lock_irqsave(a,b) {save_flags((b));cli();}
-#define spin_unlock_irqrestore(a,b) {restore_flags((b));}
-#define write_lock_irqsave(a,b) spin_lock_irqsave(a,b)
-#define write_unlock_irqrestore(a,b) spin_unlock_irqrestore(a,b)
-#define read_lock_irqsave(a,b) spin_lock_irqsave(a,b)
-#define read_unlock_irqrestore(a,b) spin_unlock_irqrestore(a,b)
-#endif
-
-//#define SAVE_AND_DISABLE_INTS(a,b) spin_lock_irqsave(a,b)
-//#define RESTORE_INTS(a,b) spin_unlock_irqrestore(a,b)
-
#define LOCK_INIT(a) rwlock_init(a)
#define SAVE_AND_DISABLE_INTS(a,b) { \
diff --git a/drivers/char/ip2main.c b/drivers/char/ip2main.c
index bda3c14dad35..0dd339726bb7 100644
--- a/drivers/char/ip2main.c
+++ b/drivers/char/ip2main.c
@@ -83,7 +83,6 @@
/* Includes */
/************/
#include <linux/config.h>
-// Uncomment the following if you want it compiled with modversions
#include <linux/version.h>
@@ -120,82 +119,11 @@
#include <asm/irq.h>
#include <asm/bitops.h>
-#ifndef KERNEL_VERSION
-#define KERNEL_VERSION(ver,rel,seq) (((ver)<<16) | ((rel)<<8) | (seq))
-#endif
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
-# include <linux/vmalloc.h>
-# include <linux/init.h>
-# include <asm/serial.h>
-#else
-# include <linux/bios32.h>
-#endif
-
-// These VERSION switches maybe inexact because I simply don't know
-// when the various features appeared in the 2.1.XX kernels.
-// They are good enough for 2.0 vs 2.2 and if you are fooling with
-// the 2.1.XX stuff then it would be trivial for you to fix.
-// Most of these macros were stolen from some other drivers
-// so blame them.
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,4)
-# define GET_USER(error,value,addr) error = get_user(value,addr)
-# define COPY_FROM_USER(error,dest,src,size) error = copy_from_user(dest,src,size) ? -EFAULT : 0
-# define PUT_USER(error,value,addr) error = put_user(value,addr)
-# define COPY_TO_USER(error,dest,src,size) error = copy_to_user(dest,src,size) ? -EFAULT : 0
-
-# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,5)
-# include <asm/uaccess.h>
-# define pcibios_strerror(status) \
- printk( KERN_ERR "IP2: PCI error 0x%x \n", status );
-# endif
-
-#else /* 2.0.x and 2.1.x before 2.1.4 */
-
-# define proc_register_dynamic(a,b) proc_register(a,b)
-
-# define GET_USER(error,value,addr) \
- do { \
- error = verify_area (VERIFY_READ, (void *) addr, sizeof (value)); \
- if (error == 0) \
- value = get_user(addr); \
- } while (0)
-
-# define COPY_FROM_USER(error,dest,src,size) \
- do { \
- error = verify_area (VERIFY_READ, (void *) src, size); \
- if (error == 0) \
- memcpy_fromfs (dest, src, size); \
- } while (0)
-
-# define PUT_USER(error,value,addr) \
- do { \
- error = verify_area (VERIFY_WRITE, (void *) addr, sizeof (value)); \
- if (error == 0) \
- put_user (value, addr); \
- } while (0)
-
-# define COPY_TO_USER(error,dest,src,size) \
- do { \
- error = verify_area (VERIFY_WRITE, (void *) dest, size); \
- if (error == 0) \
- memcpy_tofs (dest, src, size); \
- } while (0)
-
-#endif
+#include <linux/vmalloc.h>
+#include <linux/init.h>
+#include <asm/serial.h>
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0)
-#define __init
-#define __initfunc(a) a
-#define __initdata
-#define ioremap(a,b) vremap((a),(b))
-#define iounmap(a) vfree((a))
-#define SERIAL_TYPE_NORMAL 1
-#define schedule_timeout(a){current->timeout = jiffies + (a); schedule();}
-#define signal_pending(a) ((a)->signal & ~(a)->blocked)
-#define in_interrupt() intr_count
-#endif
+#include <asm/uaccess.h>
#include "./ip2/ip2types.h"
#include "./ip2/ip2trace.h"
@@ -276,11 +204,7 @@ static int set_modem_info(i2ChanStrPtr, unsigned int, unsigned int *);
static int get_serial_info(i2ChanStrPtr, struct serial_struct *);
static int set_serial_info(i2ChanStrPtr, struct serial_struct *);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0)
-static int ip2_ipl_read(struct inode *, char *, size_t , loff_t *);
-#else
-static ssize_t ip2_ipl_read(struct file *, char *, size_t, loff_t *) ;
-#endif
+static ssize_t ip2_ipl_read(struct file *, char *, size_t, loff_t *);
static ssize_t ip2_ipl_write(struct file *, const char *, size_t, loff_t *);
static int ip2_ipl_ioctl(struct inode *, struct file *, UINT, ULONG);
static int ip2_ipl_open(struct inode *, struct file *);
@@ -354,9 +278,6 @@ static int tracewrap;
#define DBG_CNT(s)
#endif
-#define MIN(a,b) ( ( (a) < (b) ) ? (a) : (b) )
-#define MAX(a,b) ( ( (a) > (b) ) ? (a) : (b) )
-
/********/
/* Code */
/********/
@@ -366,12 +287,9 @@ static int tracewrap;
#include "./ip2/i2lib.c" /* High level interface services */
/* Configuration area for modprobe */
-#ifdef MODULE
-# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
- MODULE_AUTHOR("Doug McNash");
- MODULE_DESCRIPTION("Computone IntelliPort Plus Driver");
-# endif /* LINUX_VERSION */
-#endif /* MODULE */
+
+MODULE_AUTHOR("Doug McNash");
+MODULE_DESCRIPTION("Computone IntelliPort Plus Driver");
static int poll_only = 0;
@@ -660,53 +578,6 @@ ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize)
break;
case PCI:
#ifdef CONFIG_PCI
-#if (LINUX_VERSION_CODE < 0x020163) /* 2.1.99 */
- if (pcibios_present()) {
- unsigned char pci_bus, pci_devfn;
- int Pci_index = 0;
- status = pcibios_find_device(PCI_VENDOR_ID_COMPUTONE,
- PCI_DEVICE_ID_COMPUTONE_IP2EX, Pci_index,
- &pci_bus, &pci_devfn);
- if (status == 0) {
- unsigned int addr;
- unsigned char pci_irq;
-
- ip2config.type[i] = PCI;
- /*
- * Update Pci_index, so that the next time we go
- * searching for a PCI board we find a different
- * one.
- */
- ++Pci_index;
-
- pcibios_read_config_dword(pci_bus, pci_devfn,
- PCI_BASE_ADDRESS_1, &addr);
- if ( addr & 1 ) {
- ip2config.addr[i]=(USHORT)(addr&0xfffe);
- } else {
- printk( KERN_ERR "IP2: PCI I/O address error\n");
- }
- pcibios_read_config_byte(pci_bus, pci_devfn,
- PCI_INTERRUPT_LINE, &pci_irq);
-
-// If the PCI BIOS assigned it, lets try and use it. If we
-// can't acquire it or it screws up, deal with it then.
-
-// if (!is_valid_irq(pci_irq)) {
-// printk( KERN_ERR "IP2: Bad PCI BIOS IRQ(%d)\n",pci_irq);
-// pci_irq = 0;
-// }
- ip2config.irq[i] = pci_irq;
- } else { // ann error
- ip2config.addr[i] = 0;
- if (status == PCIBIOS_DEVICE_NOT_FOUND) {
- printk( KERN_ERR "IP2: PCI board %d not found\n", i );
- } else {
- pcibios_strerror(status);
- }
- }
- }
-#else /* LINUX_VERSION_CODE > 2.1.99 */
{
struct pci_dev *pci_dev_i = NULL;
pci_dev_i = pci_find_device(PCI_VENDOR_ID_COMPUTONE,
@@ -739,11 +610,10 @@ ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize)
if (status == PCIBIOS_DEVICE_NOT_FOUND) {
printk( KERN_ERR "IP2: PCI board %d not found\n", i );
} else {
- pcibios_strerror(status);
+ printk( KERN_ERR "IP2: PCI error 0x%x \n", status );
}
}
}
-#endif /* ! 2_0_X */
#else
printk( KERN_ERR "IP2: PCI card specified but PCI support not\n");
printk( KERN_ERR "IP2: configured in this kernel.\n");
@@ -2193,7 +2063,7 @@ ip2_ioctl ( PTTY tty, struct file *pFile, UINT cmd, ULONG arg )
ip2trace (CHANN, ITRC_IOCTL, 6, 1, rc );
- PUT_USER(rc,C_CLOCAL(tty) ? 1 : 0, (unsigned long *) arg);
+ rc = put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *) arg);
if (rc)
return rc;
break;
@@ -2202,7 +2072,7 @@ ip2_ioctl ( PTTY tty, struct file *pFile, UINT cmd, ULONG arg )
ip2trace (CHANN, ITRC_IOCTL, 7, 1, rc );
- GET_USER(rc,arg,(unsigned long *) arg);
+ rc = get_user(arg,(unsigned long *) arg);
if (rc)
return rc;
tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL)
@@ -2243,7 +2113,7 @@ ip2_ioctl ( PTTY tty, struct file *pFile, UINT cmd, ULONG arg )
return -EINTR;
}
#endif
- PUT_USER(rc,
+ rc = put_user(
((pCh->dataSetOut & I2_RTS) ? TIOCM_RTS : 0)
| ((pCh->dataSetOut & I2_DTR) ? TIOCM_DTR : 0)
| ((pCh->dataSetIn & I2_DCD) ? TIOCM_CAR : 0)
@@ -2333,17 +2203,17 @@ ip2_ioctl ( PTTY tty, struct file *pFile, UINT cmd, ULONG arg )
cnow = pCh->icount;
restore_flags(flags);
p_cuser = (struct serial_icounter_struct *) arg;
- PUT_USER(rc,cnow.cts, &p_cuser->cts);
- PUT_USER(rc,cnow.dsr, &p_cuser->dsr);
- PUT_USER(rc,cnow.rng, &p_cuser->rng);
- PUT_USER(rc,cnow.dcd, &p_cuser->dcd);
- PUT_USER(rc,cnow.rx, &p_cuser->rx);
- PUT_USER(rc,cnow.tx, &p_cuser->tx);
- PUT_USER(rc,cnow.frame, &p_cuser->frame);
- PUT_USER(rc,cnow.overrun, &p_cuser->overrun);
- PUT_USER(rc,cnow.parity, &p_cuser->parity);
- PUT_USER(rc,cnow.brk, &p_cuser->brk);
- PUT_USER(rc,cnow.buf_overrun, &p_cuser->buf_overrun);
+ rc = put_user(cnow.cts, &p_cuser->cts);
+ rc = put_user(cnow.dsr, &p_cuser->dsr);
+ rc = put_user(cnow.rng, &p_cuser->rng);
+ rc = put_user(cnow.dcd, &p_cuser->dcd);
+ rc = put_user(cnow.rx, &p_cuser->rx);
+ rc = put_user(cnow.tx, &p_cuser->tx);
+ rc = put_user(cnow.frame, &p_cuser->frame);
+ rc = put_user(cnow.overrun, &p_cuser->overrun);
+ rc = put_user(cnow.parity, &p_cuser->parity);
+ rc = put_user(cnow.brk, &p_cuser->brk);
+ rc = put_user(cnow.buf_overrun, &p_cuser->buf_overrun);
break;
/*
@@ -2387,7 +2257,7 @@ set_modem_info(i2ChanStrPtr pCh, unsigned cmd, unsigned int *value)
int rc;
unsigned int arg;
- GET_USER(rc,arg,value);
+ rc = get_user(arg,value);
if (rc)
return rc;
switch(cmd) {
@@ -2469,7 +2339,7 @@ get_serial_info ( i2ChanStrPtr pCh, struct serial_struct *retinfo )
tmp.close_delay = pCh->ClosingDelay;
tmp.closing_wait = pCh->ClosingWaitTime;
tmp.custom_divisor = pCh->BaudDivisor;
- COPY_TO_USER(rc,retinfo,&tmp,sizeof(*retinfo));
+ rc = copy_to_user(retinfo,&tmp,sizeof(*retinfo));
return rc;
}
@@ -2489,15 +2359,15 @@ set_serial_info( i2ChanStrPtr pCh, struct serial_struct *new_info )
{
struct serial_struct ns;
int old_flags, old_baud_divisor;
- int rc = 0;
if ( !new_info ) {
return -EFAULT;
}
- COPY_FROM_USER(rc, &ns, new_info, sizeof (ns) );
- if (rc) {
- return rc;
+
+ if (copy_from_user(&ns, new_info, sizeof (ns))) {
+ return -EFAULT;
}
+
/*
* We don't allow setserial to change IRQ, board address, type or baud
* base. Also line nunber as such is meaningless but we use it for our
@@ -2537,7 +2407,7 @@ set_serial_info( i2ChanStrPtr pCh, struct serial_struct *new_info )
set_params( pCh, NULL );
}
- return rc;
+ return 0;
}
/******************************************************************************/
@@ -2860,16 +2730,10 @@ service_it:
/******************************************************************************/
static
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0)
-int
-ip2_ipl_read(struct inode *pInode, char *pData, size_t count, loff_t *off )
- unsigned int minor = minor( pInode->i_rdev );
-#else
ssize_t
ip2_ipl_read(struct file *pFile, char *pData, size_t count, loff_t *off )
{
unsigned int minor = minor( pFile->f_dentry->d_inode->i_rdev );
-#endif
int rc = 0;
#ifdef IP2DEBUG_IPL
@@ -2904,7 +2768,7 @@ DumpFifoBuffer ( char *pData, int count )
{
#ifdef DEBUG_FIFO
int rc;
- COPY_TO_USER(rc, pData, DBGBuf, count);
+ rc = copy_to_user(pData, DBGBuf, count);
printk(KERN_DEBUG "Last index %d\n", I );
@@ -2925,10 +2789,10 @@ DumpTraceBuffer ( char *pData, int count )
if ( count < (sizeof(int) * 6) ) {
return -EIO;
}
- PUT_USER(rc, tracewrap, pIndex );
- PUT_USER(rc, TRACEMAX, ++pIndex );
- PUT_USER(rc, tracestrip, ++pIndex );
- PUT_USER(rc, tracestuff, ++pIndex );
+ rc = put_user(tracewrap, pIndex );
+ rc = put_user(TRACEMAX, ++pIndex );
+ rc = put_user(tracestrip, ++pIndex );
+ rc = put_user(tracestuff, ++pIndex );
pData += sizeof(int) * 6;
count -= sizeof(int) * 6;
@@ -2941,7 +2805,7 @@ DumpTraceBuffer ( char *pData, int count )
}
chunk = TRACEMAX - tracestrip;
if ( dumpcount > chunk ) {
- COPY_TO_USER(rc, pData, &tracebuf[tracestrip],
+ rc = copy_to_user(pData, &tracebuf[tracestrip],
chunk * sizeof(tracebuf[0]) );
pData += chunk * sizeof(tracebuf[0]);
tracestrip = 0;
@@ -2949,13 +2813,13 @@ DumpTraceBuffer ( char *pData, int count )
} else {
chunk = dumpcount;
}
- COPY_TO_USER(rc, pData, &tracebuf[tracestrip],
+ rc = copy_to_user(pData, &tracebuf[tracestrip],
chunk * sizeof(tracebuf[0]) );
tracestrip += chunk;
tracewrap = 0;
- PUT_USER(rc, tracestrip, ++pIndex );
- PUT_USER(rc, tracestuff, ++pIndex );
+ rc = put_user(tracestrip, ++pIndex );
+ rc = put_user(tracestuff, ++pIndex );
return dumpcount;
#else
@@ -3019,15 +2883,15 @@ ip2_ipl_ioctl ( struct inode *pInode, struct file *pFile, UINT cmd, ULONG arg )
case 13:
switch ( cmd ) {
case 64: /* Driver - ip2stat */
- PUT_USER(rc, ip2_tty_driver->refcount, pIndex++ );
- PUT_USER(rc, irq_counter, pIndex++ );
- PUT_USER(rc, bh_counter, pIndex++ );
+ rc = put_user(ip2_tty_driver->refcount, pIndex++ );
+ rc = put_user(irq_counter, pIndex++ );
+ rc = put_user(bh_counter, pIndex++ );
break;
case 65: /* Board - ip2stat */
if ( pB ) {
- COPY_TO_USER(rc, (char*)arg, (char*)pB, sizeof(i2eBordStr) );
- PUT_USER(rc, INB(pB->i2eStatus),
+ rc = copy_to_user((char*)arg, (char*)pB, sizeof(i2eBordStr) );
+ rc = put_user(INB(pB->i2eStatus),
(ULONG*)(arg + (ULONG)(&pB->i2eStatus) - (ULONG)pB ) );
} else {
rc = -ENODEV;
@@ -3039,7 +2903,7 @@ ip2_ipl_ioctl ( struct inode *pInode, struct file *pFile, UINT cmd, ULONG arg )
pCh = DevTable[cmd];
if ( pCh )
{
- COPY_TO_USER(rc, (char*)arg, (char*)pCh, sizeof(i2ChanStr) );
+ rc = copy_to_user((char*)arg, (char*)pCh, sizeof(i2ChanStr) );
} else {
rc = -ENODEV;
}
@@ -3054,60 +2918,60 @@ ip2_ipl_ioctl ( struct inode *pInode, struct file *pFile, UINT cmd, ULONG arg )
break;
case 3: // Trace device
if ( cmd == 1 ) {
- PUT_USER(rc, iiSendPendingMail, pIndex++ );
- PUT_USER(rc, i2InitChannels, pIndex++ );
- PUT_USER(rc, i2QueueNeeds, pIndex++ );
- PUT_USER(rc, i2QueueCommands, pIndex++ );
- PUT_USER(rc, i2GetStatus, pIndex++ );
- PUT_USER(rc, i2Input, pIndex++ );
- PUT_USER(rc, i2InputFlush, pIndex++ );
- PUT_USER(rc, i2Output, pIndex++ );
- PUT_USER(rc, i2FlushOutput, pIndex++ );
- PUT_USER(rc, i2DrainWakeup, pIndex++ );
- PUT_USER(rc, i2DrainOutput, pIndex++ );
- PUT_USER(rc, i2OutputFree, pIndex++ );
- PUT_USER(rc, i2StripFifo, pIndex++ );
- PUT_USER(rc, i2StuffFifoBypass, pIndex++ );
- PUT_USER(rc, i2StuffFifoFlow, pIndex++ );
- PUT_USER(rc, i2StuffFifoInline, pIndex++ );
- PUT_USER(rc, i2ServiceBoard, pIndex++ );
- PUT_USER(rc, serviceOutgoingFifo, pIndex++ );
- // PUT_USER(rc, ip2_init, pIndex++ );
- PUT_USER(rc, ip2_init_board, pIndex++ );
- PUT_USER(rc, find_eisa_board, pIndex++ );
- PUT_USER(rc, set_irq, pIndex++ );
- PUT_USER(rc, ip2_interrupt, pIndex++ );
- PUT_USER(rc, ip2_poll, pIndex++ );
- PUT_USER(rc, service_all_boards, pIndex++ );
- PUT_USER(rc, do_input, pIndex++ );
- PUT_USER(rc, do_status, pIndex++ );
+ rc = put_user(iiSendPendingMail, pIndex++ );
+ rc = put_user(i2InitChannels, pIndex++ );
+ rc = put_user(i2QueueNeeds, pIndex++ );
+ rc = put_user(i2QueueCommands, pIndex++ );
+ rc = put_user(i2GetStatus, pIndex++ );
+ rc = put_user(i2Input, pIndex++ );
+ rc = put_user(i2InputFlush, pIndex++ );
+ rc = put_user(i2Output, pIndex++ );
+ rc = put_user(i2FlushOutput, pIndex++ );
+ rc = put_user(i2DrainWakeup, pIndex++ );
+ rc = put_user(i2DrainOutput, pIndex++ );
+ rc = put_user(i2OutputFree, pIndex++ );
+ rc = put_user(i2StripFifo, pIndex++ );
+ rc = put_user(i2StuffFifoBypass, pIndex++ );
+ rc = put_user(i2StuffFifoFlow, pIndex++ );
+ rc = put_user(i2StuffFifoInline, pIndex++ );
+ rc = put_user(i2ServiceBoard, pIndex++ );
+ rc = put_user(serviceOutgoingFifo, pIndex++ );
+ // rc = put_user(ip2_init, pIndex++ );
+ rc = put_user(ip2_init_board, pIndex++ );
+ rc = put_user(find_eisa_board, pIndex++ );
+ rc = put_user(set_irq, pIndex++ );
+ rc = put_user(ip2_interrupt, pIndex++ );
+ rc = put_user(ip2_poll, pIndex++ );
+ rc = put_user(service_all_boards, pIndex++ );
+ rc = put_user(do_input, pIndex++ );
+ rc = put_user(do_status, pIndex++ );
#ifndef IP2DEBUG_OPEN
- PUT_USER(rc, 0, pIndex++ );
+ rc = put_user(0, pIndex++ );
#else
- PUT_USER(rc, open_sanity_check, pIndex++ );
+ rc = put_user(open_sanity_check, pIndex++ );
#endif
- PUT_USER(rc, ip2_open, pIndex++ );
- PUT_USER(rc, ip2_close, pIndex++ );
- PUT_USER(rc, ip2_hangup, pIndex++ );
- PUT_USER(rc, ip2_write, pIndex++ );
- PUT_USER(rc, ip2_putchar, pIndex++ );
- PUT_USER(rc, ip2_flush_chars, pIndex++ );
- PUT_USER(rc, ip2_write_room, pIndex++ );
- PUT_USER(rc, ip2_chars_in_buf, pIndex++ );
- PUT_USER(rc, ip2_flush_buffer, pIndex++ );
-
- //PUT_USER(rc, ip2_wait_until_sent, pIndex++ );
- PUT_USER(rc, 0, pIndex++ );
-
- PUT_USER(rc, ip2_throttle, pIndex++ );
- PUT_USER(rc, ip2_unthrottle, pIndex++ );
- PUT_USER(rc, ip2_ioctl, pIndex++ );
- PUT_USER(rc, set_modem_info, pIndex++ );
- PUT_USER(rc, get_serial_info, pIndex++ );
- PUT_USER(rc, set_serial_info, pIndex++ );
- PUT_USER(rc, ip2_set_termios, pIndex++ );
- PUT_USER(rc, ip2_set_line_discipline, pIndex++ );
- PUT_USER(rc, set_params, pIndex++ );
+ rc = put_user(ip2_open, pIndex++ );
+ rc = put_user(ip2_close, pIndex++ );
+ rc = put_user(ip2_hangup, pIndex++ );
+ rc = put_user(ip2_write, pIndex++ );
+ rc = put_user(ip2_putchar, pIndex++ );
+ rc = put_user(ip2_flush_chars, pIndex++ );
+ rc = put_user(ip2_write_room, pIndex++ );
+ rc = put_user(ip2_chars_in_buf, pIndex++ );
+ rc = put_user(ip2_flush_buffer, pIndex++ );
+
+ //rc = put_user(ip2_wait_until_sent, pIndex++ );
+ rc = put_user(0, pIndex++ );
+
+ rc = put_user(ip2_throttle, pIndex++ );
+ rc = put_user(ip2_unthrottle, pIndex++ );
+ rc = put_user(ip2_ioctl, pIndex++ );
+ rc = put_user(set_modem_info, pIndex++ );
+ rc = put_user(get_serial_info, pIndex++ );
+ rc = put_user(set_serial_info, pIndex++ );
+ rc = put_user(ip2_set_termios, pIndex++ );
+ rc = put_user(ip2_set_line_discipline, pIndex++ );
+ rc = put_user(set_params, pIndex++ );
} else {
rc = -EINVAL;
}
diff --git a/drivers/char/watchdog/acquirewdt.c b/drivers/char/watchdog/acquirewdt.c
index 6c2645234deb..deba2eb4e8c5 100644
--- a/drivers/char/watchdog/acquirewdt.c
+++ b/drivers/char/watchdog/acquirewdt.c
@@ -143,7 +143,7 @@ static int acq_open(struct inode *inode, struct file *file)
return -EBUSY;
}
if (nowayout)
- MOD_INC_USE_COUNT;
+ __module_get(THIS_MODULE);
/* Activate */
acq_is_open=1;
diff --git a/drivers/char/watchdog/i810-tco.c b/drivers/char/watchdog/i810-tco.c
index 594b52a993b4..39b816e66912 100644
--- a/drivers/char/watchdog/i810-tco.c
+++ b/drivers/char/watchdog/i810-tco.c
@@ -25,7 +25,8 @@
* 82801AA & 82801AB chip : document number 290655-003, 290677-004,
* 82801BA & 82801BAM chip : document number 290687-002, 298242-005,
* 82801CA & 82801CAM chip : document number 290716-001, 290718-001,
- * 82801DB & 82801E chip : document number 290744-001, 273599-001
+ * 82801DB & 82801E chip : document number 290744-001, 273599-001,
+ * 82801EB & 82801ER chip : document number 252516-001
*
* 20000710 Nils Faerber
* Initial Version 0.01
@@ -42,9 +43,11 @@
* clean up ioctls (WDIOC_GETSTATUS, WDIOC_GETBOOTSTATUS and
* WDIOC_SETOPTIONS), made i810tco_getdevice __init,
* removed boot_status, removed tco_timer_read,
- * added support for 82801DB and 82801E chipset, general cleanup.
+ * added support for 82801DB and 82801E chipset,
+ * added support for 82801EB and 8280ER chipset,
+ * general cleanup.
*/
-
+
#include <linux/module.h>
#include <linux/types.h>
#include <linux/miscdevice.h>
@@ -164,7 +167,7 @@ static int tco_timer_settimer (unsigned char tmrval)
* Reload (trigger) the timer. Lock is needed so we don't reload it during
* a reprogramming event
*/
-
+
static void tco_timer_reload (void)
{
spin_lock(&tco_lock);
@@ -307,6 +310,7 @@ static struct pci_device_id i810tco_pci_tbl[] __initdata = {
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, PCI_ANY_ID, PCI_ANY_ID, },
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, PCI_ANY_ID, PCI_ANY_ID, },
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801E_0, PCI_ANY_ID, PCI_ANY_ID, },
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, PCI_ANY_ID, PCI_ANY_ID, },
{ 0, },
};
MODULE_DEVICE_TABLE (pci, i810tco_pci_tbl);
diff --git a/drivers/char/watchdog/i810-tco.h b/drivers/char/watchdog/i810-tco.h
index cfc2efaf8e0a..8b454246f4fe 100644
--- a/drivers/char/watchdog/i810-tco.h
+++ b/drivers/char/watchdog/i810-tco.h
@@ -1,5 +1,5 @@
/*
- * i810-tco 0.05: TCO timer driver for i8xx chipsets
+ * i810-tco: TCO timer driver for i8xx chipsets
*
* (c) Copyright 2000 kernel concepts <nils@kernelconcepts.de>, All Rights Reserved.
* http://www.kernelconcepts.de
@@ -8,7 +8,7 @@
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
- *
+ *
* Neither kernel concepts nor Nils Faerber admit liability nor provide
* warranty for any of this software. This material is provided
* "AS-IS" and at no charge.
diff --git a/drivers/char/watchdog/ib700wdt.c b/drivers/char/watchdog/ib700wdt.c
index b2dff14b933c..700e91d5a857 100644
--- a/drivers/char/watchdog/ib700wdt.c
+++ b/drivers/char/watchdog/ib700wdt.c
@@ -230,7 +230,7 @@ ibwdt_open(struct inode *inode, struct file *file)
return -EBUSY;
}
if (nowayout)
- MOD_INC_USE_COUNT;
+ __module_get(THIS_MODULE);
/* Activate */
ibwdt_is_open = 1;
diff --git a/drivers/char/watchdog/indydog.c b/drivers/char/watchdog/indydog.c
index a32d63eda00b..206ce9683aa2 100644
--- a/drivers/char/watchdog/indydog.c
+++ b/drivers/char/watchdog/indydog.c
@@ -54,7 +54,7 @@ static int indydog_open(struct inode *inode, struct file *file)
return -EBUSY;
if (nowayout)
- MOD_INC_USE_COUNT;
+ __module_get(THIS_MODULE);
/*
* Activate timer
diff --git a/drivers/char/watchdog/machzwd.c b/drivers/char/watchdog/machzwd.c
index 760cdcfd577e..56ccf444c66c 100644
--- a/drivers/char/watchdog/machzwd.c
+++ b/drivers/char/watchdog/machzwd.c
@@ -392,7 +392,7 @@ static int zf_open(struct inode *inode, struct file *file)
}
if (nowayout)
- MOD_INC_USE_COUNT;
+ __module_get(THIS_MODULE);
zf_is_open = 1;
diff --git a/drivers/char/watchdog/pcwd.c b/drivers/char/watchdog/pcwd.c
index 320d2d2e1dae..16a317ab23f4 100644
--- a/drivers/char/watchdog/pcwd.c
+++ b/drivers/char/watchdog/pcwd.c
@@ -431,7 +431,7 @@ static int pcwd_open(struct inode *ino, struct file *filep)
atomic_inc( &open_allowed );
return -EBUSY;
}
- MOD_INC_USE_COUNT;
+ __module_get(THIS_MODULE);
/* Enable the port */
if (revision == PCWD_REVISION_C) {
spin_lock(&io_lock);
diff --git a/drivers/char/watchdog/sbc60xxwdt.c b/drivers/char/watchdog/sbc60xxwdt.c
index 5ec91fc95ba7..03e2de743e4a 100644
--- a/drivers/char/watchdog/sbc60xxwdt.c
+++ b/drivers/char/watchdog/sbc60xxwdt.c
@@ -207,9 +207,8 @@ static int fop_open(struct inode * inode, struct file * file)
/* Just in case we're already talking to someone... */
if(wdt_is_open)
return -EBUSY;
- if (nowayout) {
- MOD_INC_USE_COUNT;
- }
+ if (nowayout)
+ __module_get(THIS_MODULE);
/* Good, fire up the show */
wdt_is_open = 1;
wdt_startup();
diff --git a/drivers/char/watchdog/sc520_wdt.c b/drivers/char/watchdog/sc520_wdt.c
index 0555022203ea..6588265427e5 100644
--- a/drivers/char/watchdog/sc520_wdt.c
+++ b/drivers/char/watchdog/sc520_wdt.c
@@ -231,7 +231,7 @@ static int fop_open(struct inode * inode, struct file * file)
/* Good, fire up the show */
wdt_startup();
if (nowayout)
- MOD_INC_USE_COUNT;
+ __module_get(THIS_MODULE);
return 0;
default:
diff --git a/drivers/char/watchdog/shwdt.c b/drivers/char/watchdog/shwdt.c
index db55b6ab37e1..2bcbeb6f9fd9 100644
--- a/drivers/char/watchdog/shwdt.c
+++ b/drivers/char/watchdog/shwdt.c
@@ -175,7 +175,7 @@ static int sh_wdt_open(struct inode *inode, struct file *file)
if (test_and_set_bit(0, &shwdt_is_open))
return -EBUSY;
if (nowayout)
- MOD_INC_USE_COUNT;
+ __module_get(THIS_MODULE);
sh_wdt_start();
diff --git a/drivers/char/watchdog/softdog.c b/drivers/char/watchdog/softdog.c
index 8e899839ecf9..0c43f23b61f6 100644
--- a/drivers/char/watchdog/softdog.c
+++ b/drivers/char/watchdog/softdog.c
@@ -104,9 +104,8 @@ static int softdog_open(struct inode *inode, struct file *file)
{
if(test_and_set_bit(0, &timer_alive))
return -EBUSY;
- if (nowayout) {
- MOD_INC_USE_COUNT;
- }
+ if (nowayout)
+ __module_get(THIS_MODULE);
/*
* Activate timer
*/
diff --git a/drivers/char/watchdog/wdt977.c b/drivers/char/watchdog/wdt977.c
index 80a4a7daebb6..fe58b5ff1d8e 100644
--- a/drivers/char/watchdog/wdt977.c
+++ b/drivers/char/watchdog/wdt977.c
@@ -99,7 +99,7 @@ static int wdt977_open(struct inode *inode, struct file *file)
if (nowayout)
{
- MOD_INC_USE_COUNT;
+ __module_get(THIS_MODULE);
/* do not permit disabling the watchdog by writing 0 to reg. 0xF2 */
if (!timeoutM) timeoutM = DEFAULT_TIMEOUT;
diff --git a/drivers/char/watchdog/wdt_pci.c b/drivers/char/watchdog/wdt_pci.c
index 98a1b4fcaac1..e1e539f5ef20 100644
--- a/drivers/char/watchdog/wdt_pci.c
+++ b/drivers/char/watchdog/wdt_pci.c
@@ -367,7 +367,7 @@ static int wdtpci_open(struct inode *inode, struct file *file)
return -EBUSY;
if (nowayout) {
- MOD_INC_USE_COUNT;
+ __module_get(THIS_MODULE);
}
/*
* Activate
diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig
index 62e6b6b5dcc6..fe78e5d2f196 100644
--- a/drivers/ide/Kconfig
+++ b/drivers/ide/Kconfig
@@ -521,7 +521,7 @@ config BLK_DEV_ALI15X3
If you say Y here, you also need to say Y to "Use DMA by default
when available", above. Please read the comments at the top of
- <file:drivers/ide/alim15x3.c>.
+ <file:drivers/ide/pci/alim15x3.c>.
If unsure, say N.
@@ -608,7 +608,7 @@ config HPT34X_AUTODMA
depends on BLK_DEV_HPT34X && IDEDMA_PCI_WIP
help
This is a dangerous thing to attempt currently! Please read the
- comments at the top of <file:drivers/ide/hpt34x.c>. If you say Y
+ comments at the top of <file:drivers/ide/pci/hpt34x.c>. If you say Y
here, then say Y to "Use DMA by default when available" as well.
If unsure, say N.
@@ -670,14 +670,14 @@ config BLK_DEV_NS87415
This driver adds detection and support for the NS87415 chip
(used in SPARC64, among others).
- Please read the comments at the top of <file:drivers/ide/ns87415.c>.
+ Please read the comments at the top of <file:drivers/ide/pci/ns87415.c>.
config BLK_DEV_OPTI621
tristate "OPTi 82C621 chipset enhanced support (EXPERIMENTAL)"
depends on PCI && BLK_DEV_IDEPCI && EXPERIMENTAL
help
This is a driver for the OPTi 82C621 EIDE controller.
- Please read the comments at the top of <file:drivers/ide/opti621.c>.
+ Please read the comments at the top of <file:drivers/ide/pci/opti621.c>.
config BLK_DEV_PDC202XX_OLD
tristate "PROMISE PDC202{46|62|65|67} support"
@@ -696,7 +696,7 @@ config PDC202XX_BURST
when the PDC20265 BIOS has been disabled (for faster boot up).
Please read the comments at the top of
- <file:drivers/ide/pdc202xx.c>.
+ <file:drivers/ide/pci/pdc202xx_old.c>.
If unsure, say N.
@@ -754,7 +754,7 @@ config BLK_DEV_SIS5513
If you say Y here, you need to say Y to "Use DMA by default when
available" as well.
- Please read the comments at the top of <file:drivers/ide/sis5513.c>.
+ Please read the comments at the top of <file:drivers/ide/pci/sis5513.c>.
config BLK_DEV_SLC90E66
tristate "SLC90E66 chipset support"
@@ -770,7 +770,7 @@ config BLK_DEV_SLC90E66
available" as well.
Please read the comments at the top of
- drivers/ide/slc90e66.c.
+ drivers/ide/pci/slc90e66.c.
config BLK_DEV_TRM290
tristate "Tekram TRM290 chipset support"
@@ -779,7 +779,7 @@ config BLK_DEV_TRM290
This driver adds support for bus master DMA transfers
using the Tekram TRM290 PCI IDE chip. Volunteers are
needed for further tweaking and development.
- Please read the comments at the top of <file:drivers/ide/trm290.c>.
+ Please read the comments at the top of <file:drivers/ide/pci/trm290.c>.
config BLK_DEV_VIA82CXXX
tristate "VIA82CXXX chipset support"
@@ -1010,7 +1010,7 @@ config BLK_DEV_ALI14XX
boot parameter. It enables support for the secondary IDE interface
of the ALI M1439/1443/1445/1487/1489 chipsets, and permits faster
I/O speeds to be set as well. See the files
- <file:Documentation/ide.txt> and <file:drivers/ide/ali14xx.c> for
+ <file:Documentation/ide.txt> and <file:drivers/ide/legacy/ali14xx.c> for
more info.
config BLK_DEV_DTC2278
@@ -1021,7 +1021,7 @@ config BLK_DEV_DTC2278
boot parameter. It enables support for the secondary IDE interface
of the DTC-2278 card, and permits faster I/O speeds to be set as
well. See the <file:Documentation/ide.txt> and
- <file:drivers/ide/dtc2278.c> files for more info.
+ <file:drivers/ide/legacy/dtc2278.c> files for more info.
config BLK_DEV_HT6560B
tristate "Holtek HT6560B support"
@@ -1031,7 +1031,7 @@ config BLK_DEV_HT6560B
boot parameter. It enables support for the secondary IDE interface
of the Holtek card, and permits faster I/O speeds to be set as well.
See the <file:Documentation/ide.txt> and
- <file:drivers/ide/ht6560b.c> files for more info.
+ <file:drivers/ide/legacy/ht6560b.c> files for more info.
config BLK_DEV_PDC4030
tristate "PROMISE DC4030 support (EXPERIMENTAL)"
@@ -1044,7 +1044,7 @@ config BLK_DEV_PDC4030
supported (and probably never will be since I don't think the cards
support them). This driver is enabled at runtime using the "ide0=dc4030"
or "ide1=dc4030" kernel boot parameter. See the
- <file:drivers/ide/pdc4030.c> file for more info.
+ <file:drivers/ide/legacy/pdc4030.c> file for more info.
config BLK_DEV_QD65XX
tristate "QDI QD65xx support"
@@ -1052,7 +1052,7 @@ config BLK_DEV_QD65XX
help
This driver is enabled at runtime using the "ide0=qd65xx" kernel
boot parameter. It permits faster I/O speeds to be set. See the
- <file:Documentation/ide.txt> and <file:drivers/ide/qd65xx.c> for
+ <file:Documentation/ide.txt> and <file:drivers/ide/legacy/qd65xx.c> for
more info.
config BLK_DEV_UMC8672
@@ -1063,7 +1063,7 @@ config BLK_DEV_UMC8672
boot parameter. It enables support for the secondary IDE interface
of the UMC-8672, and permits faster I/O speeds to be set as well.
See the files <file:Documentation/ide.txt> and
- <file:drivers/ide/umc8672.c> for more info.
+ <file:drivers/ide/legacy/umc8672.c> for more info.
config BLK_DEV_HD_ONLY
bool "Old hard disk (MFM/RLL/IDE) driver"
@@ -1132,7 +1132,7 @@ config BLK_DEV_PDC202XX
available" as well.
Please read the comments at the top of
- <file:drivers/ide/pdc202xx.c>.
+ <file:drivers/ide/pdc202xx_old.c>.
If unsure, say N.
diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig
index c3aca579563c..afcd1a4549f0 100644
--- a/drivers/md/Kconfig
+++ b/drivers/md/Kconfig
@@ -145,5 +145,12 @@ config BLK_DEV_DM
If unsure, say N.
+config DM_IOCTL_V4
+ bool "ioctl interface version 4"
+ depends on BLK_DEV_DM
+ ---help---
+ Recent tools use a new version of the ioctl interface, only
+ select this option if you intend using such tools.
+
endmenu
diff --git a/drivers/md/dm-ioctl-v1.c b/drivers/md/dm-ioctl-v1.c
new file mode 100644
index 000000000000..19cea7db179f
--- /dev/null
+++ b/drivers/md/dm-ioctl-v1.c
@@ -0,0 +1,1160 @@
+/*
+ * Copyright (C) 2001, 2002 Sistina Software (UK) Limited.
+ *
+ * This file is released under the GPL.
+ */
+
+#include "dm.h"
+
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+#include <linux/miscdevice.h>
+#include <linux/dm-ioctl.h>
+#include <linux/init.h>
+#include <linux/wait.h>
+#include <linux/blk.h>
+#include <linux/slab.h>
+#include <linux/devfs_fs_kernel.h>
+
+#include <asm/uaccess.h>
+
+#define DM_DRIVER_EMAIL "dm@uk.sistina.com"
+
+/*-----------------------------------------------------------------
+ * The ioctl interface needs to be able to look up devices by
+ * name or uuid.
+ *---------------------------------------------------------------*/
+struct hash_cell {
+ struct list_head name_list;
+ struct list_head uuid_list;
+
+ char *name;
+ char *uuid;
+ struct mapped_device *md;
+};
+
+#define NUM_BUCKETS 64
+#define MASK_BUCKETS (NUM_BUCKETS - 1)
+static struct list_head _name_buckets[NUM_BUCKETS];
+static struct list_head _uuid_buckets[NUM_BUCKETS];
+
+void dm_hash_remove_all(void);
+
+/*
+ * Guards access to all three tables.
+ */
+static DECLARE_RWSEM(_hash_lock);
+
+static void init_buckets(struct list_head *buckets)
+{
+ unsigned int i;
+
+ for (i = 0; i < NUM_BUCKETS; i++)
+ INIT_LIST_HEAD(buckets + i);
+}
+
+int dm_hash_init(void)
+{
+ init_buckets(_name_buckets);
+ init_buckets(_uuid_buckets);
+ devfs_mk_dir(DM_DIR);
+ return 0;
+}
+
+void dm_hash_exit(void)
+{
+ dm_hash_remove_all();
+ devfs_remove(DM_DIR);
+}
+
+/*-----------------------------------------------------------------
+ * Hash function:
+ * We're not really concerned with the str hash function being
+ * fast since it's only used by the ioctl interface.
+ *---------------------------------------------------------------*/
+static unsigned int hash_str(const char *str)
+{
+ const unsigned int hash_mult = 2654435387U;
+ unsigned int h = 0;
+
+ while (*str)
+ h = (h + (unsigned int) *str++) * hash_mult;
+
+ return h & MASK_BUCKETS;
+}
+
+/*-----------------------------------------------------------------
+ * Code for looking up a device by name
+ *---------------------------------------------------------------*/
+static struct hash_cell *__get_name_cell(const char *str)
+{
+ struct list_head *tmp;
+ struct hash_cell *hc;
+ unsigned int h = hash_str(str);
+
+ list_for_each (tmp, _name_buckets + h) {
+ hc = list_entry(tmp, struct hash_cell, name_list);
+ if (!strcmp(hc->name, str))
+ return hc;
+ }
+
+ return NULL;
+}
+
+static struct hash_cell *__get_uuid_cell(const char *str)
+{
+ struct list_head *tmp;
+ struct hash_cell *hc;
+ unsigned int h = hash_str(str);
+
+ list_for_each (tmp, _uuid_buckets + h) {
+ hc = list_entry(tmp, struct hash_cell, uuid_list);
+ if (!strcmp(hc->uuid, str))
+ return hc;
+ }
+
+ return NULL;
+}
+
+/*-----------------------------------------------------------------
+ * Inserting, removing and renaming a device.
+ *---------------------------------------------------------------*/
+static inline char *kstrdup(const char *str)
+{
+ char *r = kmalloc(strlen(str) + 1, GFP_KERNEL);
+ if (r)
+ strcpy(r, str);
+ return r;
+}
+
+static struct hash_cell *alloc_cell(const char *name, const char *uuid,
+ struct mapped_device *md)
+{
+ struct hash_cell *hc;
+
+ hc = kmalloc(sizeof(*hc), GFP_KERNEL);
+ if (!hc)
+ return NULL;
+
+ hc->name = kstrdup(name);
+ if (!hc->name) {
+ kfree(hc);
+ return NULL;
+ }
+
+ if (!uuid)
+ hc->uuid = NULL;
+
+ else {
+ hc->uuid = kstrdup(uuid);
+ if (!hc->uuid) {
+ kfree(hc->name);
+ kfree(hc);
+ return NULL;
+ }
+ }
+
+ INIT_LIST_HEAD(&hc->name_list);
+ INIT_LIST_HEAD(&hc->uuid_list);
+ hc->md = md;
+ return hc;
+}
+
+static void free_cell(struct hash_cell *hc)
+{
+ if (hc) {
+ kfree(hc->name);
+ kfree(hc->uuid);
+ kfree(hc);
+ }
+}
+
+/*
+ * devfs stuff.
+ */
+static int register_with_devfs(struct hash_cell *hc)
+{
+ struct gendisk *disk = dm_disk(hc->md);
+
+ devfs_mk_bdev(MKDEV(disk->major, disk->first_minor),
+ S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP,
+ DM_DIR "/%s", hc->name);
+ return 0;
+}
+
+static int unregister_with_devfs(struct hash_cell *hc)
+{
+ devfs_remove(DM_DIR"/%s", hc->name);
+ return 0;
+}
+
+/*
+ * The kdev_t and uuid of a device can never change once it is
+ * initially inserted.
+ */
+int dm_hash_insert(const char *name, const char *uuid, struct mapped_device *md)
+{
+ struct hash_cell *cell;
+
+ /*
+ * Allocate the new cells.
+ */
+ cell = alloc_cell(name, uuid, md);
+ if (!cell)
+ return -ENOMEM;
+
+ /*
+ * Insert the cell into all three hash tables.
+ */
+ down_write(&_hash_lock);
+ if (__get_name_cell(name))
+ goto bad;
+
+ list_add(&cell->name_list, _name_buckets + hash_str(name));
+
+ if (uuid) {
+ if (__get_uuid_cell(uuid)) {
+ list_del(&cell->name_list);
+ goto bad;
+ }
+ list_add(&cell->uuid_list, _uuid_buckets + hash_str(uuid));
+ }
+ register_with_devfs(cell);
+ dm_get(md);
+ up_write(&_hash_lock);
+
+ return 0;
+
+ bad:
+ up_write(&_hash_lock);
+ free_cell(cell);
+ return -EBUSY;
+}
+
+void __hash_remove(struct hash_cell *hc)
+{
+ /* remove from the dev hash */
+ list_del(&hc->uuid_list);
+ list_del(&hc->name_list);
+ unregister_with_devfs(hc);
+ dm_put(hc->md);
+ free_cell(hc);
+}
+
+void dm_hash_remove_all(void)
+{
+ int i;
+ struct hash_cell *hc;
+ struct list_head *tmp, *n;
+
+ down_write(&_hash_lock);
+ for (i = 0; i < NUM_BUCKETS; i++) {
+ list_for_each_safe (tmp, n, _name_buckets + i) {
+ hc = list_entry(tmp, struct hash_cell, name_list);
+ __hash_remove(hc);
+ }
+ }
+ up_write(&_hash_lock);
+}
+
+int dm_hash_rename(const char *old, const char *new)
+{
+ char *new_name, *old_name;
+ struct hash_cell *hc;
+
+ /*
+ * duplicate new.
+ */
+ new_name = kstrdup(new);
+ if (!new_name)
+ return -ENOMEM;
+
+ down_write(&_hash_lock);
+
+ /*
+ * Is new free ?
+ */
+ hc = __get_name_cell(new);
+ if (hc) {
+ DMWARN("asked to rename to an already existing name %s -> %s",
+ old, new);
+ up_write(&_hash_lock);
+ kfree(new_name);
+ return -EBUSY;
+ }
+
+ /*
+ * Is there such a device as 'old' ?
+ */
+ hc = __get_name_cell(old);
+ if (!hc) {
+ DMWARN("asked to rename a non existent device %s -> %s",
+ old, new);
+ up_write(&_hash_lock);
+ kfree(new_name);
+ return -ENXIO;
+ }
+
+ /*
+ * rename and move the name cell.
+ */
+ unregister_with_devfs(hc);
+
+ list_del(&hc->name_list);
+ old_name = hc->name;
+ hc->name = new_name;
+ list_add(&hc->name_list, _name_buckets + hash_str(new_name));
+
+ /* rename the device node in devfs */
+ register_with_devfs(hc);
+
+ up_write(&_hash_lock);
+ kfree(old_name);
+ return 0;
+}
+
+
+/*-----------------------------------------------------------------
+ * Implementation of the ioctl commands
+ *---------------------------------------------------------------*/
+
+/*
+ * All the ioctl commands get dispatched to functions with this
+ * prototype.
+ */
+typedef int (*ioctl_fn)(struct dm_ioctl *param, struct dm_ioctl *user);
+
+/*
+ * Check a string doesn't overrun the chunk of
+ * memory we copied from userland.
+ */
+static int valid_str(char *str, void *begin, void *end)
+{
+ while (((void *) str >= begin) && ((void *) str < end))
+ if (!*str++)
+ return 0;
+
+ return -EINVAL;
+}
+
+static int next_target(struct dm_target_spec *last, uint32_t next,
+ void *begin, void *end,
+ struct dm_target_spec **spec, char **params)
+{
+ *spec = (struct dm_target_spec *)
+ ((unsigned char *) last + next);
+ *params = (char *) (*spec + 1);
+
+ if (*spec < (last + 1) || ((void *) *spec > end))
+ return -EINVAL;
+
+ return valid_str(*params, begin, end);
+}
+
+static int populate_table(struct dm_table *table, struct dm_ioctl *args)
+{
+ int r, first = 1;
+ unsigned int i = 0;
+ struct dm_target_spec *spec;
+ char *params;
+ void *begin, *end;
+
+ if (!args->target_count) {
+ DMWARN("populate_table: no targets specified");
+ return -EINVAL;
+ }
+
+ begin = (void *) args;
+ end = begin + args->data_size;
+
+ for (i = 0; i < args->target_count; i++) {
+
+ if (first)
+ r = next_target((struct dm_target_spec *) args,
+ args->data_start,
+ begin, end, &spec, &params);
+ else
+ r = next_target(spec, spec->next, begin, end,
+ &spec, &params);
+
+ if (r) {
+ DMWARN("unable to find target");
+ return -EINVAL;
+ }
+
+ r = dm_table_add_target(table, spec->target_type,
+ (sector_t) spec->sector_start,
+ (sector_t) spec->length,
+ params);
+ if (r) {
+ DMWARN("internal error adding target to table");
+ return -EINVAL;
+ }
+
+ first = 0;
+ }
+
+ return dm_table_complete(table);
+}
+
+/*
+ * Round up the ptr to the next 'align' boundary. Obviously
+ * 'align' must be a power of 2.
+ */
+static inline void *align_ptr(void *ptr, unsigned int align)
+{
+ align--;
+ return (void *) (((unsigned long) (ptr + align)) & ~align);
+}
+
+/*
+ * Copies a dm_ioctl and an optional additional payload to
+ * userland.
+ */
+static int results_to_user(struct dm_ioctl *user, struct dm_ioctl *param,
+ void *data, uint32_t len)
+{
+ int r;
+ void *ptr = NULL;
+
+ if (data) {
+ ptr = align_ptr(user + 1, sizeof(unsigned long));
+ param->data_start = ptr - (void *) user;
+ }
+
+ /*
+ * The version number has already been filled in, so we
+ * just copy later fields.
+ */
+ r = copy_to_user(&user->data_size, &param->data_size,
+ sizeof(*param) - sizeof(param->version));
+ if (r)
+ return -EFAULT;
+
+ if (data) {
+ if (param->data_start + len > param->data_size)
+ return -ENOSPC;
+
+ if (copy_to_user(ptr, data, len))
+ r = -EFAULT;
+ }
+
+ return r;
+}
+
+/*
+ * Fills in a dm_ioctl structure, ready for sending back to
+ * userland.
+ */
+static int __info(struct mapped_device *md, struct dm_ioctl *param)
+{
+ struct dm_table *table;
+ struct block_device *bdev;
+ struct gendisk *disk = dm_disk(md);
+
+ param->flags = DM_EXISTS_FLAG;
+ if (dm_suspended(md))
+ param->flags |= DM_SUSPEND_FLAG;
+
+ bdev = bdget_disk(disk, 0);
+ if (!bdev)
+ return -ENXIO;
+
+ param->dev = bdev->bd_dev;
+ param->open_count = bdev->bd_openers;
+ bdput(bdev);
+
+ if (disk->policy)
+ param->flags |= DM_READONLY_FLAG;
+
+ table = dm_get_table(md);
+ param->target_count = dm_table_get_num_targets(table);
+ dm_table_put(table);
+
+ return 0;
+}
+
+/*
+ * Always use UUID for lookups if it's present, otherwise use name.
+ */
+static inline struct mapped_device *find_device(struct dm_ioctl *param)
+{
+ struct hash_cell *hc;
+ struct mapped_device *md = NULL;
+
+ down_read(&_hash_lock);
+ hc = *param->uuid ? __get_uuid_cell(param->uuid) :
+ __get_name_cell(param->name);
+ if (hc) {
+ md = hc->md;
+
+ /*
+ * Sneakily write in both the name and the uuid
+ * while we have the cell.
+ */
+ strlcpy(param->name, hc->name, sizeof(param->name));
+ if (hc->uuid)
+ strlcpy(param->uuid, hc->uuid, sizeof(param->uuid));
+ else
+ param->uuid[0] = '\0';
+
+ dm_get(md);
+ }
+ up_read(&_hash_lock);
+
+ return md;
+}
+
+#define ALIGNMENT sizeof(int)
+static void *_align(void *ptr, unsigned int a)
+{
+ register unsigned long align = --a;
+
+ return (void *) (((unsigned long) ptr + align) & ~align);
+}
+
+/*
+ * Copies device info back to user space, used by
+ * the create and info ioctls.
+ */
+static int info(struct dm_ioctl *param, struct dm_ioctl *user)
+{
+ struct mapped_device *md;
+
+ param->flags = 0;
+
+ md = find_device(param);
+ if (!md)
+ /*
+ * Device not found - returns cleared exists flag.
+ */
+ goto out;
+
+ __info(md, param);
+ dm_put(md);
+
+ out:
+ return results_to_user(user, param, NULL, 0);
+}
+
+static inline int get_mode(struct dm_ioctl *param)
+{
+ int mode = FMODE_READ | FMODE_WRITE;
+
+ if (param->flags & DM_READONLY_FLAG)
+ mode = FMODE_READ;
+
+ return mode;
+}
+
+static int check_name(const char *name)
+{
+ if (name[0] == '/') {
+ DMWARN("invalid device name");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int create(struct dm_ioctl *param, struct dm_ioctl *user)
+{
+ int r;
+ struct dm_table *t;
+ struct mapped_device *md;
+
+ r = check_name(param->name);
+ if (r)
+ return r;
+
+ r = dm_table_create(&t, get_mode(param));
+ if (r)
+ return r;
+
+ r = populate_table(t, param);
+ if (r) {
+ dm_table_put(t);
+ return r;
+ }
+
+ if (param->flags & DM_PERSISTENT_DEV_FLAG)
+ r = dm_create_with_minor(minor(to_kdev_t(param->dev)), &md);
+ else
+ r = dm_create(&md);
+
+ if (r) {
+ dm_table_put(t);
+ return r;
+ }
+
+ /* suspend the device */
+ r = dm_suspend(md);
+ if (r) {
+ DMWARN("suspend failed");
+ dm_table_put(t);
+ dm_put(md);
+ return r;
+ }
+ /* swap in the table */
+ r = dm_swap_table(md, t);
+ if (r) {
+ DMWARN("table swap failed");
+ dm_table_put(t);
+ dm_put(md);
+ return r;
+ }
+
+ /* resume the device */
+ r = dm_resume(md);
+ if (r) {
+ DMWARN("resume failed");
+ dm_table_put(t);
+ dm_put(md);
+ return r;
+ }
+
+ dm_table_put(t); /* md will have grabbed its own reference */
+
+ set_disk_ro(dm_disk(md), (param->flags & DM_READONLY_FLAG) ? 1 : 0);
+ r = dm_hash_insert(param->name, *param->uuid ? param->uuid : NULL, md);
+ dm_put(md);
+
+ return r ? r : info(param, user);
+}
+
+/*
+ * Build up the status struct for each target
+ */
+static int __status(struct mapped_device *md, struct dm_ioctl *param,
+ char *outbuf, size_t *len)
+{
+ unsigned int i, num_targets;
+ struct dm_target_spec *spec;
+ char *outptr;
+ status_type_t type;
+ struct dm_table *table = dm_get_table(md);
+
+ if (param->flags & DM_STATUS_TABLE_FLAG)
+ type = STATUSTYPE_TABLE;
+ else
+ type = STATUSTYPE_INFO;
+
+ outptr = outbuf;
+
+ /* Get all the target info */
+ num_targets = dm_table_get_num_targets(table);
+ for (i = 0; i < num_targets; i++) {
+ struct dm_target *ti = dm_table_get_target(table, i);
+
+ if (outptr - outbuf +
+ sizeof(struct dm_target_spec) > param->data_size) {
+ dm_table_put(table);
+ return -ENOMEM;
+ }
+
+ spec = (struct dm_target_spec *) outptr;
+
+ spec->status = 0;
+ spec->sector_start = ti->begin;
+ spec->length = ti->len;
+ strlcpy(spec->target_type, ti->type->name,
+ sizeof(spec->target_type));
+
+ outptr += sizeof(struct dm_target_spec);
+
+ /* Get the status/table string from the target driver */
+ if (ti->type->status)
+ ti->type->status(ti, type, outptr,
+ outbuf + param->data_size - outptr);
+ else
+ outptr[0] = '\0';
+
+ outptr += strlen(outptr) + 1;
+ _align(outptr, ALIGNMENT);
+ spec->next = outptr - outbuf;
+ }
+
+ param->target_count = num_targets;
+ *len = outptr - outbuf;
+ dm_table_put(table);
+
+ return 0;
+}
+
+/*
+ * Return the status of a device as a text string for each
+ * target.
+ */
+static int get_status(struct dm_ioctl *param, struct dm_ioctl *user)
+{
+ struct mapped_device *md;
+ size_t len = 0;
+ int ret;
+ char *outbuf = NULL;
+
+ md = find_device(param);
+ if (!md)
+ /*
+ * Device not found - returns cleared exists flag.
+ */
+ goto out;
+
+ /* We haven't a clue how long the resultant data will be so
+ just allocate as much as userland has allowed us and make sure
+ we don't overun it */
+ outbuf = kmalloc(param->data_size, GFP_KERNEL);
+ if (!outbuf)
+ goto out;
+ /*
+ * Get the status of all targets
+ */
+ __status(md, param, outbuf, &len);
+
+ /*
+ * Setup the basic dm_ioctl structure.
+ */
+ __info(md, param);
+
+ out:
+ if (md)
+ dm_put(md);
+
+ ret = results_to_user(user, param, outbuf, len);
+
+ if (outbuf)
+ kfree(outbuf);
+
+ return ret;
+}
+
+/*
+ * Wait for a device to report an event
+ */
+static int wait_device_event(struct dm_ioctl *param, struct dm_ioctl *user)
+{
+ struct mapped_device *md;
+ DECLARE_WAITQUEUE(wq, current);
+
+ md = find_device(param);
+ if (!md)
+ /*
+ * Device not found - returns cleared exists flag.
+ */
+ goto out;
+
+ /*
+ * Setup the basic dm_ioctl structure.
+ */
+ __info(md, param);
+
+ /*
+ * Wait for a notification event
+ */
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (!dm_add_wait_queue(md, &wq, dm_get_event_nr(md))) {
+ schedule();
+ dm_remove_wait_queue(md, &wq);
+ }
+ set_current_state(TASK_RUNNING);
+ dm_put(md);
+
+ out:
+ return results_to_user(user, param, NULL, 0);
+}
+
+/*
+ * Retrieves a list of devices used by a particular dm device.
+ */
+static int dep(struct dm_ioctl *param, struct dm_ioctl *user)
+{
+ int r;
+ unsigned int count;
+ struct mapped_device *md;
+ struct list_head *tmp;
+ size_t len = 0;
+ struct dm_target_deps *deps = NULL;
+ struct dm_table *table;
+
+ md = find_device(param);
+ if (!md)
+ goto out;
+ table = dm_get_table(md);
+
+ /*
+ * Setup the basic dm_ioctl structure.
+ */
+ __info(md, param);
+
+ /*
+ * Count the devices.
+ */
+ count = 0;
+ list_for_each(tmp, dm_table_get_devices(table))
+ count++;
+
+ /*
+ * Allocate a kernel space version of the dm_target_status
+ * struct.
+ */
+ if (array_too_big(sizeof(*deps), sizeof(*deps->dev), count)) {
+ dm_table_put(table);
+ dm_put(md);
+ return -ENOMEM;
+ }
+
+ len = sizeof(*deps) + (sizeof(*deps->dev) * count);
+ deps = kmalloc(len, GFP_KERNEL);
+ if (!deps) {
+ dm_table_put(table);
+ dm_put(md);
+ return -ENOMEM;
+ }
+
+ /*
+ * Fill in the devices.
+ */
+ deps->count = count;
+ count = 0;
+ list_for_each(tmp, dm_table_get_devices(table)) {
+ struct dm_dev *dd = list_entry(tmp, struct dm_dev, list);
+ deps->dev[count++] = dd->bdev->bd_dev;
+ }
+ dm_table_put(table);
+ dm_put(md);
+
+ out:
+ r = results_to_user(user, param, deps, len);
+
+ kfree(deps);
+ return r;
+}
+
+static int remove(struct dm_ioctl *param, struct dm_ioctl *user)
+{
+ struct hash_cell *hc;
+
+ down_write(&_hash_lock);
+ hc = *param->uuid ? __get_uuid_cell(param->uuid) :
+ __get_name_cell(param->name);
+ if (!hc) {
+ DMWARN("device doesn't appear to be in the dev hash table.");
+ up_write(&_hash_lock);
+ return -EINVAL;
+ }
+
+ /*
+ * You may ask the interface to drop its reference to an
+ * in use device. This is no different to unlinking a
+ * file that someone still has open. The device will not
+ * actually be destroyed until the last opener closes it.
+ * The name and uuid of the device (both are interface
+ * properties) will be available for reuse immediately.
+ *
+ * You don't want to drop a _suspended_ device from the
+ * interface, since that will leave you with no way of
+ * resuming it.
+ */
+ if (dm_suspended(hc->md)) {
+ DMWARN("refusing to remove a suspended device.");
+ up_write(&_hash_lock);
+ return -EPERM;
+ }
+
+ __hash_remove(hc);
+ up_write(&_hash_lock);
+ return 0;
+}
+
+static int remove_all(struct dm_ioctl *param, struct dm_ioctl *user)
+{
+ dm_hash_remove_all();
+ return 0;
+}
+
+static int suspend(struct dm_ioctl *param, struct dm_ioctl *user)
+{
+ int r;
+ struct mapped_device *md;
+
+ md = find_device(param);
+ if (!md)
+ return -ENXIO;
+
+ if (param->flags & DM_SUSPEND_FLAG)
+ r = dm_suspend(md);
+ else
+ r = dm_resume(md);
+
+ dm_put(md);
+ return r;
+}
+
+static int reload(struct dm_ioctl *param, struct dm_ioctl *user)
+{
+ int r;
+ struct mapped_device *md;
+ struct dm_table *t;
+
+ r = dm_table_create(&t, get_mode(param));
+ if (r)
+ return r;
+
+ r = populate_table(t, param);
+ if (r) {
+ dm_table_put(t);
+ return r;
+ }
+
+ md = find_device(param);
+ if (!md) {
+ dm_table_put(t);
+ return -ENXIO;
+ }
+
+ r = dm_swap_table(md, t);
+ if (r) {
+ dm_put(md);
+ dm_table_put(t);
+ return r;
+ }
+ dm_table_put(t); /* md will have taken its own reference */
+
+ set_disk_ro(dm_disk(md), (param->flags & DM_READONLY_FLAG) ? 1 : 0);
+ dm_put(md);
+
+ r = info(param, user);
+ return r;
+}
+
+static int rename(struct dm_ioctl *param, struct dm_ioctl *user)
+{
+ int r;
+ char *new_name = (char *) param + param->data_start;
+
+ if (valid_str(new_name, (void *) param,
+ (void *) param + param->data_size)) {
+ DMWARN("Invalid new logical volume name supplied.");
+ return -EINVAL;
+ }
+
+ r = check_name(new_name);
+ if (r)
+ return r;
+
+ return dm_hash_rename(param->name, new_name);
+}
+
+
+/*-----------------------------------------------------------------
+ * Implementation of open/close/ioctl on the special char
+ * device.
+ *---------------------------------------------------------------*/
+static ioctl_fn lookup_ioctl(unsigned int cmd)
+{
+ static struct {
+ int cmd;
+ ioctl_fn fn;
+ } _ioctls[] = {
+ {DM_VERSION_CMD, NULL}, /* version is dealt with elsewhere */
+ {DM_REMOVE_ALL_CMD, remove_all},
+ {DM_DEV_CREATE_CMD, create},
+ {DM_DEV_REMOVE_CMD, remove},
+ {DM_DEV_RELOAD_CMD, reload},
+ {DM_DEV_RENAME_CMD, rename},
+ {DM_DEV_SUSPEND_CMD, suspend},
+ {DM_DEV_DEPS_CMD, dep},
+ {DM_DEV_STATUS_CMD, info},
+ {DM_TARGET_STATUS_CMD, get_status},
+ {DM_TARGET_WAIT_CMD, wait_device_event},
+ };
+
+ return (cmd >= ARRAY_SIZE(_ioctls)) ? NULL : _ioctls[cmd].fn;
+}
+
+/*
+ * As well as checking the version compatibility this always
+ * copies the kernel interface version out.
+ */
+static int check_version(unsigned int cmd, struct dm_ioctl *user)
+{
+ uint32_t version[3];
+ int r = 0;
+
+ if (copy_from_user(version, user->version, sizeof(version)))
+ return -EFAULT;
+
+ if ((DM_VERSION_MAJOR != version[0]) ||
+ (DM_VERSION_MINOR < version[1])) {
+ DMWARN("ioctl interface mismatch: "
+ "kernel(%u.%u.%u), user(%u.%u.%u), cmd(%d)",
+ DM_VERSION_MAJOR, DM_VERSION_MINOR,
+ DM_VERSION_PATCHLEVEL,
+ version[0], version[1], version[2], cmd);
+ r = -EINVAL;
+ }
+
+ /*
+ * Fill in the kernel version.
+ */
+ version[0] = DM_VERSION_MAJOR;
+ version[1] = DM_VERSION_MINOR;
+ version[2] = DM_VERSION_PATCHLEVEL;
+ if (copy_to_user(user->version, version, sizeof(version)))
+ return -EFAULT;
+
+ return r;
+}
+
+static void free_params(struct dm_ioctl *param)
+{
+ vfree(param);
+}
+
+static int copy_params(struct dm_ioctl *user, struct dm_ioctl **param)
+{
+ struct dm_ioctl tmp, *dmi;
+
+ if (copy_from_user(&tmp, user, sizeof(tmp)))
+ return -EFAULT;
+
+ if (tmp.data_size < sizeof(tmp))
+ return -EINVAL;
+
+ dmi = (struct dm_ioctl *) vmalloc(tmp.data_size);
+ if (!dmi)
+ return -ENOMEM;
+
+ if (copy_from_user(dmi, user, tmp.data_size)) {
+ vfree(dmi);
+ return -EFAULT;
+ }
+
+ *param = dmi;
+ return 0;
+}
+
+static int validate_params(uint cmd, struct dm_ioctl *param)
+{
+ /* Ignores parameters */
+ if (cmd == DM_REMOVE_ALL_CMD)
+ return 0;
+
+ /* Unless creating, either name of uuid but not both */
+ if (cmd != DM_DEV_CREATE_CMD) {
+ if ((!*param->uuid && !*param->name) ||
+ (*param->uuid && *param->name)) {
+ DMWARN("one of name or uuid must be supplied");
+ return -EINVAL;
+ }
+ }
+
+ /* Ensure strings are terminated */
+ param->name[DM_NAME_LEN - 1] = '\0';
+ param->uuid[DM_UUID_LEN - 1] = '\0';
+
+ return 0;
+}
+
+static int ctl_ioctl(struct inode *inode, struct file *file,
+ uint command, ulong u)
+{
+ int r = 0;
+ unsigned int cmd;
+ struct dm_ioctl *param;
+ struct dm_ioctl *user = (struct dm_ioctl *) u;
+ ioctl_fn fn = NULL;
+
+ /* only root can play with this */
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+
+ if (_IOC_TYPE(command) != DM_IOCTL)
+ return -ENOTTY;
+
+ cmd = _IOC_NR(command);
+
+ /*
+ * Check the interface version passed in. This also
+ * writes out the kernels interface version.
+ */
+ r = check_version(cmd, user);
+ if (r)
+ return r;
+
+ /*
+ * Nothing more to do for the version command.
+ */
+ if (cmd == DM_VERSION_CMD)
+ return 0;
+
+ fn = lookup_ioctl(cmd);
+ if (!fn) {
+ DMWARN("dm_ctl_ioctl: unknown command 0x%x", command);
+ return -ENOTTY;
+ }
+
+ /*
+ * Copy the parameters into kernel space.
+ */
+ r = copy_params(user, &param);
+ if (r)
+ return r;
+
+ r = validate_params(cmd, param);
+ if (r) {
+ free_params(param);
+ return r;
+ }
+
+ r = fn(param, user);
+ free_params(param);
+ return r;
+}
+
+static struct file_operations _ctl_fops = {
+ .ioctl = ctl_ioctl,
+ .owner = THIS_MODULE,
+};
+
+static struct miscdevice _dm_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = DM_NAME,
+ .devfs_name = "mapper/control",
+ .fops = &_ctl_fops
+};
+
+/*
+ * Create misc character device and link to DM_DIR/control.
+ */
+int __init dm_interface_init(void)
+{
+ int r;
+
+ r = dm_hash_init();
+ if (r)
+ return r;
+
+ r = misc_register(&_dm_misc);
+ if (r) {
+ DMERR("misc_register failed for control device");
+ dm_hash_exit();
+ return r;
+ }
+
+ DMINFO("%d.%d.%d%s initialised: %s", DM_VERSION_MAJOR,
+ DM_VERSION_MINOR, DM_VERSION_PATCHLEVEL, DM_VERSION_EXTRA,
+ DM_DRIVER_EMAIL);
+ return 0;
+
+ if (misc_deregister(&_dm_misc) < 0)
+ DMERR("misc_deregister failed for control device");
+ dm_hash_exit();
+ return r;
+}
+
+void dm_interface_exit(void)
+{
+ if (misc_deregister(&_dm_misc) < 0)
+ DMERR("misc_deregister failed for control device");
+ dm_hash_exit();
+}
diff --git a/drivers/md/dm-ioctl-v4.c b/drivers/md/dm-ioctl-v4.c
new file mode 100644
index 000000000000..7360254999da
--- /dev/null
+++ b/drivers/md/dm-ioctl-v4.c
@@ -0,0 +1,1252 @@
+/*
+ * Copyright (C) 2001, 2002 Sistina Software (UK) Limited.
+ *
+ * This file is released under the GPL.
+ */
+
+#include "dm.h"
+
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+#include <linux/miscdevice.h>
+#include <linux/init.h>
+#include <linux/wait.h>
+#include <linux/blk.h>
+#include <linux/slab.h>
+#include <linux/devfs_fs_kernel.h>
+
+#include <asm/uaccess.h>
+
+#define DM_DRIVER_EMAIL "dm@uk.sistina.com"
+
+/*-----------------------------------------------------------------
+ * The ioctl interface needs to be able to look up devices by
+ * name or uuid.
+ *---------------------------------------------------------------*/
+struct hash_cell {
+ struct list_head name_list;
+ struct list_head uuid_list;
+
+ char *name;
+ char *uuid;
+ struct mapped_device *md;
+ struct dm_table *new_map;
+};
+
+#define NUM_BUCKETS 64
+#define MASK_BUCKETS (NUM_BUCKETS - 1)
+static struct list_head _name_buckets[NUM_BUCKETS];
+static struct list_head _uuid_buckets[NUM_BUCKETS];
+
+void dm_hash_remove_all(void);
+
+/*
+ * Guards access to both hash tables.
+ */
+static DECLARE_RWSEM(_hash_lock);
+
+static void init_buckets(struct list_head *buckets)
+{
+ unsigned int i;
+
+ for (i = 0; i < NUM_BUCKETS; i++)
+ INIT_LIST_HEAD(buckets + i);
+}
+
+int dm_hash_init(void)
+{
+ init_buckets(_name_buckets);
+ init_buckets(_uuid_buckets);
+ devfs_mk_dir(DM_DIR);
+ return 0;
+}
+
+void dm_hash_exit(void)
+{
+ dm_hash_remove_all();
+ devfs_remove(DM_DIR);
+}
+
+/*-----------------------------------------------------------------
+ * Hash function:
+ * We're not really concerned with the str hash function being
+ * fast since it's only used by the ioctl interface.
+ *---------------------------------------------------------------*/
+static unsigned int hash_str(const char *str)
+{
+ const unsigned int hash_mult = 2654435387U;
+ unsigned int h = 0;
+
+ while (*str)
+ h = (h + (unsigned int) *str++) * hash_mult;
+
+ return h & MASK_BUCKETS;
+}
+
+/*-----------------------------------------------------------------
+ * Code for looking up a device by name
+ *---------------------------------------------------------------*/
+static struct hash_cell *__get_name_cell(const char *str)
+{
+ struct list_head *tmp;
+ struct hash_cell *hc;
+ unsigned int h = hash_str(str);
+
+ list_for_each (tmp, _name_buckets + h) {
+ hc = list_entry(tmp, struct hash_cell, name_list);
+ if (!strcmp(hc->name, str))
+ return hc;
+ }
+
+ return NULL;
+}
+
+static struct hash_cell *__get_uuid_cell(const char *str)
+{
+ struct list_head *tmp;
+ struct hash_cell *hc;
+ unsigned int h = hash_str(str);
+
+ list_for_each (tmp, _uuid_buckets + h) {
+ hc = list_entry(tmp, struct hash_cell, uuid_list);
+ if (!strcmp(hc->uuid, str))
+ return hc;
+ }
+
+ return NULL;
+}
+
+/*-----------------------------------------------------------------
+ * Inserting, removing and renaming a device.
+ *---------------------------------------------------------------*/
+static inline char *kstrdup(const char *str)
+{
+ char *r = kmalloc(strlen(str) + 1, GFP_KERNEL);
+ if (r)
+ strcpy(r, str);
+ return r;
+}
+
+static struct hash_cell *alloc_cell(const char *name, const char *uuid,
+ struct mapped_device *md)
+{
+ struct hash_cell *hc;
+
+ hc = kmalloc(sizeof(*hc), GFP_KERNEL);
+ if (!hc)
+ return NULL;
+
+ hc->name = kstrdup(name);
+ if (!hc->name) {
+ kfree(hc);
+ return NULL;
+ }
+
+ if (!uuid)
+ hc->uuid = NULL;
+
+ else {
+ hc->uuid = kstrdup(uuid);
+ if (!hc->uuid) {
+ kfree(hc->name);
+ kfree(hc);
+ return NULL;
+ }
+ }
+
+ INIT_LIST_HEAD(&hc->name_list);
+ INIT_LIST_HEAD(&hc->uuid_list);
+ hc->md = md;
+ hc->new_map = NULL;
+ return hc;
+}
+
+static void free_cell(struct hash_cell *hc)
+{
+ if (hc) {
+ kfree(hc->name);
+ kfree(hc->uuid);
+ kfree(hc);
+ }
+}
+
+/*
+ * devfs stuff.
+ */
+static int register_with_devfs(struct hash_cell *hc)
+{
+ struct gendisk *disk = dm_disk(hc->md);
+
+ devfs_mk_bdev(MKDEV(disk->major, disk->first_minor),
+ S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP,
+ DM_DIR "/%s", hc->name);
+ return 0;
+}
+
+static int unregister_with_devfs(struct hash_cell *hc)
+{
+ devfs_remove(DM_DIR"/%s", hc->name);
+ return 0;
+}
+
+/*
+ * The kdev_t and uuid of a device can never change once it is
+ * initially inserted.
+ */
+int dm_hash_insert(const char *name, const char *uuid, struct mapped_device *md)
+{
+ struct hash_cell *cell;
+
+ /*
+ * Allocate the new cells.
+ */
+ cell = alloc_cell(name, uuid, md);
+ if (!cell)
+ return -ENOMEM;
+
+ /*
+ * Insert the cell into both hash tables.
+ */
+ down_write(&_hash_lock);
+ if (__get_name_cell(name))
+ goto bad;
+
+ list_add(&cell->name_list, _name_buckets + hash_str(name));
+
+ if (uuid) {
+ if (__get_uuid_cell(uuid)) {
+ list_del(&cell->name_list);
+ goto bad;
+ }
+ list_add(&cell->uuid_list, _uuid_buckets + hash_str(uuid));
+ }
+ register_with_devfs(cell);
+ dm_get(md);
+ up_write(&_hash_lock);
+
+ return 0;
+
+ bad:
+ up_write(&_hash_lock);
+ free_cell(cell);
+ return -EBUSY;
+}
+
+void __hash_remove(struct hash_cell *hc)
+{
+ /* remove from the dev hash */
+ list_del(&hc->uuid_list);
+ list_del(&hc->name_list);
+ unregister_with_devfs(hc);
+ dm_put(hc->md);
+ if (hc->new_map)
+ dm_table_put(hc->new_map);
+ free_cell(hc);
+}
+
+void dm_hash_remove_all(void)
+{
+ int i;
+ struct hash_cell *hc;
+ struct list_head *tmp, *n;
+
+ down_write(&_hash_lock);
+ for (i = 0; i < NUM_BUCKETS; i++) {
+ list_for_each_safe (tmp, n, _name_buckets + i) {
+ hc = list_entry(tmp, struct hash_cell, name_list);
+ __hash_remove(hc);
+ }
+ }
+ up_write(&_hash_lock);
+}
+
+int dm_hash_rename(const char *old, const char *new)
+{
+ char *new_name, *old_name;
+ struct hash_cell *hc;
+
+ /*
+ * duplicate new.
+ */
+ new_name = kstrdup(new);
+ if (!new_name)
+ return -ENOMEM;
+
+ down_write(&_hash_lock);
+
+ /*
+ * Is new free ?
+ */
+ hc = __get_name_cell(new);
+ if (hc) {
+ DMWARN("asked to rename to an already existing name %s -> %s",
+ old, new);
+ up_write(&_hash_lock);
+ kfree(new_name);
+ return -EBUSY;
+ }
+
+ /*
+ * Is there such a device as 'old' ?
+ */
+ hc = __get_name_cell(old);
+ if (!hc) {
+ DMWARN("asked to rename a non existent device %s -> %s",
+ old, new);
+ up_write(&_hash_lock);
+ kfree(new_name);
+ return -ENXIO;
+ }
+
+ /*
+ * rename and move the name cell.
+ */
+ unregister_with_devfs(hc);
+
+ list_del(&hc->name_list);
+ old_name = hc->name;
+ hc->name = new_name;
+ list_add(&hc->name_list, _name_buckets + hash_str(new_name));
+
+ /* rename the device node in devfs */
+ register_with_devfs(hc);
+
+ up_write(&_hash_lock);
+ kfree(old_name);
+ return 0;
+}
+
+/*-----------------------------------------------------------------
+ * Implementation of the ioctl commands
+ *---------------------------------------------------------------*/
+/*
+ * All the ioctl commands get dispatched to functions with this
+ * prototype.
+ */
+typedef int (*ioctl_fn)(struct dm_ioctl *param, size_t param_size);
+
+static int remove_all(struct dm_ioctl *param, size_t param_size)
+{
+ dm_hash_remove_all();
+ param->data_size = 0;
+ return 0;
+}
+
+/*
+ * Round up the ptr to an 8-byte boundary.
+ */
+#define ALIGN_MASK 7
+static inline void *align_ptr(void *ptr)
+{
+ return (void *) (((size_t) (ptr + ALIGN_MASK)) & ~ALIGN_MASK);
+}
+
+/*
+ * Retrieves the data payload buffer from an already allocated
+ * struct dm_ioctl.
+ */
+static void *get_result_buffer(struct dm_ioctl *param, size_t param_size,
+ size_t *len)
+{
+ param->data_start = align_ptr(param + 1) - (void *) param;
+
+ if (param->data_start < param_size)
+ *len = param_size - param->data_start;
+ else
+ *len = 0;
+
+ return ((void *) param) + param->data_start;
+}
+
+static int list_devices(struct dm_ioctl *param, size_t param_size)
+{
+ unsigned int i;
+ struct hash_cell *hc;
+ size_t len, needed = 0;
+ struct gendisk *disk;
+ struct dm_name_list *nl, *old_nl = NULL;
+
+ down_write(&_hash_lock);
+
+ /*
+ * Loop through all the devices working out how much
+ * space we need.
+ */
+ for (i = 0; i < NUM_BUCKETS; i++) {
+ list_for_each_entry (hc, _name_buckets + i, name_list) {
+ needed += sizeof(struct dm_name_list);
+ needed += strlen(hc->name);
+ needed += ALIGN_MASK;
+ }
+ }
+
+ /*
+ * Grab our output buffer.
+ */
+ nl = get_result_buffer(param, param_size, &len);
+ if (len < needed) {
+ param->flags |= DM_BUFFER_FULL_FLAG;
+ goto out;
+ }
+ param->data_size = param->data_start + needed;
+
+ nl->dev = 0; /* Flags no data */
+
+ /*
+ * Now loop through filling out the names.
+ */
+ for (i = 0; i < NUM_BUCKETS; i++) {
+ list_for_each_entry (hc, _name_buckets + i, name_list) {
+ if (old_nl)
+ old_nl->next = (uint32_t) ((void *) nl -
+ (void *) old_nl);
+ disk = dm_disk(hc->md);
+ nl->dev = MKDEV(disk->major, disk->first_minor);
+ nl->next = 0;
+ strcpy(nl->name, hc->name);
+
+ old_nl = nl;
+ nl = align_ptr(((void *) ++nl) + strlen(hc->name) + 1);
+ }
+ }
+
+ out:
+ up_write(&_hash_lock);
+ return 0;
+}
+
+static int check_name(const char *name)
+{
+ if (strchr(name, '/')) {
+ DMWARN("invalid device name");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*
+ * Fills in a dm_ioctl structure, ready for sending back to
+ * userland.
+ */
+static int __dev_status(struct mapped_device *md, struct dm_ioctl *param)
+{
+ struct gendisk *disk = dm_disk(md);
+ struct dm_table *table;
+ struct block_device *bdev;
+
+ param->flags &= ~(DM_SUSPEND_FLAG | DM_READONLY_FLAG |
+ DM_ACTIVE_PRESENT_FLAG);
+
+ if (dm_suspended(md))
+ param->flags |= DM_SUSPEND_FLAG;
+
+ bdev = bdget_disk(disk, 0);
+ if (!bdev)
+ return -ENXIO;
+
+ param->dev = MKDEV(disk->major, disk->first_minor);
+
+ /*
+ * Yes, this will be out of date by the time it gets back
+ * to userland, but it is still very useful ofr
+ * debugging.
+ */
+ param->open_count = bdev->bd_openers;
+ bdput(bdev);
+
+ if (disk->policy)
+ param->flags |= DM_READONLY_FLAG;
+
+ param->event_nr = dm_get_event_nr(md);
+
+ table = dm_get_table(md);
+ if (table) {
+ param->flags |= DM_ACTIVE_PRESENT_FLAG;
+ param->target_count = dm_table_get_num_targets(table);
+ dm_table_put(table);
+ } else
+ param->target_count = 0;
+
+ return 0;
+}
+
+static int dev_create(struct dm_ioctl *param, size_t param_size)
+{
+ int r;
+ struct mapped_device *md;
+
+ r = check_name(param->name);
+ if (r)
+ return r;
+
+ if (param->flags & DM_PERSISTENT_DEV_FLAG)
+ r = dm_create_with_minor(minor(to_kdev_t(param->dev)), &md);
+ else
+ r = dm_create(&md);
+
+ if (r)
+ return r;
+
+ r = dm_hash_insert(param->name, *param->uuid ? param->uuid : NULL, md);
+ if (r) {
+ dm_put(md);
+ return r;
+ }
+
+ param->flags &= ~DM_INACTIVE_PRESENT_FLAG;
+
+ r = __dev_status(md, param);
+ dm_put(md);
+
+ return r;
+}
+
+/*
+ * Always use UUID for lookups if it's present, otherwise use name.
+ */
+static inline struct hash_cell *__find_device_hash_cell(struct dm_ioctl *param)
+{
+ return *param->uuid ?
+ __get_uuid_cell(param->uuid) : __get_name_cell(param->name);
+}
+
+static inline struct mapped_device *find_device(struct dm_ioctl *param)
+{
+ struct hash_cell *hc;
+ struct mapped_device *md = NULL;
+
+ down_read(&_hash_lock);
+ hc = __find_device_hash_cell(param);
+ if (hc) {
+ md = hc->md;
+
+ /*
+ * Sneakily write in both the name and the uuid
+ * while we have the cell.
+ */
+ strncpy(param->name, hc->name, sizeof(param->name));
+ if (hc->uuid)
+ strncpy(param->uuid, hc->uuid, sizeof(param->uuid)-1);
+ else
+ param->uuid[0] = '\0';
+
+ if (hc->new_map)
+ param->flags |= DM_INACTIVE_PRESENT_FLAG;
+ else
+ param->flags &= ~DM_INACTIVE_PRESENT_FLAG;
+
+ dm_get(md);
+ }
+ up_read(&_hash_lock);
+
+ return md;
+}
+
+static int dev_remove(struct dm_ioctl *param, size_t param_size)
+{
+ struct hash_cell *hc;
+
+ down_write(&_hash_lock);
+ hc = __find_device_hash_cell(param);
+
+ if (!hc) {
+ DMWARN("device doesn't appear to be in the dev hash table.");
+ up_write(&_hash_lock);
+ return -ENXIO;
+ }
+
+ __hash_remove(hc);
+ up_write(&_hash_lock);
+ param->data_size = 0;
+ return 0;
+}
+
+/*
+ * Check a string doesn't overrun the chunk of
+ * memory we copied from userland.
+ */
+static int invalid_str(char *str, void *end)
+{
+ while ((void *) str < end)
+ if (!*str++)
+ return 0;
+
+ return -EINVAL;
+}
+
+static int dev_rename(struct dm_ioctl *param, size_t param_size)
+{
+ int r;
+ char *new_name = (char *) param + param->data_start;
+
+ if (new_name < (char *) (param + 1) ||
+ invalid_str(new_name, (void *) param + param_size)) {
+ DMWARN("Invalid new logical volume name supplied.");
+ return -EINVAL;
+ }
+
+ r = check_name(new_name);
+ if (r)
+ return r;
+
+ param->data_size = 0;
+ return dm_hash_rename(param->name, new_name);
+}
+
+static int suspend(struct dm_ioctl *param)
+{
+ int r = 0;
+ struct mapped_device *md;
+
+ md = find_device(param);
+ if (!md)
+ return -ENXIO;
+
+ if (!dm_suspended(md))
+ r = dm_suspend(md);
+
+ if (!r)
+ r = __dev_status(md, param);
+
+ dm_put(md);
+ return r;
+}
+
+static int resume(struct dm_ioctl *param)
+{
+ int r = 0;
+ struct hash_cell *hc;
+ struct mapped_device *md;
+ struct dm_table *new_map;
+
+ down_write(&_hash_lock);
+
+ hc = __find_device_hash_cell(param);
+ if (!hc) {
+ DMWARN("device doesn't appear to be in the dev hash table.");
+ up_write(&_hash_lock);
+ return -ENXIO;
+ }
+
+ md = hc->md;
+ dm_get(md);
+
+ new_map = hc->new_map;
+ hc->new_map = NULL;
+ param->flags &= ~DM_INACTIVE_PRESENT_FLAG;
+
+ up_write(&_hash_lock);
+
+ /* Do we need to load a new map ? */
+ if (new_map) {
+ /* Suspend if it isn't already suspended */
+ if (!dm_suspended(md))
+ dm_suspend(md);
+
+ r = dm_swap_table(md, new_map);
+ if (r) {
+ dm_put(md);
+ dm_table_put(new_map);
+ return r;
+ }
+
+ if (dm_table_get_mode(new_map) & FMODE_WRITE)
+ set_disk_ro(dm_disk(md), 0);
+ else
+ set_disk_ro(dm_disk(md), 1);
+
+ dm_table_put(new_map);
+ }
+
+ if (dm_suspended(md))
+ r = dm_resume(md);
+
+ if (!r)
+ r = __dev_status(md, param);
+
+ dm_put(md);
+ return r;
+}
+
+/*
+ * Set or unset the suspension state of a device.
+ * If the device already is in the requested state we just return its status.
+ */
+static int dev_suspend(struct dm_ioctl *param, size_t param_size)
+{
+ if (param->flags & DM_SUSPEND_FLAG)
+ return suspend(param);
+
+ return resume(param);
+}
+
+/*
+ * Copies device info back to user space, used by
+ * the create and info ioctls.
+ */
+static int dev_status(struct dm_ioctl *param, size_t param_size)
+{
+ int r;
+ struct mapped_device *md;
+
+ md = find_device(param);
+ if (!md)
+ return -ENXIO;
+
+ r = __dev_status(md, param);
+ dm_put(md);
+ return r;
+}
+
+/*
+ * Wait for a device to report an event
+ */
+static int dev_wait(struct dm_ioctl *param, size_t param_size)
+{
+ int r;
+ struct mapped_device *md;
+ DECLARE_WAITQUEUE(wq, current);
+
+ md = find_device(param);
+ if (!md)
+ return -ENXIO;
+
+ /*
+ * Wait for a notification event
+ */
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (!dm_add_wait_queue(md, &wq, param->event_nr)) {
+ schedule();
+ dm_remove_wait_queue(md, &wq);
+ }
+ set_current_state(TASK_RUNNING);
+
+ /*
+ * The userland program is going to want to know what
+ * changed to trigger the event, so we may as well tell
+ * him and save an ioctl.
+ */
+ r = __dev_status(md, param);
+
+ dm_put(md);
+ return r;
+}
+
+static inline int get_mode(struct dm_ioctl *param)
+{
+ int mode = FMODE_READ | FMODE_WRITE;
+
+ if (param->flags & DM_READONLY_FLAG)
+ mode = FMODE_READ;
+
+ return mode;
+}
+
+static int next_target(struct dm_target_spec *last, uint32_t next, void *end,
+ struct dm_target_spec **spec, char **target_params)
+{
+ *spec = (struct dm_target_spec *) ((unsigned char *) last + next);
+ *target_params = (char *) (*spec + 1);
+
+ if (*spec < (last + 1))
+ return -EINVAL;
+
+ return invalid_str(*target_params, end);
+}
+
+static int populate_table(struct dm_table *table,
+ struct dm_ioctl *param, size_t param_size)
+{
+ int r;
+ unsigned int i = 0;
+ struct dm_target_spec *spec = (struct dm_target_spec *) param;
+ uint32_t next = param->data_start;
+ void *end = (void *) param + param_size;
+ char *target_params;
+
+ if (!param->target_count) {
+ DMWARN("populate_table: no targets specified");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < param->target_count; i++) {
+
+ r = next_target(spec, next, end, &spec, &target_params);
+ if (r) {
+ DMWARN("unable to find target");
+ return r;
+ }
+
+ r = dm_table_add_target(table, spec->target_type,
+ (sector_t) spec->sector_start,
+ (sector_t) spec->length,
+ target_params);
+ if (r) {
+ DMWARN("error adding target to table");
+ return r;
+ }
+
+ next = spec->next;
+ }
+
+ return dm_table_complete(table);
+}
+
+static int table_load(struct dm_ioctl *param, size_t param_size)
+{
+ int r;
+ struct hash_cell *hc;
+ struct dm_table *t;
+
+ r = dm_table_create(&t, get_mode(param));
+ if (r)
+ return r;
+
+ r = populate_table(t, param, param_size);
+ if (r) {
+ dm_table_put(t);
+ return r;
+ }
+
+ down_write(&_hash_lock);
+ hc = __find_device_hash_cell(param);
+ if (!hc) {
+ DMWARN("device doesn't appear to be in the dev hash table.");
+ up_write(&_hash_lock);
+ return -ENXIO;
+ }
+
+ hc->new_map = t;
+ param->flags |= DM_INACTIVE_PRESENT_FLAG;
+
+ r = __dev_status(hc->md, param);
+ up_write(&_hash_lock);
+ return r;
+}
+
+static int table_clear(struct dm_ioctl *param, size_t param_size)
+{
+ int r;
+ struct hash_cell *hc;
+
+ down_write(&_hash_lock);
+
+ hc = __find_device_hash_cell(param);
+ if (!hc) {
+ DMWARN("device doesn't appear to be in the dev hash table.");
+ up_write(&_hash_lock);
+ return -ENXIO;
+ }
+
+ if (hc->new_map) {
+ dm_table_put(hc->new_map);
+ hc->new_map = NULL;
+ }
+
+ param->flags &= ~DM_INACTIVE_PRESENT_FLAG;
+
+ r = __dev_status(hc->md, param);
+ up_write(&_hash_lock);
+ return r;
+}
+
+/*
+ * Retrieves a list of devices used by a particular dm device.
+ */
+static void retrieve_deps(struct dm_table *table,
+ struct dm_ioctl *param, size_t param_size)
+{
+ unsigned int count = 0;
+ struct list_head *tmp;
+ size_t len, needed;
+ struct dm_target_deps *deps;
+
+ deps = get_result_buffer(param, param_size, &len);
+
+ /*
+ * Count the devices.
+ */
+ list_for_each(tmp, dm_table_get_devices(table))
+ count++;
+
+ /*
+ * Check we have enough space.
+ */
+ needed = sizeof(*deps) + (sizeof(*deps->dev) * count);
+ if (len < needed) {
+ param->flags |= DM_BUFFER_FULL_FLAG;
+ return;
+ }
+
+ /*
+ * Fill in the devices.
+ */
+ deps->count = count;
+ count = 0;
+ list_for_each(tmp, dm_table_get_devices(table)) {
+ struct dm_dev *dd = list_entry(tmp, struct dm_dev, list);
+ deps->dev[count++] = dd->bdev->bd_dev;
+ }
+
+ param->data_size = param->data_start + needed;
+}
+
+static int table_deps(struct dm_ioctl *param, size_t param_size)
+{
+ int r = 0;
+ struct mapped_device *md;
+ struct dm_table *table;
+
+ md = find_device(param);
+ if (!md)
+ return -ENXIO;
+
+ r = __dev_status(md, param);
+ if (r)
+ goto out;
+
+ table = dm_get_table(md);
+ if (table) {
+ retrieve_deps(table, param, param_size);
+ dm_table_put(table);
+ }
+
+ out:
+ dm_put(md);
+ return r;
+}
+
+/*
+ * Build up the status struct for each target
+ */
+static void retrieve_status(struct dm_table *table,
+ struct dm_ioctl *param, size_t param_size)
+{
+ unsigned int i, num_targets;
+ struct dm_target_spec *spec;
+ char *outbuf, *outptr;
+ status_type_t type;
+ size_t remaining, len, used = 0;
+
+ outptr = outbuf = get_result_buffer(param, param_size, &len);
+
+ if (param->flags & DM_STATUS_TABLE_FLAG)
+ type = STATUSTYPE_TABLE;
+ else
+ type = STATUSTYPE_INFO;
+
+ /* Get all the target info */
+ num_targets = dm_table_get_num_targets(table);
+ for (i = 0; i < num_targets; i++) {
+ struct dm_target *ti = dm_table_get_target(table, i);
+
+ remaining = len - (outptr - outbuf);
+ if (remaining < sizeof(struct dm_target_spec)) {
+ param->flags |= DM_BUFFER_FULL_FLAG;
+ break;
+ }
+
+ spec = (struct dm_target_spec *) outptr;
+
+ spec->status = 0;
+ spec->sector_start = ti->begin;
+ spec->length = ti->len;
+ strncpy(spec->target_type, ti->type->name,
+ sizeof(spec->target_type));
+
+ outptr += sizeof(struct dm_target_spec);
+ remaining = len - (outptr - outbuf);
+
+ /* Get the status/table string from the target driver */
+ if (ti->type->status) {
+ if (ti->type->status(ti, type, outptr, remaining)) {
+ param->flags |= DM_BUFFER_FULL_FLAG;
+ break;
+ }
+ } else
+ outptr[0] = '\0';
+
+ outptr += strlen(outptr) + 1;
+ used = param->data_start + (outptr - outbuf);
+
+ align_ptr(outptr);
+ spec->next = outptr - outbuf;
+ }
+
+ if (used)
+ param->data_size = used;
+
+ param->target_count = num_targets;
+}
+
+/*
+ * Return the status of a device as a text string for each
+ * target.
+ */
+static int table_status(struct dm_ioctl *param, size_t param_size)
+{
+ int r;
+ struct mapped_device *md;
+ struct dm_table *table;
+
+ md = find_device(param);
+ if (!md)
+ return -ENXIO;
+
+ r = __dev_status(md, param);
+ if (r)
+ goto out;
+
+ table = dm_get_table(md);
+ if (table) {
+ retrieve_status(table, param, param_size);
+ dm_table_put(table);
+ }
+
+ out:
+ dm_put(md);
+ return r;
+}
+
+/*-----------------------------------------------------------------
+ * Implementation of open/close/ioctl on the special char
+ * device.
+ *---------------------------------------------------------------*/
+static ioctl_fn lookup_ioctl(unsigned int cmd)
+{
+ static struct {
+ int cmd;
+ ioctl_fn fn;
+ } _ioctls[] = {
+ {DM_VERSION_CMD, NULL}, /* version is dealt with elsewhere */
+ {DM_REMOVE_ALL_CMD, remove_all},
+ {DM_LIST_DEVICES_CMD, list_devices},
+
+ {DM_DEV_CREATE_CMD, dev_create},
+ {DM_DEV_REMOVE_CMD, dev_remove},
+ {DM_DEV_RENAME_CMD, dev_rename},
+ {DM_DEV_SUSPEND_CMD, dev_suspend},
+ {DM_DEV_STATUS_CMD, dev_status},
+ {DM_DEV_WAIT_CMD, dev_wait},
+
+ {DM_TABLE_LOAD_CMD, table_load},
+ {DM_TABLE_CLEAR_CMD, table_clear},
+ {DM_TABLE_DEPS_CMD, table_deps},
+ {DM_TABLE_STATUS_CMD, table_status}
+ };
+
+ return (cmd >= ARRAY_SIZE(_ioctls)) ? NULL : _ioctls[cmd].fn;
+}
+
+/*
+ * As well as checking the version compatibility this always
+ * copies the kernel interface version out.
+ */
+static int check_version(unsigned int cmd, struct dm_ioctl *user)
+{
+ uint32_t version[3];
+ int r = 0;
+
+ if (copy_from_user(version, user->version, sizeof(version)))
+ return -EFAULT;
+
+ if ((DM_VERSION_MAJOR != version[0]) ||
+ (DM_VERSION_MINOR < version[1])) {
+ DMWARN("ioctl interface mismatch: "
+ "kernel(%u.%u.%u), user(%u.%u.%u), cmd(%d)",
+ DM_VERSION_MAJOR, DM_VERSION_MINOR,
+ DM_VERSION_PATCHLEVEL,
+ version[0], version[1], version[2], cmd);
+ r = -EINVAL;
+ }
+
+ /*
+ * Fill in the kernel version.
+ */
+ version[0] = DM_VERSION_MAJOR;
+ version[1] = DM_VERSION_MINOR;
+ version[2] = DM_VERSION_PATCHLEVEL;
+ if (copy_to_user(user->version, version, sizeof(version)))
+ return -EFAULT;
+
+ return r;
+}
+
+static void free_params(struct dm_ioctl *param)
+{
+ vfree(param);
+}
+
+static int copy_params(struct dm_ioctl *user, struct dm_ioctl **param)
+{
+ struct dm_ioctl tmp, *dmi;
+
+ if (copy_from_user(&tmp, user, sizeof(tmp)))
+ return -EFAULT;
+
+ if (tmp.data_size < sizeof(tmp))
+ return -EINVAL;
+
+ dmi = (struct dm_ioctl *) vmalloc(tmp.data_size);
+ if (!dmi)
+ return -ENOMEM;
+
+ if (copy_from_user(dmi, user, tmp.data_size)) {
+ vfree(dmi);
+ return -EFAULT;
+ }
+
+ *param = dmi;
+ return 0;
+}
+
+static int validate_params(uint cmd, struct dm_ioctl *param)
+{
+ /* Always clear this flag */
+ param->flags &= ~DM_BUFFER_FULL_FLAG;
+
+ /* Ignores parameters */
+ if (cmd == DM_REMOVE_ALL_CMD || cmd == DM_LIST_DEVICES_CMD)
+ return 0;
+
+ /* Unless creating, either name or uuid but not both */
+ if (cmd != DM_DEV_CREATE_CMD) {
+ if ((!*param->uuid && !*param->name) ||
+ (*param->uuid && *param->name)) {
+ DMWARN("one of name or uuid must be supplied, cmd(%u)",
+ cmd);
+ return -EINVAL;
+ }
+ }
+
+ /* Ensure strings are terminated */
+ param->name[DM_NAME_LEN - 1] = '\0';
+ param->uuid[DM_UUID_LEN - 1] = '\0';
+
+ return 0;
+}
+
+static int ctl_ioctl(struct inode *inode, struct file *file,
+ uint command, ulong u)
+{
+ int r = 0;
+ unsigned int cmd;
+ struct dm_ioctl *param;
+ struct dm_ioctl *user = (struct dm_ioctl *) u;
+ ioctl_fn fn = NULL;
+ size_t param_size;
+
+ /* only root can play with this */
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+
+ if (_IOC_TYPE(command) != DM_IOCTL)
+ return -ENOTTY;
+
+ cmd = _IOC_NR(command);
+
+ /*
+ * Check the interface version passed in. This also
+ * writes out the kernel's interface version.
+ */
+ r = check_version(cmd, user);
+ if (r)
+ return r;
+
+ /*
+ * Nothing more to do for the version command.
+ */
+ if (cmd == DM_VERSION_CMD)
+ return 0;
+
+ fn = lookup_ioctl(cmd);
+ if (!fn) {
+ DMWARN("dm_ctl_ioctl: unknown command 0x%x", command);
+ return -ENOTTY;
+ }
+
+ /*
+ * Trying to avoid low memory issues when a device is
+ * suspended.
+ */
+ current->flags |= PF_MEMALLOC;
+
+ /*
+ * Copy the parameters into kernel space.
+ */
+ r = copy_params(user, &param);
+ if (r) {
+ current->flags &= ~PF_MEMALLOC;
+ return r;
+ }
+
+ /*
+ * FIXME: eventually we will remove the PF_MEMALLOC flag
+ * here. However the tools still do nasty things like
+ * 'load' while a device is suspended.
+ */
+
+ r = validate_params(cmd, param);
+ if (r)
+ goto out;
+
+ param_size = param->data_size;
+ param->data_size = sizeof(*param);
+ r = fn(param, param_size);
+
+ /*
+ * Copy the results back to userland.
+ */
+ if (!r && copy_to_user(user, param, param->data_size))
+ r = -EFAULT;
+
+ out:
+ free_params(param);
+ current->flags &= ~PF_MEMALLOC;
+ return r;
+}
+
+static struct file_operations _ctl_fops = {
+ .ioctl = ctl_ioctl,
+ .owner = THIS_MODULE,
+};
+
+static struct miscdevice _dm_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = DM_NAME,
+ .devfs_name = "mapper/control",
+ .fops = &_ctl_fops
+};
+
+/*
+ * Create misc character device and link to DM_DIR/control.
+ */
+int __init dm_interface_init(void)
+{
+ int r;
+
+ r = dm_hash_init();
+ if (r)
+ return r;
+
+ r = misc_register(&_dm_misc);
+ if (r) {
+ DMERR("misc_register failed for control device");
+ dm_hash_exit();
+ return r;
+ }
+
+ DMINFO("%d.%d.%d%s initialised: %s", DM_VERSION_MAJOR,
+ DM_VERSION_MINOR, DM_VERSION_PATCHLEVEL, DM_VERSION_EXTRA,
+ DM_DRIVER_EMAIL);
+ return 0;
+}
+
+void dm_interface_exit(void)
+{
+ if (misc_deregister(&_dm_misc) < 0)
+ DMERR("misc_deregister failed for control device");
+
+ dm_hash_exit();
+}
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c
index 52f95fd239b8..9af8a5a9b1e8 100644
--- a/drivers/md/dm-ioctl.c
+++ b/drivers/md/dm-ioctl.c
@@ -1,1133 +1,13 @@
/*
- * Copyright (C) 2001, 2002 Sistina Software (UK) Limited.
+ * Copyright (C) 2003 Sistina Software (UK) Limited.
*
* This file is released under the GPL.
*/
-#include "dm.h"
-
-#include <linux/module.h>
-#include <linux/vmalloc.h>
-#include <linux/miscdevice.h>
#include <linux/dm-ioctl.h>
-#include <linux/init.h>
-#include <linux/wait.h>
-#include <linux/slab.h>
-#include <linux/devfs_fs_kernel.h>
-
-#include <asm/uaccess.h>
-
-#define DM_DRIVER_EMAIL "dm@uk.sistina.com"
-
-/*-----------------------------------------------------------------
- * The ioctl interface needs to be able to look up devices by
- * name or uuid.
- *---------------------------------------------------------------*/
-struct hash_cell {
- struct list_head name_list;
- struct list_head uuid_list;
-
- char *name;
- char *uuid;
- struct mapped_device *md;
-};
-
-#define NUM_BUCKETS 64
-#define MASK_BUCKETS (NUM_BUCKETS - 1)
-static struct list_head _name_buckets[NUM_BUCKETS];
-static struct list_head _uuid_buckets[NUM_BUCKETS];
-
-void dm_hash_remove_all(void);
-
-/*
- * Guards access to all three tables.
- */
-static DECLARE_RWSEM(_hash_lock);
-
-static void init_buckets(struct list_head *buckets)
-{
- unsigned int i;
-
- for (i = 0; i < NUM_BUCKETS; i++)
- INIT_LIST_HEAD(buckets + i);
-}
-
-int dm_hash_init(void)
-{
- init_buckets(_name_buckets);
- init_buckets(_uuid_buckets);
- devfs_mk_dir(DM_DIR);
- return 0;
-}
-
-void dm_hash_exit(void)
-{
- dm_hash_remove_all();
- devfs_remove(DM_DIR);
-}
-
-/*-----------------------------------------------------------------
- * Hash function:
- * We're not really concerned with the str hash function being
- * fast since it's only used by the ioctl interface.
- *---------------------------------------------------------------*/
-static unsigned int hash_str(const char *str)
-{
- const unsigned int hash_mult = 2654435387U;
- unsigned int h = 0;
-
- while (*str)
- h = (h + (unsigned int) *str++) * hash_mult;
-
- return h & MASK_BUCKETS;
-}
-
-/*-----------------------------------------------------------------
- * Code for looking up a device by name
- *---------------------------------------------------------------*/
-static struct hash_cell *__get_name_cell(const char *str)
-{
- struct list_head *tmp;
- struct hash_cell *hc;
- unsigned int h = hash_str(str);
-
- list_for_each (tmp, _name_buckets + h) {
- hc = list_entry(tmp, struct hash_cell, name_list);
- if (!strcmp(hc->name, str))
- return hc;
- }
-
- return NULL;
-}
-
-static struct hash_cell *__get_uuid_cell(const char *str)
-{
- struct list_head *tmp;
- struct hash_cell *hc;
- unsigned int h = hash_str(str);
-
- list_for_each (tmp, _uuid_buckets + h) {
- hc = list_entry(tmp, struct hash_cell, uuid_list);
- if (!strcmp(hc->uuid, str))
- return hc;
- }
-
- return NULL;
-}
-
-/*-----------------------------------------------------------------
- * Inserting, removing and renaming a device.
- *---------------------------------------------------------------*/
-static inline char *kstrdup(const char *str)
-{
- char *r = kmalloc(strlen(str) + 1, GFP_KERNEL);
- if (r)
- strcpy(r, str);
- return r;
-}
-
-static struct hash_cell *alloc_cell(const char *name, const char *uuid,
- struct mapped_device *md)
-{
- struct hash_cell *hc;
-
- hc = kmalloc(sizeof(*hc), GFP_KERNEL);
- if (!hc)
- return NULL;
-
- hc->name = kstrdup(name);
- if (!hc->name) {
- kfree(hc);
- return NULL;
- }
-
- if (!uuid)
- hc->uuid = NULL;
-
- else {
- hc->uuid = kstrdup(uuid);
- if (!hc->uuid) {
- kfree(hc->name);
- kfree(hc);
- return NULL;
- }
- }
-
- INIT_LIST_HEAD(&hc->name_list);
- INIT_LIST_HEAD(&hc->uuid_list);
- hc->md = md;
- return hc;
-}
-
-static void free_cell(struct hash_cell *hc)
-{
- if (hc) {
- kfree(hc->name);
- kfree(hc->uuid);
- kfree(hc);
- }
-}
-
-/*
- * devfs stuff.
- */
-static int register_with_devfs(struct hash_cell *hc)
-{
- struct gendisk *disk = dm_disk(hc->md);
-
- devfs_mk_bdev(MKDEV(disk->major, disk->first_minor),
- S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP,
- DM_DIR "/%s", hc->name);
- return 0;
-}
-
-static int unregister_with_devfs(struct hash_cell *hc)
-{
- devfs_remove(DM_DIR"/%s", hc->name);
- return 0;
-}
-
-/*
- * The kdev_t and uuid of a device can never change once it is
- * initially inserted.
- */
-int dm_hash_insert(const char *name, const char *uuid, struct mapped_device *md)
-{
- struct hash_cell *cell;
-
- /*
- * Allocate the new cells.
- */
- cell = alloc_cell(name, uuid, md);
- if (!cell)
- return -ENOMEM;
-
- /*
- * Insert the cell into all three hash tables.
- */
- down_write(&_hash_lock);
- if (__get_name_cell(name))
- goto bad;
-
- list_add(&cell->name_list, _name_buckets + hash_str(name));
-
- if (uuid) {
- if (__get_uuid_cell(uuid)) {
- list_del(&cell->name_list);
- goto bad;
- }
- list_add(&cell->uuid_list, _uuid_buckets + hash_str(uuid));
- }
- register_with_devfs(cell);
- dm_get(md);
- up_write(&_hash_lock);
-
- return 0;
-
- bad:
- up_write(&_hash_lock);
- free_cell(cell);
- return -EBUSY;
-}
-
-void __hash_remove(struct hash_cell *hc)
-{
- /* remove from the dev hash */
- list_del(&hc->uuid_list);
- list_del(&hc->name_list);
- unregister_with_devfs(hc);
- dm_put(hc->md);
- free_cell(hc);
-}
-
-void dm_hash_remove_all(void)
-{
- int i;
- struct hash_cell *hc;
- struct list_head *tmp, *n;
-
- down_write(&_hash_lock);
- for (i = 0; i < NUM_BUCKETS; i++) {
- list_for_each_safe (tmp, n, _name_buckets + i) {
- hc = list_entry(tmp, struct hash_cell, name_list);
- __hash_remove(hc);
- }
- }
- up_write(&_hash_lock);
-}
-
-int dm_hash_rename(const char *old, const char *new)
-{
- char *new_name, *old_name;
- struct hash_cell *hc;
-
- /*
- * duplicate new.
- */
- new_name = kstrdup(new);
- if (!new_name)
- return -ENOMEM;
-
- down_write(&_hash_lock);
-
- /*
- * Is new free ?
- */
- hc = __get_name_cell(new);
- if (hc) {
- DMWARN("asked to rename to an already existing name %s -> %s",
- old, new);
- up_write(&_hash_lock);
- kfree(new_name);
- return -EBUSY;
- }
-
- /*
- * Is there such a device as 'old' ?
- */
- hc = __get_name_cell(old);
- if (!hc) {
- DMWARN("asked to rename a non existent device %s -> %s",
- old, new);
- up_write(&_hash_lock);
- kfree(new_name);
- return -ENXIO;
- }
-
- /*
- * rename and move the name cell.
- */
- unregister_with_devfs(hc);
-
- list_del(&hc->name_list);
- old_name = hc->name;
- hc->name = new_name;
- list_add(&hc->name_list, _name_buckets + hash_str(new_name));
-
- /* rename the device node in devfs */
- register_with_devfs(hc);
-
- up_write(&_hash_lock);
- kfree(old_name);
- return 0;
-}
-
-
-/*-----------------------------------------------------------------
- * Implementation of the ioctl commands
- *---------------------------------------------------------------*/
-
-/*
- * All the ioctl commands get dispatched to functions with this
- * prototype.
- */
-typedef int (*ioctl_fn)(struct dm_ioctl *param, struct dm_ioctl *user);
-
-/*
- * Check a string doesn't overrun the chunk of
- * memory we copied from userland.
- */
-static int valid_str(char *str, void *begin, void *end)
-{
- while (((void *) str >= begin) && ((void *) str < end))
- if (!*str++)
- return 0;
-
- return -EINVAL;
-}
-
-static int next_target(struct dm_target_spec *last, uint32_t next,
- void *begin, void *end,
- struct dm_target_spec **spec, char **params)
-{
- *spec = (struct dm_target_spec *)
- ((unsigned char *) last + next);
- *params = (char *) (*spec + 1);
-
- if (*spec < (last + 1) || ((void *) *spec > end))
- return -EINVAL;
-
- return valid_str(*params, begin, end);
-}
-
-static int populate_table(struct dm_table *table, struct dm_ioctl *args)
-{
- int r, first = 1;
- unsigned int i = 0;
- struct dm_target_spec *spec;
- char *params;
- void *begin, *end;
-
- if (!args->target_count) {
- DMWARN("populate_table: no targets specified");
- return -EINVAL;
- }
-
- begin = (void *) args;
- end = begin + args->data_size;
-
- for (i = 0; i < args->target_count; i++) {
-
- if (first)
- r = next_target((struct dm_target_spec *) args,
- args->data_start,
- begin, end, &spec, &params);
- else
- r = next_target(spec, spec->next, begin, end,
- &spec, &params);
-
- if (r) {
- DMWARN("unable to find target");
- return -EINVAL;
- }
-
- r = dm_table_add_target(table, spec->target_type,
- (sector_t) spec->sector_start,
- (sector_t) spec->length,
- params);
- if (r) {
- DMWARN("internal error adding target to table");
- return -EINVAL;
- }
-
- first = 0;
- }
-
- return dm_table_complete(table);
-}
-
-/*
- * Round up the ptr to the next 'align' boundary. Obviously
- * 'align' must be a power of 2.
- */
-static inline void *align_ptr(void *ptr, unsigned int align)
-{
- align--;
- return (void *) (((unsigned long) (ptr + align)) & ~align);
-}
-
-/*
- * Copies a dm_ioctl and an optional additional payload to
- * userland.
- */
-static int results_to_user(struct dm_ioctl *user, struct dm_ioctl *param,
- void *data, uint32_t len)
-{
- int r;
- void *ptr = NULL;
-
- if (data) {
- ptr = align_ptr(user + 1, sizeof(unsigned long));
- param->data_start = ptr - (void *) user;
- }
-
- /*
- * The version number has already been filled in, so we
- * just copy later fields.
- */
- r = copy_to_user(&user->data_size, &param->data_size,
- sizeof(*param) - sizeof(param->version));
- if (r)
- return -EFAULT;
-
- if (data) {
- if (param->data_start + len > param->data_size)
- return -ENOSPC;
-
- if (copy_to_user(ptr, data, len))
- r = -EFAULT;
- }
-
- return r;
-}
-
-/*
- * Fills in a dm_ioctl structure, ready for sending back to
- * userland.
- */
-static int __info(struct mapped_device *md, struct dm_ioctl *param)
-{
- struct dm_table *table;
- struct block_device *bdev;
- struct gendisk *disk = dm_disk(md);
-
- param->flags = DM_EXISTS_FLAG;
- if (dm_suspended(md))
- param->flags |= DM_SUSPEND_FLAG;
-
- bdev = bdget_disk(disk, 0);
- if (!bdev)
- return -ENXIO;
-
- param->dev = bdev->bd_dev;
- param->open_count = bdev->bd_openers;
- bdput(bdev);
-
- if (disk->policy)
- param->flags |= DM_READONLY_FLAG;
-
- table = dm_get_table(md);
- param->target_count = dm_table_get_num_targets(table);
- dm_table_put(table);
-
- return 0;
-}
-
-/*
- * Always use UUID for lookups if it's present, otherwise use name.
- */
-static inline struct mapped_device *find_device(struct dm_ioctl *param)
-{
- struct hash_cell *hc;
- struct mapped_device *md = NULL;
-
- down_read(&_hash_lock);
- hc = *param->uuid ? __get_uuid_cell(param->uuid) :
- __get_name_cell(param->name);
- if (hc) {
- md = hc->md;
-
- /*
- * Sneakily write in both the name and the uuid
- * while we have the cell.
- */
- strlcpy(param->name, hc->name, sizeof(param->name));
- if (hc->uuid)
- strlcpy(param->uuid, hc->uuid, sizeof(param->uuid));
- else
- param->uuid[0] = '\0';
-
- dm_get(md);
- }
- up_read(&_hash_lock);
-
- return md;
-}
-
-#define ALIGNMENT sizeof(int)
-static void *_align(void *ptr, unsigned int a)
-{
- register unsigned long align = --a;
-
- return (void *) (((unsigned long) ptr + align) & ~align);
-}
-
-/*
- * Copies device info back to user space, used by
- * the create and info ioctls.
- */
-static int info(struct dm_ioctl *param, struct dm_ioctl *user)
-{
- struct mapped_device *md;
-
- param->flags = 0;
-
- md = find_device(param);
- if (!md)
- /*
- * Device not found - returns cleared exists flag.
- */
- goto out;
-
- __info(md, param);
- dm_put(md);
-
- out:
- return results_to_user(user, param, NULL, 0);
-}
-
-static inline int get_mode(struct dm_ioctl *param)
-{
- int mode = FMODE_READ | FMODE_WRITE;
-
- if (param->flags & DM_READONLY_FLAG)
- mode = FMODE_READ;
-
- return mode;
-}
-
-static int check_name(const char *name)
-{
- if (name[0] == '/') {
- DMWARN("invalid device name");
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int create(struct dm_ioctl *param, struct dm_ioctl *user)
-{
- int r;
- struct dm_table *t;
- struct mapped_device *md;
-
- r = check_name(param->name);
- if (r)
- return r;
-
- r = dm_table_create(&t, get_mode(param));
- if (r)
- return r;
-
- r = populate_table(t, param);
- if (r) {
- dm_table_put(t);
- return r;
- }
-
- if (param->flags & DM_PERSISTENT_DEV_FLAG)
- r = dm_create_with_minor(minor(to_kdev_t(param->dev)), t, &md);
- else
- r = dm_create(t, &md);
-
- if (r) {
- dm_table_put(t);
- return r;
- }
- dm_table_put(t); /* md will have grabbed its own reference */
-
- set_disk_ro(dm_disk(md), (param->flags & DM_READONLY_FLAG) ? 1 : 0);
- r = dm_hash_insert(param->name, *param->uuid ? param->uuid : NULL, md);
- dm_put(md);
-
- return r ? r : info(param, user);
-}
-
-/*
- * Build up the status struct for each target
- */
-static int __status(struct mapped_device *md, struct dm_ioctl *param,
- char *outbuf, size_t *len)
-{
- unsigned int i, num_targets;
- struct dm_target_spec *spec;
- char *outptr;
- status_type_t type;
- struct dm_table *table = dm_get_table(md);
-
- if (param->flags & DM_STATUS_TABLE_FLAG)
- type = STATUSTYPE_TABLE;
- else
- type = STATUSTYPE_INFO;
-
- outptr = outbuf;
-
- /* Get all the target info */
- num_targets = dm_table_get_num_targets(table);
- for (i = 0; i < num_targets; i++) {
- struct dm_target *ti = dm_table_get_target(table, i);
-
- if (outptr - outbuf +
- sizeof(struct dm_target_spec) > param->data_size) {
- dm_table_put(table);
- return -ENOMEM;
- }
-
- spec = (struct dm_target_spec *) outptr;
-
- spec->status = 0;
- spec->sector_start = ti->begin;
- spec->length = ti->len;
- strlcpy(spec->target_type, ti->type->name,
- sizeof(spec->target_type));
-
- outptr += sizeof(struct dm_target_spec);
-
- /* Get the status/table string from the target driver */
- if (ti->type->status)
- ti->type->status(ti, type, outptr,
- outbuf + param->data_size - outptr);
- else
- outptr[0] = '\0';
-
- outptr += strlen(outptr) + 1;
- _align(outptr, ALIGNMENT);
- spec->next = outptr - outbuf;
- }
-
- param->target_count = num_targets;
- *len = outptr - outbuf;
- dm_table_put(table);
-
- return 0;
-}
-
-/*
- * Return the status of a device as a text string for each
- * target.
- */
-static int get_status(struct dm_ioctl *param, struct dm_ioctl *user)
-{
- struct mapped_device *md;
- size_t len = 0;
- int ret;
- char *outbuf = NULL;
-
- md = find_device(param);
- if (!md)
- /*
- * Device not found - returns cleared exists flag.
- */
- goto out;
-
- /* We haven't a clue how long the resultant data will be so
- just allocate as much as userland has allowed us and make sure
- we don't overun it */
- outbuf = kmalloc(param->data_size, GFP_KERNEL);
- if (!outbuf)
- goto out;
- /*
- * Get the status of all targets
- */
- __status(md, param, outbuf, &len);
-
- /*
- * Setup the basic dm_ioctl structure.
- */
- __info(md, param);
-
- out:
- if (md)
- dm_put(md);
-
- ret = results_to_user(user, param, outbuf, len);
-
- if (outbuf)
- kfree(outbuf);
-
- return ret;
-}
-
-/*
- * Wait for a device to report an event
- */
-static int wait_device_event(struct dm_ioctl *param, struct dm_ioctl *user)
-{
- struct mapped_device *md;
- struct dm_table *table;
- DECLARE_WAITQUEUE(wq, current);
-
- md = find_device(param);
- if (!md)
- /*
- * Device not found - returns cleared exists flag.
- */
- goto out;
-
- /*
- * Setup the basic dm_ioctl structure.
- */
- __info(md, param);
-
- /*
- * Wait for a notification event
- */
- set_current_state(TASK_INTERRUPTIBLE);
- table = dm_get_table(md);
- dm_table_add_wait_queue(table, &wq);
- dm_table_put(table);
- dm_put(md);
-
- schedule();
-
- out:
- return results_to_user(user, param, NULL, 0);
-}
-
-/*
- * Retrieves a list of devices used by a particular dm device.
- */
-static int dep(struct dm_ioctl *param, struct dm_ioctl *user)
-{
- int r;
- unsigned int count;
- struct mapped_device *md;
- struct list_head *tmp;
- size_t len = 0;
- struct dm_target_deps *deps = NULL;
- struct dm_table *table;
-
- md = find_device(param);
- if (!md)
- goto out;
- table = dm_get_table(md);
-
- /*
- * Setup the basic dm_ioctl structure.
- */
- __info(md, param);
-
- /*
- * Count the devices.
- */
- count = 0;
- list_for_each(tmp, dm_table_get_devices(table))
- count++;
-
- /*
- * Allocate a kernel space version of the dm_target_status
- * struct.
- */
- if (array_too_big(sizeof(*deps), sizeof(*deps->dev), count)) {
- dm_table_put(table);
- dm_put(md);
- return -ENOMEM;
- }
-
- len = sizeof(*deps) + (sizeof(*deps->dev) * count);
- deps = kmalloc(len, GFP_KERNEL);
- if (!deps) {
- dm_table_put(table);
- dm_put(md);
- return -ENOMEM;
- }
-
- /*
- * Fill in the devices.
- */
- deps->count = count;
- count = 0;
- list_for_each(tmp, dm_table_get_devices(table)) {
- struct dm_dev *dd = list_entry(tmp, struct dm_dev, list);
- deps->dev[count++] = dd->bdev->bd_dev;
- }
- dm_table_put(table);
- dm_put(md);
-
- out:
- r = results_to_user(user, param, deps, len);
-
- kfree(deps);
- return r;
-}
-
-static int remove(struct dm_ioctl *param, struct dm_ioctl *user)
-{
- struct hash_cell *hc;
-
- down_write(&_hash_lock);
- hc = *param->uuid ? __get_uuid_cell(param->uuid) :
- __get_name_cell(param->name);
- if (!hc) {
- DMWARN("device doesn't appear to be in the dev hash table.");
- up_write(&_hash_lock);
- return -EINVAL;
- }
-
- /*
- * You may ask the interface to drop its reference to an
- * in use device. This is no different to unlinking a
- * file that someone still has open. The device will not
- * actually be destroyed until the last opener closes it.
- * The name and uuid of the device (both are interface
- * properties) will be available for reuse immediately.
- *
- * You don't want to drop a _suspended_ device from the
- * interface, since that will leave you with no way of
- * resuming it.
- */
- if (dm_suspended(hc->md)) {
- DMWARN("refusing to remove a suspended device.");
- up_write(&_hash_lock);
- return -EPERM;
- }
-
- __hash_remove(hc);
- up_write(&_hash_lock);
- return 0;
-}
-
-static int remove_all(struct dm_ioctl *param, struct dm_ioctl *user)
-{
- dm_hash_remove_all();
- return 0;
-}
-
-static int suspend(struct dm_ioctl *param, struct dm_ioctl *user)
-{
- int r;
- struct mapped_device *md;
-
- md = find_device(param);
- if (!md)
- return -ENXIO;
-
- if (param->flags & DM_SUSPEND_FLAG)
- r = dm_suspend(md);
- else
- r = dm_resume(md);
-
- dm_put(md);
- return r;
-}
-
-static int reload(struct dm_ioctl *param, struct dm_ioctl *user)
-{
- int r;
- struct mapped_device *md;
- struct dm_table *t;
-
- r = dm_table_create(&t, get_mode(param));
- if (r)
- return r;
-
- r = populate_table(t, param);
- if (r) {
- dm_table_put(t);
- return r;
- }
-
- md = find_device(param);
- if (!md) {
- dm_table_put(t);
- return -ENXIO;
- }
-
- r = dm_swap_table(md, t);
- if (r) {
- dm_put(md);
- dm_table_put(t);
- return r;
- }
- dm_table_put(t); /* md will have taken its own reference */
-
- set_disk_ro(dm_disk(md), (param->flags & DM_READONLY_FLAG) ? 1 : 0);
- dm_put(md);
-
- r = info(param, user);
- return r;
-}
-
-static int rename(struct dm_ioctl *param, struct dm_ioctl *user)
-{
- int r;
- char *new_name = (char *) param + param->data_start;
-
- if (valid_str(new_name, (void *) param,
- (void *) param + param->data_size)) {
- DMWARN("Invalid new logical volume name supplied.");
- return -EINVAL;
- }
-
- r = check_name(new_name);
- if (r)
- return r;
-
- return dm_hash_rename(param->name, new_name);
-}
-
-
-/*-----------------------------------------------------------------
- * Implementation of open/close/ioctl on the special char
- * device.
- *---------------------------------------------------------------*/
-static ioctl_fn lookup_ioctl(unsigned int cmd)
-{
- static struct {
- int cmd;
- ioctl_fn fn;
- } _ioctls[] = {
- {DM_VERSION_CMD, NULL}, /* version is dealt with elsewhere */
- {DM_REMOVE_ALL_CMD, remove_all},
- {DM_DEV_CREATE_CMD, create},
- {DM_DEV_REMOVE_CMD, remove},
- {DM_DEV_RELOAD_CMD, reload},
- {DM_DEV_RENAME_CMD, rename},
- {DM_DEV_SUSPEND_CMD, suspend},
- {DM_DEV_DEPS_CMD, dep},
- {DM_DEV_STATUS_CMD, info},
- {DM_TARGET_STATUS_CMD, get_status},
- {DM_TARGET_WAIT_CMD, wait_device_event},
- };
-
- return (cmd >= ARRAY_SIZE(_ioctls)) ? NULL : _ioctls[cmd].fn;
-}
-
-/*
- * As well as checking the version compatibility this always
- * copies the kernel interface version out.
- */
-static int check_version(unsigned int cmd, struct dm_ioctl *user)
-{
- uint32_t version[3];
- int r = 0;
-
- if (copy_from_user(version, user->version, sizeof(version)))
- return -EFAULT;
-
- if ((DM_VERSION_MAJOR != version[0]) ||
- (DM_VERSION_MINOR < version[1])) {
- DMWARN("ioctl interface mismatch: "
- "kernel(%u.%u.%u), user(%u.%u.%u), cmd(%d)",
- DM_VERSION_MAJOR, DM_VERSION_MINOR,
- DM_VERSION_PATCHLEVEL,
- version[0], version[1], version[2], cmd);
- r = -EINVAL;
- }
-
- /*
- * Fill in the kernel version.
- */
- version[0] = DM_VERSION_MAJOR;
- version[1] = DM_VERSION_MINOR;
- version[2] = DM_VERSION_PATCHLEVEL;
- if (copy_to_user(user->version, version, sizeof(version)))
- return -EFAULT;
-
- return r;
-}
-
-static void free_params(struct dm_ioctl *param)
-{
- vfree(param);
-}
-
-static int copy_params(struct dm_ioctl *user, struct dm_ioctl **param)
-{
- struct dm_ioctl tmp, *dmi;
-
- if (copy_from_user(&tmp, user, sizeof(tmp)))
- return -EFAULT;
-
- if (tmp.data_size < sizeof(tmp))
- return -EINVAL;
-
- dmi = (struct dm_ioctl *) vmalloc(tmp.data_size);
- if (!dmi)
- return -ENOMEM;
-
- if (copy_from_user(dmi, user, tmp.data_size)) {
- vfree(dmi);
- return -EFAULT;
- }
-
- *param = dmi;
- return 0;
-}
-
-static int validate_params(uint cmd, struct dm_ioctl *param)
-{
- /* Ignores parameters */
- if (cmd == DM_REMOVE_ALL_CMD)
- return 0;
-
- /* Unless creating, either name of uuid but not both */
- if (cmd != DM_DEV_CREATE_CMD) {
- if ((!*param->uuid && !*param->name) ||
- (*param->uuid && *param->name)) {
- DMWARN("one of name or uuid must be supplied");
- return -EINVAL;
- }
- }
-
- /* Ensure strings are terminated */
- param->name[DM_NAME_LEN - 1] = '\0';
- param->uuid[DM_UUID_LEN - 1] = '\0';
-
- return 0;
-}
-
-static int ctl_ioctl(struct inode *inode, struct file *file,
- uint command, ulong u)
-{
- int r = 0;
- unsigned int cmd;
- struct dm_ioctl *param;
- struct dm_ioctl *user = (struct dm_ioctl *) u;
- ioctl_fn fn = NULL;
-
- /* only root can play with this */
- if (!capable(CAP_SYS_ADMIN))
- return -EACCES;
-
- if (_IOC_TYPE(command) != DM_IOCTL)
- return -ENOTTY;
-
- cmd = _IOC_NR(command);
-
- /*
- * Check the interface version passed in. This also
- * writes out the kernels interface version.
- */
- r = check_version(cmd, user);
- if (r)
- return r;
-
- /*
- * Nothing more to do for the version command.
- */
- if (cmd == DM_VERSION_CMD)
- return 0;
-
- fn = lookup_ioctl(cmd);
- if (!fn) {
- DMWARN("dm_ctl_ioctl: unknown command 0x%x", command);
- return -ENOTTY;
- }
-
- /*
- * Copy the parameters into kernel space.
- */
- r = copy_params(user, &param);
- if (r)
- return r;
-
- r = validate_params(cmd, param);
- if (r) {
- free_params(param);
- return r;
- }
-
- r = fn(param, user);
- free_params(param);
- return r;
-}
-
-static struct file_operations _ctl_fops = {
- .ioctl = ctl_ioctl,
- .owner = THIS_MODULE,
-};
-
-static struct miscdevice _dm_misc = {
- .minor = MISC_DYNAMIC_MINOR,
- .name = DM_NAME,
- .devfs_name = "mapper/control",
- .fops = &_ctl_fops
-};
-
-/*
- * Create misc character device and link to DM_DIR/control.
- */
-int __init dm_interface_init(void)
-{
- int r;
-
- r = dm_hash_init();
- if (r)
- return r;
-
- r = misc_register(&_dm_misc);
- if (r) {
- DMERR("misc_register failed for control device");
- dm_hash_exit();
- return r;
- }
-
- DMINFO("%d.%d.%d%s initialised: %s", DM_VERSION_MAJOR,
- DM_VERSION_MINOR, DM_VERSION_PATCHLEVEL, DM_VERSION_EXTRA,
- DM_DRIVER_EMAIL);
- return 0;
-
- if (misc_deregister(&_dm_misc) < 0)
- DMERR("misc_deregister failed for control device");
- dm_hash_exit();
- return r;
-}
-void dm_interface_exit(void)
-{
- if (misc_deregister(&_dm_misc) < 0)
- DMERR("misc_deregister failed for control device");
- dm_hash_exit();
-}
+#ifdef CONFIG_DM_IOCTL_V4
+#include "dm-ioctl-v4.c"
+#else
+#include "dm-ioctl-v1.c"
+#endif
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
index c62db9e25ffa..942b7e1de7a0 100644
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -48,11 +48,9 @@ struct dm_table {
*/
struct io_restrictions limits;
- /*
- * A waitqueue for processes waiting for something
- * interesting to happen to this table.
- */
- wait_queue_head_t eventq;
+ /* events get handed up using this callback */
+ void (*event_fn)(void *);
+ void *event_context;
};
/*
@@ -222,7 +220,6 @@ int dm_table_create(struct dm_table **result, int mode)
return -ENOMEM;
}
- init_waitqueue_head(&t->eventq);
t->mode = mode;
*result = t;
return 0;
@@ -243,9 +240,6 @@ void table_destroy(struct dm_table *t)
{
unsigned int i;
- /* destroying the table counts as an event */
- dm_table_event(t);
-
/* free the indexes (see dm_table_complete) */
if (t->depth >= 2)
vfree(t->index[t->depth - 2]);
@@ -694,9 +688,22 @@ int dm_table_complete(struct dm_table *t)
return r;
}
+static spinlock_t _event_lock = SPIN_LOCK_UNLOCKED;
+void dm_table_event_callback(struct dm_table *t,
+ void (*fn)(void *), void *context)
+{
+ spin_lock_irq(&_event_lock);
+ t->event_fn = fn;
+ t->event_context = context;
+ spin_unlock_irq(&_event_lock);
+}
+
void dm_table_event(struct dm_table *t)
{
- wake_up_interruptible(&t->eventq);
+ spin_lock(&_event_lock);
+ if (t->event_fn)
+ t->event_fn(t->event_context);
+ spin_unlock(&_event_lock);
}
sector_t dm_table_get_size(struct dm_table *t)
@@ -761,11 +768,6 @@ int dm_table_get_mode(struct dm_table *t)
return t->mode;
}
-void dm_table_add_wait_queue(struct dm_table *t, wait_queue_t *wq)
-{
- add_wait_queue(&t->eventq, wq);
-}
-
void dm_table_suspend_targets(struct dm_table *t)
{
int i;
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index 89e31d2b1a4a..9933e9b71a90 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -62,6 +62,12 @@ struct mapped_device {
* io objects are allocated from here.
*/
mempool_t *io_pool;
+
+ /*
+ * Event handling.
+ */
+ uint32_t event_nr;
+ wait_queue_head_t eventq;
};
#define MIN_IOS 256
@@ -509,6 +515,11 @@ static int dm_request(request_queue_t *q, struct bio *bio)
down_read(&md->lock);
}
+ if (!md->map) {
+ bio_io_error(bio, bio->bi_size);
+ return 0;
+ }
+
__split_bio(md, bio);
up_read(&md->lock);
return 0;
@@ -618,6 +629,8 @@ static struct mapped_device *alloc_dev(unsigned int minor, int persistent)
atomic_set(&md->pending, 0);
init_waitqueue_head(&md->wait);
+ init_waitqueue_head(&md->eventq);
+
return md;
}
@@ -633,6 +646,16 @@ static void free_dev(struct mapped_device *md)
/*
* Bind a table to the device.
*/
+static void event_callback(void *context)
+{
+ struct mapped_device *md = (struct mapped_device *) context;
+
+ down_write(&md->lock);
+ md->event_nr++;
+ wake_up_interruptible(&md->eventq);
+ up_write(&md->lock);
+}
+
static int __bind(struct mapped_device *md, struct dm_table *t)
{
request_queue_t *q = &md->queue;
@@ -644,6 +667,8 @@ static int __bind(struct mapped_device *md, struct dm_table *t)
if (size == 0)
return 0;
+ dm_table_event_callback(md->map, event_callback, md);
+
dm_table_get(t);
dm_table_set_restrictions(t, q);
return 0;
@@ -651,6 +676,10 @@ static int __bind(struct mapped_device *md, struct dm_table *t)
static void __unbind(struct mapped_device *md)
{
+ if (!md->map)
+ return;
+
+ dm_table_event_callback(md->map, NULL, NULL);
dm_table_put(md->map);
md->map = NULL;
set_capacity(md->disk, 0);
@@ -660,35 +689,26 @@ static void __unbind(struct mapped_device *md)
* Constructor for a new device.
*/
static int create_aux(unsigned int minor, int persistent,
- struct dm_table *table, struct mapped_device **result)
+ struct mapped_device **result)
{
- int r;
struct mapped_device *md;
md = alloc_dev(minor, persistent);
if (!md)
return -ENXIO;
- r = __bind(md, table);
- if (r) {
- free_dev(md);
- return r;
- }
- dm_table_resume_targets(md->map);
-
*result = md;
return 0;
}
-int dm_create(struct dm_table *table, struct mapped_device **result)
+int dm_create(struct mapped_device **result)
{
- return create_aux(0, 0, table, result);
+ return create_aux(0, 0, result);
}
-int dm_create_with_minor(unsigned int minor,
- struct dm_table *table, struct mapped_device **result)
+int dm_create_with_minor(unsigned int minor, struct mapped_device **result)
{
- return create_aux(minor, 1, table, result);
+ return create_aux(minor, 1, result);
}
void dm_get(struct mapped_device *md)
@@ -699,7 +719,7 @@ void dm_get(struct mapped_device *md)
void dm_put(struct mapped_device *md)
{
if (atomic_dec_and_test(&md->holders)) {
- if (!test_bit(DMF_SUSPENDED, &md->flags))
+ if (!test_bit(DMF_SUSPENDED, &md->flags) && md->map)
dm_table_suspend_targets(md->map);
__unbind(md);
free_dev(md);
@@ -789,7 +809,8 @@ int dm_suspend(struct mapped_device *md)
down_write(&md->lock);
remove_wait_queue(&md->wait, &wait);
set_bit(DMF_SUSPENDED, &md->flags);
- dm_table_suspend_targets(md->map);
+ if (md->map)
+ dm_table_suspend_targets(md->map);
up_write(&md->lock);
return 0;
@@ -800,7 +821,8 @@ int dm_resume(struct mapped_device *md)
struct deferred_io *def;
down_write(&md->lock);
- if (!test_bit(DMF_SUSPENDED, &md->flags) ||
+ if (!md->map ||
+ !test_bit(DMF_SUSPENDED, &md->flags) ||
!dm_table_get_size(md->map)) {
up_write(&md->lock);
return -EINVAL;
@@ -819,6 +841,42 @@ int dm_resume(struct mapped_device *md)
return 0;
}
+/*-----------------------------------------------------------------
+ * Event notification.
+ *---------------------------------------------------------------*/
+uint32_t dm_get_event_nr(struct mapped_device *md)
+{
+ uint32_t r;
+
+ down_read(&md->lock);
+ r = md->event_nr;
+ up_read(&md->lock);
+
+ return r;
+}
+
+int dm_add_wait_queue(struct mapped_device *md, wait_queue_t *wq,
+ uint32_t event_nr)
+{
+ down_write(&md->lock);
+ if (event_nr != md->event_nr) {
+ up_write(&md->lock);
+ return 1;
+ }
+
+ add_wait_queue(&md->eventq, wq);
+ up_write(&md->lock);
+
+ return 0;
+}
+
+void dm_remove_wait_queue(struct mapped_device *md, wait_queue_t *wq)
+{
+ down_write(&md->lock);
+ remove_wait_queue(&md->eventq, wq);
+ up_write(&md->lock);
+}
+
/*
* The gendisk is only valid as long as you have a reference
* count on 'md'.
@@ -834,7 +892,8 @@ struct dm_table *dm_get_table(struct mapped_device *md)
down_read(&md->lock);
t = md->map;
- dm_table_get(t);
+ if (t)
+ dm_table_get(t);
up_read(&md->lock);
return t;
diff --git a/drivers/md/dm.h b/drivers/md/dm.h
index 1760f0aca7cd..d5deaf13fd80 100644
--- a/drivers/md/dm.h
+++ b/drivers/md/dm.h
@@ -51,9 +51,8 @@ struct mapped_device;
* Functions for manipulating a struct mapped_device.
* Drop the reference with dm_put when you finish with the object.
*---------------------------------------------------------------*/
-int dm_create(struct dm_table *table, struct mapped_device **md);
-int dm_create_with_minor(unsigned int minor, struct dm_table *table,
- struct mapped_device **md);
+int dm_create(struct mapped_device **md);
+int dm_create_with_minor(unsigned int minor, struct mapped_device **md);
/*
* Reference counting for md.
@@ -79,6 +78,14 @@ int dm_swap_table(struct mapped_device *md, struct dm_table *t);
struct dm_table *dm_get_table(struct mapped_device *md);
/*
+ * Event functions.
+ */
+uint32_t dm_get_event_nr(struct mapped_device *md);
+int dm_add_wait_queue(struct mapped_device *md, wait_queue_t *wq,
+ uint32_t event_nr);
+void dm_remove_wait_queue(struct mapped_device *md, wait_queue_t *wq);
+
+/*
* Info functions.
*/
struct gendisk *dm_disk(struct mapped_device *md);
@@ -96,6 +103,8 @@ void dm_table_put(struct dm_table *t);
int dm_table_add_target(struct dm_table *t, const char *type,
sector_t start, sector_t len, char *params);
int dm_table_complete(struct dm_table *t);
+void dm_table_event_callback(struct dm_table *t,
+ void (*fn)(void *), void *context);
void dm_table_event(struct dm_table *t);
sector_t dm_table_get_size(struct dm_table *t);
struct dm_target *dm_table_get_target(struct dm_table *t, unsigned int index);
@@ -104,7 +113,6 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q);
unsigned int dm_table_get_num_targets(struct dm_table *t);
struct list_head *dm_table_get_devices(struct dm_table *t);
int dm_table_get_mode(struct dm_table *t);
-void dm_table_add_wait_queue(struct dm_table *t, wait_queue_t *wq);
void dm_table_suspend_targets(struct dm_table *t);
void dm_table_resume_targets(struct dm_table *t);
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 19b7d611e38e..36411b1447f4 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -1153,7 +1153,7 @@ config ZNET
config SEEQ8005
tristate "SEEQ8005 support (EXPERIMENTAL)"
- depends on NET_ISA && OBSOLETE && EXPERIMENTAL
+ depends on NET_ISA && EXPERIMENTAL
help
This is a driver for the SEEQ 8005 network (Ethernet) card. If this
is for you, read the Ethernet-HOWTO, available from
diff --git a/drivers/net/ni65.c b/drivers/net/ni65.c
index d19f909c1d86..3ddc5e07ae24 100644
--- a/drivers/net/ni65.c
+++ b/drivers/net/ni65.c
@@ -245,6 +245,7 @@ struct priv
int cmdr_addr;
int cardno;
int features;
+ spinlock_t ring_lock;
};
static int ni65_probe1(struct net_device *dev,int);
@@ -299,7 +300,7 @@ static int ni65_open(struct net_device *dev)
int irqval = request_irq(dev->irq, &ni65_interrupt,0,
cards[p->cardno].cardname,dev);
if (irqval) {
- printk ("%s: unable to get IRQ %d (irqval=%d).\n",
+ printk(KERN_ERR "%s: unable to get IRQ %d (irqval=%d).\n",
dev->name,dev->irq, irqval);
return -EAGAIN;
}
@@ -409,12 +410,14 @@ static int __init ni65_probe1(struct net_device *dev,int ioaddr)
p = (struct priv *) dev->priv;
p->cmdr_addr = ioaddr + cards[i].cmd_offset;
p->cardno = i;
+ spin_lock_init(&p->ring_lock);
- printk("%s: %s found at %#3x, ", dev->name, cards[p->cardno].cardname , ioaddr);
+ printk(KERN_INFO "%s: %s found at %#3x, ", dev->name, cards[p->cardno].cardname , ioaddr);
outw(inw(PORT+L_RESET),PORT+L_RESET); /* first: reset the card */
if( (j=readreg(CSR0)) != 0x4) {
- printk(KERN_ERR "can't RESET card: %04x\n",j);
+ printk("failed.\n");
+ printk(KERN_ERR "%s: Can't RESET card: %04x\n", dev->name, j);
ni65_free_buffer(p);
release_region(ioaddr, cards[p->cardno].total_size);
return -EAGAIN;
@@ -467,7 +470,8 @@ static int __init ni65_probe1(struct net_device *dev,int ioaddr)
break;
}
if(i == 5) {
- printk("Can't detect DMA channel!\n");
+ printk("failed.\n");
+ printk(KERN_ERR "%s: Can't detect DMA channel!\n", dev->name);
ni65_free_buffer(p);
release_region(ioaddr, cards[p->cardno].total_size);
return -EAGAIN;
@@ -480,13 +484,13 @@ static int __init ni65_probe1(struct net_device *dev,int ioaddr)
if(dev->irq < 2)
{
- unsigned long irq_mask, delay;
+ unsigned long irq_mask;
ni65_init_lance(p,dev->dev_addr,0,0);
irq_mask = probe_irq_on();
writereg(CSR0_INIT|CSR0_INEA,CSR0); /* trigger interrupt */
- delay = jiffies + HZ/50;
- while (time_before(jiffies, delay)) ;
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(HZ/50);
dev->irq = probe_irq_off(irq_mask);
if(!dev->irq)
{
@@ -503,7 +507,7 @@ static int __init ni65_probe1(struct net_device *dev,int ioaddr)
if(request_dma(dev->dma, cards[p->cardno].cardname ) != 0)
{
- printk("%s: Can't request dma-channel %d\n",dev->name,(int) dev->dma);
+ printk(KERN_ERR "%s: Can't request dma-channel %d\n",dev->name,(int) dev->dma);
ni65_free_buffer(p);
release_region(ioaddr, cards[p->cardno].total_size);
return -EAGAIN;
@@ -570,7 +574,7 @@ static void *ni65_alloc_mem(struct net_device *dev,char *what,int size,int type)
if(type) {
ret = skb = alloc_skb(2+16+size,GFP_KERNEL|GFP_DMA);
if(!skb) {
- printk("%s: unable to allocate %s memory.\n",dev->name,what);
+ printk(KERN_WARNING "%s: unable to allocate %s memory.\n",dev->name,what);
return NULL;
}
skb->dev = dev;
@@ -581,12 +585,12 @@ static void *ni65_alloc_mem(struct net_device *dev,char *what,int size,int type)
else {
ret = ptr = kmalloc(T_BUF_SIZE,GFP_KERNEL | GFP_DMA);
if(!ret) {
- printk("%s: unable to allocate %s memory.\n",dev->name,what);
+ printk(KERN_WARNING "%s: unable to allocate %s memory.\n",dev->name,what);
return NULL;
}
}
if( (u32) virt_to_phys(ptr+size) > 0x1000000) {
- printk("%s: unable to allocate %s memory in lower 16MB!\n",dev->name,what);
+ printk(KERN_WARNING "%s: unable to allocate %s memory in lower 16MB!\n",dev->name,what);
if(type)
kfree_skb(skb);
else
@@ -692,7 +696,7 @@ static void ni65_stop_start(struct net_device *dev,struct priv *p)
writedatareg(CSR0_STOP);
if(debuglevel > 1)
- printk("ni65_stop_start\n");
+ printk(KERN_DEBUG "ni65_stop_start\n");
if(p->features & INIT_RING_BEFORE_START) {
int i;
@@ -846,6 +850,8 @@ static irqreturn_t ni65_interrupt(int irq, void * dev_id, struct pt_regs * regs)
p = (struct priv *) dev->priv;
+ spin_lock(&p->ring_lock);
+
while(--bcnt) {
csr0 = inw(PORT+L_DATAREG);
@@ -867,7 +873,7 @@ static irqreturn_t ni65_interrupt(int irq, void * dev_id, struct pt_regs * regs)
{
struct priv *p = (struct priv *) dev->priv;
if(debuglevel > 1)
- printk("%s: general error: %04x.\n",dev->name,csr0);
+ printk(KERN_ERR "%s: general error: %04x.\n",dev->name,csr0);
if(csr0 & CSR0_BABL)
p->stats.tx_errors++;
if(csr0 & CSR0_MISS) {
@@ -879,7 +885,7 @@ static irqreturn_t ni65_interrupt(int irq, void * dev_id, struct pt_regs * regs)
}
if(csr0 & CSR0_MERR) {
if(debuglevel > 1)
- printk("%s: Ooops .. memory error: %04x.\n",dev->name,csr0);
+ printk(KERN_ERR "%s: Ooops .. memory error: %04x.\n",dev->name,csr0);
ni65_stop_start(dev,p);
}
}
@@ -932,12 +938,13 @@ static irqreturn_t ni65_interrupt(int irq, void * dev_id, struct pt_regs * regs)
#endif
if( (csr0 & (CSR0_RXON | CSR0_TXON)) != (CSR0_RXON | CSR0_TXON) ) {
- printk("%s: RX or TX was offline -> restart\n",dev->name);
+ printk(KERN_DEBUG "%s: RX or TX was offline -> restart\n",dev->name);
ni65_stop_start(dev,p);
}
else
writedatareg(CSR0_INEA);
+ spin_unlock(&p->ring_lock);
return IRQ_HANDLED;
}
@@ -1147,9 +1154,7 @@ static int ni65_send_packet(struct sk_buff *skb, struct net_device *dev)
memset((char *)p->tmdbounce[p->tmdbouncenum]+skb->len, 0, len-skb->len);
dev_kfree_skb (skb);
- save_flags(flags);
- cli();
-
+ spin_lock_irqsave(&p->ring_lock, flags);
tmdp = p->tmdhead + p->tmdnum;
tmdp->u.buffer = (u32) isa_virt_to_bus(p->tmdbounce[p->tmdbouncenum]);
p->tmdbouncenum = (p->tmdbouncenum + 1) & (TMDNUM - 1);
@@ -1157,8 +1162,7 @@ static int ni65_send_packet(struct sk_buff *skb, struct net_device *dev)
#ifdef XMT_VIA_SKB
}
else {
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&p->ring_lock, flags);
tmdp = p->tmdhead + p->tmdnum;
tmdp->u.buffer = (u32) isa_virt_to_bus(skb->data);
@@ -1178,8 +1182,8 @@ static int ni65_send_packet(struct sk_buff *skb, struct net_device *dev)
p->lock = 0;
dev->trans_start = jiffies;
-
- restore_flags(flags);
+
+ spin_unlock_irqrestore(&p->ring_lock, flags);
}
return 0;
@@ -1238,10 +1242,8 @@ void cleanup_module(void)
{
struct priv *p;
p = (struct priv *) dev_ni65.priv;
- if(!p) {
- printk("Ooops .. no private struct\n");
- return;
- }
+ if(!p)
+ BUG();
disable_dma(dev_ni65.dma);
free_dma(dev_ni65.dma);
unregister_netdev(&dev_ni65);
@@ -1250,6 +1252,7 @@ void cleanup_module(void)
dev_ni65.priv = NULL;
}
#endif /* MODULE */
+
MODULE_LICENSE("GPL");
/*
diff --git a/drivers/net/ni65.h b/drivers/net/ni65.h
index 6208f8a3fcd8..b01cef1b62c1 100644
--- a/drivers/net/ni65.h
+++ b/drivers/net/ni65.h
@@ -20,32 +20,32 @@
#define CSR0_BABL 0x4000 /* Babble transmitter timeout error (RC) */
#define CSR0_CERR 0x2000 /* Collision Error (RC) */
#define CSR0_MISS 0x1000 /* Missed packet (RC) */
-#define CSR0_MERR 0x0800 /* Memory Error (RC) */
+#define CSR0_MERR 0x0800 /* Memory Error (RC) */
#define CSR0_RINT 0x0400 /* Receiver Interrupt (RC) */
-#define CSR0_TINT 0x0200 /* Transmit Interrupt (RC) */
+#define CSR0_TINT 0x0200 /* Transmit Interrupt (RC) */
#define CSR0_IDON 0x0100 /* Initialization Done (RC) */
#define CSR0_INTR 0x0080 /* Interrupt Flag (R) */
#define CSR0_INEA 0x0040 /* Interrupt Enable (RW) */
#define CSR0_RXON 0x0020 /* Receiver on (R) */
-#define CSR0_TXON 0x0010 /* Transmitter on (R) */
+#define CSR0_TXON 0x0010 /* Transmitter on (R) */
#define CSR0_TDMD 0x0008 /* Transmit Demand (RS) */
-#define CSR0_STOP 0x0004 /* Stop (RS) */
+#define CSR0_STOP 0x0004 /* Stop (RS) */
#define CSR0_STRT 0x0002 /* Start (RS) */
#define CSR0_INIT 0x0001 /* Initialize (RS) */
-#define CSR0_CLRALL 0x7f00 /* mask for all clearable bits */
+#define CSR0_CLRALL 0x7f00 /* mask for all clearable bits */
/*
* Initialization Block Mode operation Bit Definitions.
*/
#define M_PROM 0x8000 /* Promiscuous Mode */
-#define M_INTL 0x0040 /* Internal Loopback */
-#define M_DRTY 0x0020 /* Disable Retry */
+#define M_INTL 0x0040 /* Internal Loopback */
+#define M_DRTY 0x0020 /* Disable Retry */
#define M_COLL 0x0010 /* Force Collision */
#define M_DTCR 0x0008 /* Disable Transmit CRC) */
#define M_LOOP 0x0004 /* Loopback */
-#define M_DTX 0x0002 /* Disable the Transmitter */
-#define M_DRX 0x0001 /* Disable the Receiver */
+#define M_DTX 0x0002 /* Disable the Transmitter */
+#define M_DRX 0x0001 /* Disable the Receiver */
/*
@@ -56,7 +56,7 @@
#define RCV_ERR 0x40 /* Error Summary */
#define RCV_FRAM 0x20 /* Framing Error */
#define RCV_OFLO 0x10 /* Overflow Error */
-#define RCV_CRC 0x08 /* CRC Error */
+#define RCV_CRC 0x08 /* CRC Error */
#define RCV_BUF_ERR 0x04 /* Buffer Error */
#define RCV_START 0x02 /* Start of Packet */
#define RCV_END 0x01 /* End of Packet */
@@ -67,7 +67,7 @@
*/
#define XMIT_OWN 0x80 /* owner bit 0 = host, 1 = lance */
-#define XMIT_ERR 0x40 /* Error Summary */
+#define XMIT_ERR 0x40 /* Error Summary */
#define XMIT_RETRY 0x10 /* more the 1 retry needed to Xmit */
#define XMIT_1_RETRY 0x08 /* one retry needed to Xmit */
#define XMIT_DEF 0x04 /* Deferred */
@@ -78,53 +78,44 @@
* transmit status (2) (valid if XMIT_ERR == 1)
*/
-#define XMIT_TDRMASK 0x03ff /* time-domain-reflectometer-value */
-#define XMIT_RTRY 0x0400 /* Failed after 16 retransmissions */
-#define XMIT_LCAR 0x0800 /* Loss of Carrier */
-#define XMIT_LCOL 0x1000 /* Late collision */
-#define XMIT_RESERV 0x2000 /* Reserved */
-#define XMIT_UFLO 0x4000 /* Underflow (late memory) */
-#define XMIT_BUFF 0x8000 /* Buffering error (no ENP) */
-
-struct init_block
-{
- unsigned short mode;
- unsigned char eaddr[6];
- unsigned char filter[8];
- /* bit 29-31: number of rmd's (power of 2) */
- u32 rrp; /* receive ring pointer (align 8) */
- /* bit 29-31: number of tmd's (power of 2) */
- u32 trp; /* transmit ring pointer (align 8) */
+#define XMIT_TDRMASK 0x03ff /* time-domain-reflectometer-value */
+#define XMIT_RTRY 0x0400 /* Failed after 16 retransmissions */
+#define XMIT_LCAR 0x0800 /* Loss of Carrier */
+#define XMIT_LCOL 0x1000 /* Late collision */
+#define XMIT_RESERV 0x2000 /* Reserved */
+#define XMIT_UFLO 0x4000 /* Underflow (late memory) */
+#define XMIT_BUFF 0x8000 /* Buffering error (no ENP) */
+
+struct init_block {
+ unsigned short mode;
+ unsigned char eaddr[6];
+ unsigned char filter[8];
+ /* bit 29-31: number of rmd's (power of 2) */
+ u32 rrp; /* receive ring pointer (align 8) */
+ /* bit 29-31: number of tmd's (power of 2) */
+ u32 trp; /* transmit ring pointer (align 8) */
};
-struct rmd /* Receive Message Descriptor */
-{
- union
- {
- volatile u32 buffer;
- struct
- {
- volatile unsigned char dummy[3];
- volatile unsigned char status;
- } s;
- } u;
- volatile short blen;
- volatile unsigned short mlen;
+struct rmd { /* Receive Message Descriptor */
+ union {
+ volatile u32 buffer;
+ struct {
+ volatile unsigned char dummy[3];
+ volatile unsigned char status;
+ } s;
+ } u;
+ volatile short blen;
+ volatile unsigned short mlen;
};
-struct tmd
-{
- union
- {
- volatile u32 buffer;
- struct
- {
- volatile unsigned char dummy[3];
- volatile unsigned char status;
- } s;
- } u;
- volatile unsigned short blen;
- volatile unsigned short status2;
+struct tmd {
+ union {
+ volatile u32 buffer;
+ struct {
+ volatile unsigned char dummy[3];
+ volatile unsigned char status;
+ } s;
+ } u;
+ volatile unsigned short blen;
+ volatile unsigned short status2;
};
-
-
diff --git a/drivers/net/pcmcia/Kconfig b/drivers/net/pcmcia/Kconfig
index 1f68bd86ace0..c317cccbd6b6 100644
--- a/drivers/net/pcmcia/Kconfig
+++ b/drivers/net/pcmcia/Kconfig
@@ -113,7 +113,7 @@ config PCMCIA_XIRC2PS
If unsure, say N.
config PCMCIA_AXNET
- tristate "broken NS8390-cards support"
+ tristate "Asix AX88190 PCMCIA support"
depends on NET_PCMCIA && PCMCIA
---help---
Say Y here if you intend to attach an Asix AX88190-based PCMCIA
diff --git a/drivers/net/seeq8005.c b/drivers/net/seeq8005.c
index 08cd543eda47..aeb0ffe105a8 100644
--- a/drivers/net/seeq8005.c
+++ b/drivers/net/seeq8005.c
@@ -700,7 +700,8 @@ static void hardware_send_packet(struct net_device * dev, char *buf, int length)
* wait_for_buffer
*
* This routine waits for the SEEQ chip to assert that the FIFO is ready
- * by checking for a window interrupt, and then clearing it
+ * by checking for a window interrupt, and then clearing it. This has to
+ * occur in the interrupt handler!
*/
inline void wait_for_buffer(struct net_device * dev)
{
@@ -710,7 +711,7 @@ inline void wait_for_buffer(struct net_device * dev)
tmp = jiffies + HZ;
while ( ( ((status=inw(SEEQ_STATUS)) & SEEQSTAT_WINDOW_INT) != SEEQSTAT_WINDOW_INT) && time_before(jiffies, tmp))
- mb();
+ cpu_relax();
if ( (status & SEEQSTAT_WINDOW_INT) == SEEQSTAT_WINDOW_INT)
outw( SEEQCMD_WINDOW_INT_ACK | (status & SEEQCMD_INT_MASK), SEEQ_CMD);
diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c
index b07f5e06ef19..48dbbe3bda56 100644
--- a/drivers/parport/parport_pc.c
+++ b/drivers/parport/parport_pc.c
@@ -94,7 +94,8 @@ static struct superio_struct { /* For Super-IO chips autodetection */
} superios[NR_SUPERIOS] __devinitdata = { {0,},};
static int user_specified __devinitdata = 0;
-#if defined(CONFIG_PARPORT_PC_FIFO) || defined(CONFIG_PARPORT_PC_SUPERIO)
+#if defined(CONFIG_PARPORT_PC_SUPERIO) || \
+ (defined(CONFIG_PARPORT_1284) && defined(CONFIG_PARPORT_PC_FIFO))
static int verbose_probing;
#endif
static int registered_parport;
@@ -3116,7 +3117,8 @@ MODULE_PARM_DESC(irq, "IRQ line");
MODULE_PARM(irq, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "s");
MODULE_PARM_DESC(dma, "DMA channel");
MODULE_PARM(dma, "1-" __MODULE_STRING(PARPORT_PC_MAX_PORTS) "s");
-#if defined(CONFIG_PARPORT_PC_FIFO) || defined(CONFIG_PARPORT_PC_SUPERIO)
+#if defined(CONFIG_PARPORT_PC_SUPERIO) || \
+ (defined(CONFIG_PARPORT_1284) && defined(CONFIG_PARPORT_PC_FIFO))
MODULE_PARM_DESC(verbose_probing, "Log chit-chat during initialisation");
MODULE_PARM(verbose_probing, "i");
#endif
diff --git a/drivers/pcmcia/ricoh.h b/drivers/pcmcia/ricoh.h
index dcfcbd4328b3..9f9c688d20eb 100644
--- a/drivers/pcmcia/ricoh.h
+++ b/drivers/pcmcia/ricoh.h
@@ -116,6 +116,8 @@
#define RL5C4XX_CMD_SHIFT 4
#define RL5C4XX_HOLD_MASK 0x1c00
#define RL5C4XX_HOLD_SHIFT 10
+#define RL5C4XX_MISC_CONTROL 0x2F /* 8 bit */
+#define RL5C4XX_ZV_ENABLE 0x08
#ifdef __YENTA_H
@@ -125,10 +127,41 @@
#define rl_mem(socket) ((socket)->private[3])
#define rl_config(socket) ((socket)->private[4])
+static void ricoh_zoom_video(struct pcmcia_socket *sock, int onoff)
+{
+ u8 reg;
+ struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket);
+
+ reg = config_readb(socket, RL5C4XX_MISC_CONTROL);
+ if (onoff)
+ /* Zoom zoom, we will all go together, zoom zoom, zoom zoom */
+ reg |= RL5C4XX_ZV_ENABLE;
+ else
+ reg &= ~RL5C4XX_ZV_ENABLE;
+
+ config_writeb(socket, RL5C4XX_MISC_CONTROL, reg);
+}
+
+static void ricoh_set_zv(struct pcmcia_socket *sock)
+{
+ struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket);
+ if(socket->dev->vendor == PCI_VENDOR_ID_RICOH)
+ {
+ switch(socket->dev->device)
+ {
+ /* There may be more .. */
+ case PCI_DEVICE_ID_RICOH_RL5C478:
+ sock->zoom_video = ricoh_zoom_video;
+ break;
+ }
+ }
+}
+
static int ricoh_init(struct pcmcia_socket *sock)
{
struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket);
yenta_init(sock);
+ ricoh_set_zv(sock);
config_writew(socket, RL5C4XX_MISC, rl_misc(socket));
config_writew(socket, RL5C4XX_16BIT_CTL, rl_ctl(socket));
diff --git a/drivers/pcmcia/ti113x.h b/drivers/pcmcia/ti113x.h
index 2cdb46d4eb3c..4a0099518a76 100644
--- a/drivers/pcmcia/ti113x.h
+++ b/drivers/pcmcia/ti113x.h
@@ -148,14 +148,96 @@ static int ti_intctl(struct yenta_socket *socket)
return 0;
}
+/*
+ * Zoom video control for TI122x/113x chips
+ */
+
+static void ti_zoom_video(struct pcmcia_socket *sock, int onoff)
+{
+ u8 reg;
+ struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket);
+
+ /* If we don't have a Zoom Video switch this is harmless,
+ we just tristate the unused (ZV) lines */
+ reg = config_readb(socket, TI113X_CARD_CONTROL);
+ if (onoff)
+ /* Zoom zoom, we will all go together, zoom zoom, zoom zoom */
+ reg |= TI113X_CCR_ZVENABLE;
+ else
+ reg &= ~TI113X_CCR_ZVENABLE;
+ config_writeb(socket, TI113X_CARD_CONTROL, reg);
+}
+
+/*
+ * The 145x series can also use this. They have an additional
+ * ZV autodetect mode we don't use but don't actually need.
+ * FIXME: manual says its in func0 and func1 but disagrees with
+ * itself about this - do we need to force func0, if so we need
+ * to know a lot more about socket pairings in pcmcia_socket than
+ * we do now.. uggh.
+ */
+
+static void ti1250_zoom_video(struct pcmcia_socket *sock, int onoff)
+{
+ struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket);
+ int shift = 0;
+ u8 reg;
+
+ ti_zoom_video(sock, onoff);
+
+ reg = config_readb(socket, 0x84);
+ reg |= (1<<7); /* ZV bus enable */
+
+ if(PCI_FUNC(socket->dev->devfn)==1)
+ shift = 1;
+
+ if(onoff)
+ {
+ reg &= ~(1<<6); /* Clear select bit */
+ reg |= shift<<6; /* Favour our socket */
+ reg |= 1<<shift; /* Socket zoom video on */
+ }
+ else
+ {
+ reg &= ~(1<<6); /* Clear select bit */
+ reg |= (1^shift)<<6; /* Favour other socket */
+ reg &= ~(1<<shift); /* Socket zoon video off */
+ }
+
+ config_writeb(socket, 0x84, reg);
+}
+
+static void ti_set_zv(struct pcmcia_socket *sock)
+{
+ struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket);
+ if(socket->dev->vendor == PCI_VENDOR_ID_TI)
+ {
+ switch(socket->dev->device)
+ {
+ /* There may be more .. */
+ case PCI_DEVICE_ID_TI_1220:
+ case PCI_DEVICE_ID_TI_1221:
+ case PCI_DEVICE_ID_TI_1225:
+ sock->zoom_video = ti_zoom_video;
+ break;
+ case PCI_DEVICE_ID_TI_1250:
+ case PCI_DEVICE_ID_TI_1251A:
+ case PCI_DEVICE_ID_TI_1251B:
+ case PCI_DEVICE_ID_TI_1450:
+ sock->zoom_video = ti1250_zoom_video;
+ }
+ }
+}
static int ti_init(struct pcmcia_socket *sock)
{
struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket);
yenta_init(sock);
+ ti_set_zv(sock);
ti_intctl(socket);
return 0;
}
+
/*
* Generic TI init - TI has an extension for the
* INTCTL register that sets the PCI CSC interrupt.
@@ -176,9 +258,6 @@ static int ti_override(struct yenta_socket *socket)
if (new != reg)
exca_writeb(socket, I365_INTCTL, new);
-#if 0
- /* THIS CAUSES HANGS! Disabled for now, do not know why */
-
/*
* If ISA interrupts don't work, then fall back to routing card
* interrupts to the PCI interrupt of the socket.
@@ -190,7 +269,7 @@ static int ti_override(struct yenta_socket *socket)
u8 irqmux, devctl;
devctl = config_readb(socket, TI113X_DEVICE_CONTROL);
- if (devctl & TI113X_DCR_IMODE_MASK != TI12XX_DCR_IMODE_ALL_SERIAL) {
+ if ((devctl & TI113X_DCR_IMODE_MASK) != TI12XX_DCR_IMODE_ALL_SERIAL) {
printk (KERN_INFO "ti113x: Routing card interrupts to PCI\n");
devctl &= ~TI113X_DCR_IMODE_MASK;
@@ -203,7 +282,6 @@ static int ti_override(struct yenta_socket *socket)
config_writeb(socket, TI113X_DEVICE_CONTROL, devctl);
}
}
-#endif
socket->socket.ops->init = ti_init;
return 0;
@@ -220,6 +298,7 @@ static int ti113x_init(struct pcmcia_socket *sock)
{
struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket);
yenta_init(sock);
+ ti_set_zv(sock);
config_writel(socket, TI113X_SYSTEM_CONTROL, ti_sysctl(socket));
config_writeb(socket, TI113X_CARD_CONTROL, ti_cardctl(socket));
@@ -248,6 +327,7 @@ static int ti1250_init(struct pcmcia_socket *sock)
struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket);
yenta_init(sock);
ti113x_init(sock);
+ ti_set_zv(sock);
ti_irqmux(socket) = config_readl(socket, TI122X_IRQMUX);
ti_irqmux(socket) = (ti_irqmux(socket) & ~0x0f) | 0x02; /* route INTA */
if (!(ti_sysctl(socket) & TI122X_SCR_INTRTIE))
diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c
index 707cb7297fc5..5056a66e3ff1 100644
--- a/drivers/pcmcia/yenta_socket.c
+++ b/drivers/pcmcia/yenta_socket.c
@@ -297,6 +297,8 @@ static int yenta_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
}
exca_writeb(socket, I365_CSCINT, reg);
exca_readb(socket, I365_CSC);
+ if(sock->zoom_video)
+ sock->zoom_video(sock, state->flags & SS_ZVCARD);
}
config_writew(socket, CB_BRIDGE_CONTROL, bridge);
/* Socket event mask: get card insert/remove events.. */
diff --git a/drivers/pnp/isapnp/core.c b/drivers/pnp/isapnp/core.c
index 967f95bd4ac3..b8e973c99b9f 100644
--- a/drivers/pnp/isapnp/core.c
+++ b/drivers/pnp/isapnp/core.c
@@ -255,14 +255,22 @@ static void __init isapnp_peek(unsigned char *data, int bytes)
static int isapnp_next_rdp(void)
{
int rdp = isapnp_rdp;
+ static int old_rdp = 0;
+
+ if(old_rdp)
+ {
+ release_region(old_rdp, 1);
+ old_rdp = 0;
+ }
while (rdp <= 0x3ff) {
/*
* We cannot use NE2000 probe spaces for ISAPnP or we
* will lock up machines.
*/
- if ((rdp < 0x280 || rdp > 0x380) && !check_region(rdp, 1))
+ if ((rdp < 0x280 || rdp > 0x380) && request_region(rdp, 1, "ISAPnP"))
{
isapnp_rdp = rdp;
+ old_rdp = rdp;
return 0;
}
rdp += RDP_STEP;
diff --git a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c
index 3e70fb999f56..c2fce462e847 100644
--- a/drivers/scsi/53c700.c
+++ b/drivers/scsi/53c700.c
@@ -172,7 +172,7 @@ STATIC void NCR_700_chip_reset(struct Scsi_Host *host);
STATIC int NCR_700_slave_configure(Scsi_Device *SDpnt);
STATIC void NCR_700_slave_destroy(Scsi_Device *SDpnt);
-static struct device_attribute **NCR_700_dev_attrs = NULL;
+STATIC struct device_attribute *NCR_700_dev_attrs[];
static char *NCR_700_phase[] = {
"",
@@ -2027,25 +2027,12 @@ static struct device_attribute NCR_700_active_tags_attr = {
.show = NCR_700_show_active_tags,
};
-STATIC int __init
-NCR_700_init(void)
-{
- scsi_sysfs_modify_sdev_attribute(&NCR_700_dev_attrs,
- &NCR_700_queue_depth_attr);
- scsi_sysfs_modify_sdev_attribute(&NCR_700_dev_attrs,
- &NCR_700_active_tags_attr);
- return 0;
-}
-
-/* NULL exit routine to keep modutils happy */
-STATIC void __exit
-NCR_700_exit(void)
-{
-}
+STATIC struct device_attribute *NCR_700_dev_attrs[] = {
+ &NCR_700_queue_depth_attr,
+ &NCR_700_active_tags_attr,
+ NULL,
+};
EXPORT_SYMBOL(NCR_700_detect);
EXPORT_SYMBOL(NCR_700_release);
EXPORT_SYMBOL(NCR_700_intr);
-
-module_init(NCR_700_init);
-module_exit(NCR_700_exit);
diff --git a/drivers/scsi/NCR_D700.c b/drivers/scsi/NCR_D700.c
index f1eb7aaf22e4..7bff5570b6a0 100644
--- a/drivers/scsi/NCR_D700.c
+++ b/drivers/scsi/NCR_D700.c
@@ -218,7 +218,8 @@ NCR_D700_probe_one(struct NCR_D700_private *p, int siop,
goto irq_failed;
}
- scsi_add_host(host, p->dev);
+ scsi_add_host(host, p->dev); /* XXX handle failure */
+ scsi_scan_host(host);
p->hosts[siop] = host;
hostdata->dev = p->dev;
@@ -387,7 +388,6 @@ static int __init NCR_D700_init(void)
static void __exit NCR_D700_exit(void)
{
mca_unregister_driver(&NCR_D700_driver);
- scsi_sysfs_release_attributes(&NCR_D700_driver_template);
}
module_init(NCR_D700_init);
diff --git a/drivers/scsi/NCR_Q720.c b/drivers/scsi/NCR_Q720.c
index c45c353cc9ad..b7d3b5264223 100644
--- a/drivers/scsi/NCR_Q720.c
+++ b/drivers/scsi/NCR_Q720.c
@@ -85,6 +85,7 @@ NCR_Q720_probe_one(struct NCR_Q720_private *p, int siop,
__u8 scsr1 = readb(vaddr + NCR_Q720_SCSR_OFFSET + 1);
__u8 differential = readb(vaddr + NCR_Q720_SCSR_OFFSET) & 0x20;
__u8 version;
+ int error;
scsi_id = scsr1 >> 4;
/* enable burst length 16 (FIXME: should allow this) */
@@ -120,9 +121,12 @@ NCR_Q720_probe_one(struct NCR_Q720_private *p, int siop,
scsr1 &= ~0x01;
writeb(scsr1, vaddr + NCR_Q720_SCSR_OFFSET + 1);
- scsi_add_host(p->hosts[siop], p->dev);
-
- return 0;
+ error = scsi_add_host(p->hosts[siop], p->dev);
+ if (error)
+ ncr53c8xx_release(p->hosts[siop]);
+ else
+ scsi_scan_host(p->hosts[siop]);
+ return error;
fail:
return -ENODEV;
@@ -347,7 +351,6 @@ static void __exit
NCR_Q720_exit(void)
{
mca_unregister_driver(&NCR_Q720_driver);
- //scsi_sysfs_release_attributes(&NCR_Q720_driver_template);
}
module_init(NCR_Q720_init);
diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c
index ee380d8b0ba6..5618e688d6c3 100644
--- a/drivers/scsi/aha152x.c
+++ b/drivers/scsi/aha152x.c
@@ -939,7 +939,8 @@ static irqreturn_t swintr(int irqno, void *dev_id, struct pt_regs *regs)
struct Scsi_Host *shpnt = lookup_irq(irqno);
if (!shpnt) {
- printk(KERN_ERR "aha152x%d: catched software interrupt %d for unknown controller.\n", HOSTNO, irqno);
+ /* no point using HOSTNO here! */
+ printk(KERN_ERR "aha152x: catched software interrupt %d for unknown controller.\n", irqno);
return IRQ_NONE;
}
@@ -1047,6 +1048,10 @@ struct Scsi_Host *aha152x_probe_one(struct aha152x_setup *setup)
printk(KERN_INFO "aha152x%d: trying software interrupt, ",
shost->host_no);
+
+ /* need to have host registered before triggering any interrupt */
+ aha152x_host[registered_count] = shost;
+ mb();
SETPORT(DMACNTRL0, SWINT|INTEN);
mdelay(1000);
free_irq(shost->irq, shost);
@@ -1062,7 +1067,7 @@ struct Scsi_Host *aha152x_probe_one(struct aha152x_setup *setup)
printk(KERN_ERR "aha152x%d: IRQ %d possibly wrong. "
"Please verify.\n", shost->host_no, shost->irq);
- goto out_release_region;
+ goto out_unregister_host;
}
printk("ok.\n");
@@ -1075,12 +1080,12 @@ struct Scsi_Host *aha152x_probe_one(struct aha152x_setup *setup)
"aha152x", shost) < 0) {
printk(KERN_ERR "aha152x%d: failed to reassign interrupt.\n",
shost->host_no);
- goto out_release_region;
+ goto out_unregister_host;
}
-
- aha152x_host[registered_count] = shost;
return shost; /* the pcmcia stub needs the return value; */
+out_unregister_host:
+ aha152x_host[registered_count] = NULL;
out_release_region:
release_region(shost->io_port, IO_RANGE);
out_unregister:
diff --git a/drivers/scsi/aha1542.h b/drivers/scsi/aha1542.h
index abe66b3e82da..9c8c731d7186 100644
--- a/drivers/scsi/aha1542.h
+++ b/drivers/scsi/aha1542.h
@@ -130,7 +130,6 @@ struct ccb { /* Command Control Block 5.3 */
};
static int aha1542_detect(Scsi_Host_Template *);
-static int aha1542_command(Scsi_Cmnd *);
static int aha1542_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
static int aha1542_abort(Scsi_Cmnd * SCpnt);
static int aha1542_bus_reset(Scsi_Cmnd * SCpnt);
diff --git a/drivers/scsi/aha1740.c b/drivers/scsi/aha1740.c
index fe22bc364faf..9b1e7cace348 100644
--- a/drivers/scsi/aha1740.c
+++ b/drivers/scsi/aha1740.c
@@ -375,7 +375,7 @@ static int aha1740_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
#endif
/* locate an available ecb */
- spin_lock_irqsave(&SCpnt->device->host->host_lock, flags);
+ spin_lock_irqsave(SCpnt->device->host->host_lock, flags);
ecbno = host->last_ecb_used + 1; /* An optimization */
if (ecbno >= AHA1740_ECBS)
ecbno = 0;
@@ -394,7 +394,7 @@ static int aha1740_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
doubles as reserved flag */
host->last_ecb_used = ecbno;
- spin_unlock_irqrestore(&SCpnt->device->host->host_lock, flags);
+ spin_unlock_irqrestore(SCpnt->device->host->host_lock, flags);
#ifdef DEBUG
printk("Sending command (%d %x)...", ecbno, done);
@@ -491,7 +491,7 @@ static int aha1740_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
unsigned int base = SCpnt->device->host->io_port;
DEB(printk("aha1740[%d] critical section\n",ecbno));
- spin_lock_irqsave(&SCpnt->device->host->host_lock, flags);
+ spin_lock_irqsave(SCpnt->device->host->host_lock, flags);
for (loopcnt = 0; ; loopcnt++) {
if (inb(G2STAT(base)) & G2STAT_MBXOUT) break;
if (loopcnt == LOOPCNT_WARN) {
@@ -511,7 +511,7 @@ static int aha1740_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
panic("aha1740.c: attn wait failed!\n");
}
outb(ATTN_START | (target & 7), ATTN(base)); /* Start it up */
- spin_unlock_irqrestore(&SCpnt->device->host->host_lock, flags);
+ spin_unlock_irqrestore(SCpnt->device->host->host_lock, flags);
DEB(printk("aha1740[%d] request queued.\n",ecbno));
} else
printk(KERN_ALERT "aha1740_queuecommand: done can't be NULL\n");
@@ -594,7 +594,7 @@ static int aha1740_probe (struct device *dev)
if (!request_region(slotbase, SLOTSIZE, "aha1740")) /* See if in use */
return -EBUSY;
if (!aha1740_test_port(slotbase))
- goto err_release;
+ goto err_release_region;
aha1740_getconfig(slotbase,&irq_level,&translation);
if ((inb(G2STAT(slotbase)) &
(G2STAT_MBXOUT|G2STAT_BUSY)) != G2STAT_MBXOUT) {
@@ -609,7 +609,7 @@ static int aha1740_probe (struct device *dev)
shpnt = scsi_host_alloc(&aha1740_template,
sizeof(struct aha1740_hostdata));
if(shpnt == NULL)
- goto err_release;
+ goto err_release_region;
shpnt->base = 0;
shpnt->io_port = slotbase;
@@ -625,21 +625,27 @@ static int aha1740_probe (struct device *dev)
if (!host->ecb_dma_addr) {
printk (KERN_ERR "aha1740_probe: Couldn't map ECB, giving up\n");
scsi_unregister (shpnt);
- goto err_release;
+ goto err_host_put;
}
DEB(printk("aha1740_probe: enable interrupt channel %d\n",irq_level));
if (request_irq(irq_level,aha1740_intr_handle,0,"aha1740",shpnt)) {
printk(KERN_ERR "aha1740_probe: Unable to allocate IRQ %d.\n",
irq_level);
- goto err_release;
+ goto err_unmap;
}
eisa_set_drvdata (edev, shpnt);
- scsi_add_host (shpnt, dev);
+ scsi_add_host (shpnt, dev); /* XXX handle failure */
+ scsi_scan_host (shpnt);
return 0;
- err_release:
+ err_unmap:
+ dma_unmap_single (&edev->dev, host->ecb_dma_addr,
+ sizeof (host->ecb), DMA_BIDIRECTIONAL);
+ err_host_put:
+ scsi_host_put (shpnt);
+ err_release_region:
release_region(slotbase, SLOTSIZE);
return -ENODEV;
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c
index c50c2bb46973..1b87b2aac104 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.c
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.c
@@ -2173,7 +2173,8 @@ ahd_linux_register_host(struct ahd_softc *ahd, Scsi_Host_Template *template)
ahd_unlock(ahd, &s);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
- scsi_add_host(host, &ahd->dev_softc->dev);
+ scsi_add_host(host, &ahd->dev_softc->dev); /* XXX handle failure */
+ scsi_scan_host(host);
#endif
return (0);
}
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c
index a2ec0a94f44c..8c1e4086a808 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c
@@ -1811,7 +1811,8 @@ ahc_linux_register_host(struct ahc_softc *ahc, Scsi_Host_Template *template)
ahc_unlock(ahc, &s);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
- scsi_add_host(host, (ahc->dev_softc ? &ahc->dev_softc->dev : NULL));
+ scsi_add_host(host, (ahc->dev_softc ? &ahc->dev_softc->dev : NULL)); /* XXX handle failure */
+ scsi_scan_host(host);
#endif
return (0);
}
diff --git a/drivers/scsi/arm/acornscsi.c b/drivers/scsi/arm/acornscsi.c
index 7ac9e317ec51..a0452a6c6122 100644
--- a/drivers/scsi/arm/acornscsi.c
+++ b/drivers/scsi/arm/acornscsi.c
@@ -3043,9 +3043,13 @@ acornscsi_probe(struct expansion_card *ec, const struct ecard_id *id)
acornscsi_resetcard(ashost);
ret = scsi_add_host(host, &ec->dev);
- if (ret == 0)
- goto out;
+ if (ret)
+ goto err_7;
+
+ scsi_scan_host(host);
+ goto out;
+ err_7:
free_irq(host->irq, ashost);
err_6:
release_region(host->io_port, 2048);
diff --git a/drivers/scsi/arm/cumana_1.c b/drivers/scsi/arm/cumana_1.c
index 35b1488ce2a6..aa75d505697f 100644
--- a/drivers/scsi/arm/cumana_1.c
+++ b/drivers/scsi/arm/cumana_1.c
@@ -297,9 +297,13 @@ cumanascsi1_probe(struct expansion_card *ec, const struct ecard_id *id)
printk("\n");
ret = scsi_add_host(host, &ec->dev);
- if (ret == 0)
- goto out;
+ if (ret)
+ goto out_free_irq;
+
+ scsi_scan_host(host);
+ goto out;
+ out_free_irq:
free_irq(host->irq, host);
out_release:
release_region(host->io_port, host->n_io_port);
diff --git a/drivers/scsi/arm/ecoscsi.c b/drivers/scsi/arm/ecoscsi.c
index ec1571c94539..7f27e54258b8 100644
--- a/drivers/scsi/arm/ecoscsi.c
+++ b/drivers/scsi/arm/ecoscsi.c
@@ -205,7 +205,8 @@ static int __init ecoscsi_init(void)
NCR5380_print_options(host);
printk("\n");
- scsi_add_host(host, NULL);
+ scsi_add_host(host, NULL); /* XXX handle failure */
+ scsi_scan_host(host);
return 0;
release_reg:
diff --git a/drivers/scsi/arm/fas216.c b/drivers/scsi/arm/fas216.c
index 11a733dea1c8..2648c6ee5b37 100644
--- a/drivers/scsi/arm/fas216.c
+++ b/drivers/scsi/arm/fas216.c
@@ -2861,6 +2861,8 @@ int fas216_add(struct Scsi_Host *host, struct device *dev)
ret = scsi_add_host(host, dev);
if (ret)
fas216_writeb(info, REG_CMD, CMD_RESETCHIP);
+ else
+ scsi_scan_host(host);
return ret;
}
diff --git a/drivers/scsi/arm/oak.c b/drivers/scsi/arm/oak.c
index 34a54329d216..ccca39b6943d 100644
--- a/drivers/scsi/arm/oak.c
+++ b/drivers/scsi/arm/oak.c
@@ -158,9 +158,13 @@ oakscsi_probe(struct expansion_card *ec, const struct ecard_id *id)
printk("\n");
ret = scsi_add_host(host, &ec->dev);
- if (ret == 0)
- goto out;
+ if (ret)
+ goto out_release;
+
+ scsi_scan_host(host);
+ goto out;
+ out_release:
release_region(host->io_port, host->n_io_port);
unreg:
scsi_host_put(host);
diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c
index 65c9467477f9..ecf0333f92d4 100644
--- a/drivers/scsi/dc395x.c
+++ b/drivers/scsi/dc395x.c
@@ -6214,7 +6214,8 @@ int __devinit dc395x_init_one(struct pci_dev *pdev,
pci_set_drvdata(pdev, scsi_host);
/* get the scsi mid level to scan for new devices on the bus */
- scsi_add_host(scsi_host, &pdev->dev);
+ scsi_add_host(scsi_host, &pdev->dev); /* XXX handle failure */
+ scsi_scan_host(scsi_host);
return 0;
}
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
index 755f7b837f04..f4f69bf1e148 100644
--- a/drivers/scsi/hosts.c
+++ b/drivers/scsi/hosts.c
@@ -81,19 +81,15 @@ int scsi_add_host(struct Scsi_Host *shost, struct device *dev)
printk(KERN_INFO "scsi%d : %s\n", shost->host_no,
sht->info ? sht->info(shost) : sht->name);
- error = scsi_sysfs_add_host(shost, dev);
-
if (!shost->can_queue) {
printk(KERN_ERR "%s: can_queue = 0 no longer supported\n",
sht->name);
error = -EINVAL;
}
- if (!error) {
+ error = scsi_sysfs_add_host(shost, dev);
+ if (!error)
scsi_proc_host_add(shost);
- scsi_scan_host(shost);
- }
-
return error;
}
@@ -151,12 +147,6 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
dump_stack();
}
- /* if its not set in the template, use the default */
- if (!sht->shost_attrs)
- sht->shost_attrs = scsi_sysfs_shost_attrs;
- if (!sht->sdev_attrs)
- sht->sdev_attrs = scsi_sysfs_sdev_attrs;
-
shost = kmalloc(sizeof(struct Scsi_Host) + privsize, gfp_mask);
if (!shost)
return NULL;
@@ -283,8 +273,8 @@ struct Scsi_Host *scsi_host_lookup(unsigned short hostnum)
**/
void scsi_host_get(struct Scsi_Host *shost)
{
- get_device(&shost->host_gendev);
- class_device_get(&shost->class_dev);
+ get_device(&shost->shost_gendev);
+ class_device_get(&shost->shost_classdev);
}
/**
@@ -293,6 +283,6 @@ void scsi_host_get(struct Scsi_Host *shost)
**/
void scsi_host_put(struct Scsi_Host *shost)
{
- class_device_put(&shost->class_dev);
- put_device(&shost->host_gendev);
+ class_device_put(&shost->shost_classdev);
+ put_device(&shost->shost_gendev);
}
diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c
index cfd1e581072c..84238c4de22a 100644
--- a/drivers/scsi/ide-scsi.c
+++ b/drivers/scsi/ide-scsi.c
@@ -978,8 +978,10 @@ static int idescsi_attach(ide_drive_t *drive)
idescsi_setup (drive, idescsi);
drive->disk->fops = &idescsi_ops;
err = scsi_add_host(host, &idescsi_primary);
- if (!err)
+ if (!err) {
+ scsi_scan_host(host);
return 0;
+ }
/* fall through on error */
ide_unregister_subdriver(drive);
}
diff --git a/drivers/scsi/ips.h b/drivers/scsi/ips.h
index 921d73f38f9d..0ad7adce9acf 100644
--- a/drivers/scsi/ips.h
+++ b/drivers/scsi/ips.h
@@ -111,7 +111,7 @@
#else
#define IPS_REGISTER_HOSTS(SHT) (!ips_detect(SHT))
#define IPS_UNREGISTER_HOSTS(SHT)
- #define IPS_ADD_HOST(shost,device) scsi_add_host(shost,device)
+ #define IPS_ADD_HOST(shost,device) do { scsi_add_host(shost,device); scsi_scan_host(shost); } while (0)
#define IPS_REMOVE_HOST(shost) scsi_remove_host(shost)
#define IPS_SCSI_SET_DEVICE(sh,ha) scsi_set_device(sh, &(ha)->pcidev->dev)
#define IPS_PRINTK(level, pcidev, format, arg...) \
diff --git a/drivers/scsi/lasi700.c b/drivers/scsi/lasi700.c
index b5c4b51b3cf3..25cff061f4a1 100644
--- a/drivers/scsi/lasi700.c
+++ b/drivers/scsi/lasi700.c
@@ -128,7 +128,8 @@ lasi700_driver_callback(struct parisc_device *dev)
}
dev_set_drvdata(&dev->dev, host);
- scsi_add_host(host, &dev->dev);
+ scsi_add_host(host, &dev->dev); /* XXX handle failure */
+ scsi_scan_host(host);
return 0;
@@ -165,7 +166,6 @@ static void __exit
lasi700_exit(void)
{
unregister_parisc_driver(&lasi700_driver);
- scsi_sysfs_release_attributes(&lasi700_template);
}
module_init(lasi700_init);
diff --git a/drivers/scsi/nsp32.c b/drivers/scsi/nsp32.c
index 963e409dcfd7..d9567d5b75f3 100644
--- a/drivers/scsi/nsp32.c
+++ b/drivers/scsi/nsp32.c
@@ -1820,7 +1820,8 @@ static int nsp32_detect(struct pci_dev *pdev)
goto free_irq;
}
- scsi_add_host(host, &pdev->dev);
+ scsi_add_host(host, &pdev->dev); /* XXX handle failure */
+ scsi_scan_host(host);
pci_set_drvdata(pdev, host);
return 0;
diff --git a/drivers/scsi/pas16.c b/drivers/scsi/pas16.c
index 3266488a5b44..fe5b7af58902 100644
--- a/drivers/scsi/pas16.c
+++ b/drivers/scsi/pas16.c
@@ -117,6 +117,7 @@
#include <linux/proc_fs.h>
#include <linux/sched.h>
#include <asm/io.h>
+#include <asm/dma.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
diff --git a/drivers/scsi/pcmcia/aha152x_stub.c b/drivers/scsi/pcmcia/aha152x_stub.c
index 41f420335072..af999e9509b6 100644
--- a/drivers/scsi/pcmcia/aha152x_stub.c
+++ b/drivers/scsi/pcmcia/aha152x_stub.c
@@ -278,7 +278,8 @@ static void aha152x_config_cs(dev_link_t *link)
goto cs_failed;
}
- scsi_add_host(host, NULL);
+ scsi_add_host(host, NULL); /* XXX handle failure */
+ scsi_scan_host(host);
sprintf(info->node.dev_name, "scsi%d", host->host_no);
link->dev = &info->node;
diff --git a/drivers/scsi/pcmcia/fdomain_stub.c b/drivers/scsi/pcmcia/fdomain_stub.c
index 7e12c1d37673..e91187dca450 100644
--- a/drivers/scsi/pcmcia/fdomain_stub.c
+++ b/drivers/scsi/pcmcia/fdomain_stub.c
@@ -254,7 +254,8 @@ static void fdomain_config(dev_link_t *link)
goto cs_failed;
}
- scsi_add_host(host, NULL);
+ scsi_add_host(host, NULL); /* XXX handle failure */
+ scsi_scan_host(host);
sprintf(info->node.dev_name, "scsi%d", host->host_no);
link->dev = &info->node;
diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c
index 59291c8b32c1..5165af63b6b5 100644
--- a/drivers/scsi/pcmcia/nsp_cs.c
+++ b/drivers/scsi/pcmcia/nsp_cs.c
@@ -1773,7 +1773,8 @@ static void nsp_cs_config(dev_link_t *link)
req.Base+req.Size-1);
printk("\n");
- scsi_add_host(host, NULL);
+ scsi_add_host(host, NULL); /* XXX handle failure */
+ scsi_scan_host(host);
link->state &= ~DEV_CONFIG_PENDING;
return;
diff --git a/drivers/scsi/pcmcia/qlogic_stub.c b/drivers/scsi/pcmcia/qlogic_stub.c
index debc8c985330..503a5fd05d96 100644
--- a/drivers/scsi/pcmcia/qlogic_stub.c
+++ b/drivers/scsi/pcmcia/qlogic_stub.c
@@ -270,7 +270,8 @@ static void qlogic_config(dev_link_t * link)
link->dev = &info->node;
info->host = host;
- scsi_add_host(host, NULL);
+ scsi_add_host(host, NULL); /* XXX handle failure */
+ scsi_scan_host(host);
out:
link->state &= ~DEV_CONFIG_PENDING;
diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c
index a98ebec23f18..25e031649be9 100644
--- a/drivers/scsi/qla1280.c
+++ b/drivers/scsi/qla1280.c
@@ -327,7 +327,7 @@
/* 3.16 */
#ifdef QLA_64BIT_PTR
#define pci_dma_lo32(a) (a & 0xffffffff)
-#define pci_dma_hi32(a) (a >> 32)
+#define pci_dma_hi32(a) ((a >> 16)>>16)
#else
#define pci_dma_lo32(a) (a & 0xffffffff)
#define pci_dma_hi32(a) 0
diff --git a/drivers/scsi/qlogicfas.c b/drivers/scsi/qlogicfas.c
index 05638f11195d..c3729c74c6e8 100644
--- a/drivers/scsi/qlogicfas.c
+++ b/drivers/scsi/qlogicfas.c
@@ -140,6 +140,7 @@
#include <asm/io.h>
#include <asm/irq.h>
+#include <asm/dma.h>
#include "scsi.h"
#include "hosts.h"
diff --git a/drivers/scsi/scsi.h b/drivers/scsi/scsi.h
index 3ff36ab84744..5d2e6d8aec01 100644
--- a/drivers/scsi/scsi.h
+++ b/drivers/scsi/scsi.h
@@ -174,11 +174,6 @@ extern const char *scsi_extd_sense_format(unsigned char, unsigned char);
#define SCSI_MLQUEUE_DEVICE_BUSY 0x1056
#define SCSI_MLQUEUE_EH_RETRY 0x1057
-extern int scsi_sysfs_modify_sdev_attribute(struct device_attribute ***dev_attrs,
- struct device_attribute *attr);
-extern int scsi_sysfs_modify_shost_attribute(struct class_device_attribute ***class_attrs,
- struct class_device_attribute *attr);
-
/*
* Legacy dma direction interfaces.
*
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index 138e78f133b7..47125ef5d93e 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -687,7 +687,7 @@ static int resp_mode_sense(unsigned char * cmd, int target,
pcontrol = (cmd[2] & 0xc0) >> 6;
pcode = cmd[2] & 0x3f;
msense_6 = (MODE_SENSE == cmd[0]);
- alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[6]);
+ alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]);
/* printk(KERN_INFO "msense: dbd=%d pcontrol=%d pcode=%d "
"msense_6=%d alloc_len=%d\n", dbd, pcontrol, pcode, "
"msense_6, alloc_len); */
@@ -1701,7 +1701,8 @@ static int sdebug_driver_probe(struct device * dev)
printk(KERN_ERR "%s: scsi_add_host failed\n", __FUNCTION__);
error = -ENODEV;
scsi_host_put(hpnt);
- }
+ } else
+ scsi_scan_host(hpnt);
return error;
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 3997f09783e0..3a5d82add006 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -444,22 +444,8 @@ static void scsi_run_queue(struct request_queue *q)
*/
static void scsi_requeue_command(struct request_queue *q, struct scsi_cmnd *cmd)
{
- unsigned long flags;
-
- spin_lock_irqsave(q->queue_lock, flags);
- cmd->request->special = cmd;
- if (blk_rq_tagged(cmd->request))
- blk_queue_end_tag(q, cmd->request);
-
- /*
- * set REQ_SPECIAL - we have a command
- * clear REQ_DONTPREP - we assume the sg table has been
- * nuked so we need to set it up again.
- */
- cmd->request->flags |= REQ_SPECIAL;
cmd->request->flags &= ~REQ_DONTPREP;
- __elv_add_request(q, cmd->request, 0, 0);
- spin_unlock_irqrestore(q->queue_lock, flags);
+ blk_insert_request(q, cmd->request, 1, cmd);
scsi_run_queue(q);
}
@@ -1213,9 +1199,7 @@ static void scsi_request_fn(struct request_queue *q)
* later time.
*/
spin_lock_irq(q->queue_lock);
- if (blk_rq_tagged(req))
- blk_queue_end_tag(q, req);
- __elv_add_request(q, req, 0, 0);
+ blk_requeue_request(q, req);
sdev->device_busy--;
if(sdev->device_busy == 0)
blk_plug_device(q);
@@ -1426,17 +1410,17 @@ __scsi_mode_sense(struct scsi_request *sreq, int dbd, int modepage,
if(scsi_status_is_good(sreq->sr_result)) {
data->header_length = header_length;
if(use_10_for_ms) {
- data->length = buffer[0]*256 + buffer[1];
+ data->length = buffer[0]*256 + buffer[1] + 2;
data->medium_type = buffer[2];
data->device_specific = buffer[3];
data->longlba = buffer[4] & 0x01;
data->block_descriptor_length = buffer[6]*256
+ buffer[7];
} else {
- data->length = buffer[0];
+ data->length = buffer[0] + 1;
data->medium_type = buffer[1];
- data->device_specific = buffer[3];
- data->block_descriptor_length = buffer[4];
+ data->device_specific = buffer[2];
+ data->block_descriptor_length = buffer[3];
}
}
diff --git a/drivers/scsi/scsi_module.c b/drivers/scsi/scsi_module.c
index 7803089da533..515a3e4b48fe 100644
--- a/drivers/scsi/scsi_module.c
+++ b/drivers/scsi/scsi_module.c
@@ -40,6 +40,7 @@ static int __init init_this_scsi_driver(void)
error = scsi_add_host(shost, NULL);
if (error)
goto fail;
+ scsi_scan_host(shost);
}
return 0;
fail:
diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h
index 6346005e64c7..f17bdd42afe6 100644
--- a/drivers/scsi/scsi_priv.h
+++ b/drivers/scsi/scsi_priv.h
@@ -102,7 +102,6 @@ extern void scsi_exit_procfs(void);
#endif /* CONFIG_PROC_FS */
/* scsi_scan.c */
-extern void scsi_scan_host(struct Scsi_Host *);
extern void scsi_forget_host(struct Scsi_Host *);
extern void scsi_free_sdev(struct scsi_device *);
extern void scsi_free_shost(struct Scsi_Host *);
@@ -117,11 +116,6 @@ extern void scsi_sysfs_remove_host(struct Scsi_Host *);
extern int scsi_sysfs_register(void);
extern void scsi_sysfs_unregister(void);
-/* definitions for the linker default sections covering the host
- * class and device attributes */
-extern struct class_device_attribute *scsi_sysfs_shost_attrs[];
-extern struct device_attribute *scsi_sysfs_sdev_attrs[];
-
extern struct class shost_class;
extern struct bus_type scsi_bus_type;
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 9dffa0c2caca..3b8309105021 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -464,8 +464,7 @@ static void scsi_set_name(struct scsi_device *sdev, char *inq_result)
while (i >= 0 && type[i] == ' ')
type[i--] = '\0';
- snprintf(sdev->sdev_driverfs_dev.name, DEVICE_NAME_SIZE, "SCSI %s",
- type);
+ snprintf(sdev->sdev_gendev.name, DEVICE_NAME_SIZE, "SCSI %s", type);
}
/**
diff --git a/drivers/scsi/scsi_syms.c b/drivers/scsi/scsi_syms.c
index 62e413ef5949..2ce7cb6c25bf 100644
--- a/drivers/scsi/scsi_syms.c
+++ b/drivers/scsi/scsi_syms.c
@@ -34,6 +34,7 @@ EXPORT_SYMBOL(scsi_register_driver);
EXPORT_SYMBOL(scsi_register_interface);
EXPORT_SYMBOL(scsi_host_alloc);
EXPORT_SYMBOL(scsi_add_host);
+EXPORT_SYMBOL(scsi_scan_host);
EXPORT_SYMBOL(scsi_remove_host);
EXPORT_SYMBOL(scsi_host_get);
EXPORT_SYMBOL(scsi_host_put);
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index 80be2659043d..3801b768c733 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -45,7 +45,7 @@ shost_rd_attr(cmd_per_lun, "%hd\n");
shost_rd_attr(sg_tablesize, "%hu\n");
shost_rd_attr(unchecked_isa_dma, "%d\n");
-struct class_device_attribute *scsi_sysfs_shost_attrs[] = {
+static struct class_device_attribute *scsi_sysfs_shost_attrs[] = {
&class_device_attr_unique_id,
&class_device_attr_host_busy,
&class_device_attr_cmd_per_lun,
@@ -204,7 +204,7 @@ store_rescan_field (struct device *dev, const char *buf, size_t count)
static DEVICE_ATTR(rescan, S_IWUSR, NULL, store_rescan_field)
/* Default template for device attributes. May NOT be modified */
-struct device_attribute *scsi_sysfs_sdev_attrs[] = {
+static struct device_attribute *scsi_sysfs_sdev_attrs[] = {
&dev_attr_device_blocked,
&dev_attr_queue_depth,
&dev_attr_type,
@@ -228,6 +228,42 @@ static void scsi_device_release(struct device *dev)
scsi_free_sdev(sdev);
}
+static struct device_attribute *attr_overridden(
+ struct device_attribute **attrs,
+ struct device_attribute *attr)
+{
+ int i;
+
+ if (!attrs)
+ return NULL;
+ for (i = 0; attrs[i]; i++)
+ if (!strcmp(attrs[i]->attr.name, attr->attr.name))
+ return attrs[i];
+ return NULL;
+}
+
+static int attr_add(struct device *dev, struct device_attribute *attr)
+{
+ struct device_attribute *base_attr;
+
+ /*
+ * Spare the caller from having to copy things it's not interested in.
+ */
+ base_attr = attr_overridden(scsi_sysfs_sdev_attrs, attr);
+ if (base_attr) {
+ /* extend permissions */
+ attr->attr.mode |= base_attr->attr.mode;
+
+ /* override null show/store with default */
+ if (!attr->show)
+ attr->show = base_attr->show;
+ if (!attr->store)
+ attr->store = base_attr->store;
+ }
+
+ return device_create_file(dev, attr);
+}
+
/**
* scsi_device_register - register a scsi device with the scsi bus
* @sdev: scsi_device to register
@@ -239,20 +275,20 @@ int scsi_device_register(struct scsi_device *sdev)
{
int error = 0, i;
- device_initialize(&sdev->sdev_driverfs_dev);
- sprintf(sdev->sdev_driverfs_dev.bus_id,"%d:%d:%d:%d",
+ device_initialize(&sdev->sdev_gendev);
+ sprintf(sdev->sdev_gendev.bus_id,"%d:%d:%d:%d",
sdev->host->host_no, sdev->channel, sdev->id, sdev->lun);
- sdev->sdev_driverfs_dev.parent = &sdev->host->host_gendev;
- sdev->sdev_driverfs_dev.bus = &scsi_bus_type;
- sdev->sdev_driverfs_dev.release = scsi_device_release;
+ sdev->sdev_gendev.parent = &sdev->host->shost_gendev;
+ sdev->sdev_gendev.bus = &scsi_bus_type;
+ sdev->sdev_gendev.release = scsi_device_release;
class_device_initialize(&sdev->sdev_classdev);
- sdev->sdev_classdev.dev = &sdev->sdev_driverfs_dev;
+ sdev->sdev_classdev.dev = &sdev->sdev_gendev;
sdev->sdev_classdev.class = &sdev_class;
snprintf(sdev->sdev_classdev.class_id, BUS_ID_SIZE, "%d:%d:%d:%d",
sdev->host->host_no, sdev->channel, sdev->id, sdev->lun);
- error = device_add(&sdev->sdev_driverfs_dev);
+ error = device_add(&sdev->sdev_gendev);
if (error) {
printk(KERN_INFO "error 1\n");
return error;
@@ -260,16 +296,28 @@ int scsi_device_register(struct scsi_device *sdev)
error = class_device_add(&sdev->sdev_classdev);
if (error) {
printk(KERN_INFO "error 2\n");
- device_unregister(&sdev->sdev_driverfs_dev);
+ device_unregister(&sdev->sdev_gendev);
return error;
}
- for (i = 0; !error && sdev->host->hostt->sdev_attrs[i] != NULL; i++)
- error = device_create_file(&sdev->sdev_driverfs_dev,
- sdev->host->hostt->sdev_attrs[i]);
-
- if (error)
- scsi_device_unregister(sdev);
+ if (sdev->host->hostt->sdev_attrs) {
+ for (i = 0; sdev->host->hostt->sdev_attrs[i]; i++) {
+ error = attr_add(&sdev->sdev_gendev,
+ sdev->host->hostt->sdev_attrs[i]);
+ if (error)
+ scsi_device_unregister(sdev);
+ }
+ }
+
+ for (i = 0; scsi_sysfs_sdev_attrs[i]; i++) {
+ if (!attr_overridden(sdev->host->hostt->sdev_attrs,
+ scsi_sysfs_sdev_attrs[i])) {
+ error = device_create_file(&sdev->sdev_gendev,
+ scsi_sysfs_sdev_attrs[i]);
+ if (error)
+ scsi_device_unregister(sdev);
+ }
+ }
return error;
}
@@ -280,12 +328,8 @@ int scsi_device_register(struct scsi_device *sdev)
**/
void scsi_device_unregister(struct scsi_device *sdev)
{
- int i;
-
- for (i = 0; sdev->host->hostt->sdev_attrs[i] != NULL; i++)
- device_remove_file(&sdev->sdev_driverfs_dev, sdev->host->hostt->sdev_attrs[i]);
class_device_unregister(&sdev->sdev_classdev);
- device_unregister(&sdev->sdev_driverfs_dev);
+ device_unregister(&sdev->sdev_gendev);
}
int scsi_register_driver(struct device_driver *drv)
@@ -315,20 +359,57 @@ static void scsi_host_release(struct device *dev)
void scsi_sysfs_init_host(struct Scsi_Host *shost)
{
- device_initialize(&shost->host_gendev);
- snprintf(shost->host_gendev.bus_id, BUS_ID_SIZE, "host%d",
+ device_initialize(&shost->shost_gendev);
+ snprintf(shost->shost_gendev.bus_id, BUS_ID_SIZE, "host%d",
shost->host_no);
- snprintf(shost->host_gendev.name, DEVICE_NAME_SIZE, "%s",
+ snprintf(shost->shost_gendev.name, DEVICE_NAME_SIZE, "%s",
shost->hostt->proc_name);
- shost->host_gendev.release = scsi_host_release;
+ shost->shost_gendev.release = scsi_host_release;
- class_device_initialize(&shost->class_dev);
- shost->class_dev.dev = &shost->host_gendev;
- shost->class_dev.class = &shost_class;
- snprintf(shost->class_dev.class_id, BUS_ID_SIZE, "host%d",
+ class_device_initialize(&shost->shost_classdev);
+ shost->shost_classdev.dev = &shost->shost_gendev;
+ shost->shost_classdev.class = &shost_class;
+ snprintf(shost->shost_classdev.class_id, BUS_ID_SIZE, "host%d",
shost->host_no);
}
+static struct class_device_attribute *class_attr_overridden(
+ struct class_device_attribute **attrs,
+ struct class_device_attribute *attr)
+{
+ int i;
+
+ if (!attrs)
+ return NULL;
+ for (i = 0; attrs[i]; i++)
+ if (!strcmp(attrs[i]->attr.name, attr->attr.name))
+ return attrs[i];
+ return NULL;
+}
+
+static int class_attr_add(struct class_device *classdev,
+ struct class_device_attribute *attr)
+{
+ struct class_device_attribute *base_attr;
+
+ /*
+ * Spare the caller from having to copy things it's not interested in.
+ */
+ base_attr = class_attr_overridden(scsi_sysfs_shost_attrs, attr);
+ if (base_attr) {
+ /* extend permissions */
+ attr->attr.mode |= base_attr->attr.mode;
+
+ /* override null show/store with default */
+ if (!attr->show)
+ attr->show = base_attr->show;
+ if (!attr->store)
+ attr->store = base_attr->store;
+ }
+
+ return class_device_create_file(classdev, attr);
+}
+
/**
* scsi_sysfs_add_host - add scsi host to subsystem
* @shost: scsi host struct to add to subsystem
@@ -336,31 +417,44 @@ void scsi_sysfs_init_host(struct Scsi_Host *shost)
**/
int scsi_sysfs_add_host(struct Scsi_Host *shost, struct device *dev)
{
- int i, error;
+ int error, i;
- if (!shost->host_gendev.parent)
- shost->host_gendev.parent = dev ? dev : &legacy_bus;
+ if (!shost->shost_gendev.parent)
+ shost->shost_gendev.parent = dev ? dev : &legacy_bus;
- error = device_add(&shost->host_gendev);
+ error = device_add(&shost->shost_gendev);
if (error)
return error;
- error = class_device_add(&shost->class_dev);
+ error = class_device_add(&shost->shost_classdev);
if (error)
goto clean_device;
- for (i = 0; !error && shost->hostt->shost_attrs[i] != NULL; i++)
- error = class_device_create_file(&shost->class_dev,
- shost->hostt->shost_attrs[i]);
- if (error)
- goto clean_class;
+ if (shost->hostt->shost_attrs) {
+ for (i = 0; shost->hostt->shost_attrs[i]; i++) {
+ error = class_attr_add(&shost->shost_classdev,
+ shost->hostt->shost_attrs[i]);
+ if (error)
+ goto clean_class;
+ }
+ }
+
+ for (i = 0; scsi_sysfs_shost_attrs[i]; i++) {
+ if (!class_attr_overridden(shost->hostt->shost_attrs,
+ scsi_sysfs_shost_attrs[i])) {
+ error = class_device_create_file(&shost->shost_classdev,
+ scsi_sysfs_shost_attrs[i]);
+ if (error)
+ goto clean_class;
+ }
+ }
return error;
clean_class:
- class_device_del(&shost->class_dev);
+ class_device_del(&shost->shost_classdev);
clean_device:
- device_del(&shost->host_gendev);
+ device_del(&shost->shost_gendev);
return error;
}
@@ -371,133 +465,6 @@ clean_device:
**/
void scsi_sysfs_remove_host(struct Scsi_Host *shost)
{
- class_device_del(&shost->class_dev);
- device_del(&shost->host_gendev);
-}
-
-/** scsi_sysfs_modify_shost_attribute - modify or add a host class attribute
- *
- * @class_attrs:host class attribute list to be added to or modified
- * @attr: individual attribute to change or added
- *
- * returns zero if successful or error if not
- **/
-int scsi_sysfs_modify_shost_attribute(
- struct class_device_attribute ***class_attrs,
- struct class_device_attribute *attr)
-{
- int modify = -1;
- int num_attrs;
-
- if(*class_attrs == NULL)
- *class_attrs = scsi_sysfs_shost_attrs;
-
- for(num_attrs=0; (*class_attrs)[num_attrs] != NULL; num_attrs++)
- if(strcmp((*class_attrs)[num_attrs]->attr.name,
- attr->attr.name) == 0)
- modify = num_attrs;
-
- if(*class_attrs == scsi_sysfs_shost_attrs || modify < 0) {
- /* note: need space for null at the end as well */
- struct class_device_attribute **tmp_attrs =
- kmalloc(sizeof(*tmp_attrs) *
- (num_attrs + (modify >= 0 ? 1 : 2)),
- GFP_KERNEL);
- if(tmp_attrs == NULL)
- return -ENOMEM;
- memcpy(tmp_attrs, *class_attrs, sizeof(*tmp_attrs) *
- (num_attrs + 1));
- if(*class_attrs != scsi_sysfs_shost_attrs)
- kfree(*class_attrs);
- *class_attrs = tmp_attrs;
- }
- if(modify >= 0) {
- /* spare the caller from having to copy things it's
- * not interested in */
- struct class_device_attribute *old_attr =
- (*class_attrs)[modify];
- /* extend permissions */
- attr->attr.mode |= old_attr->attr.mode;
-
- /* override null show/store with default */
- if(attr->show == NULL)
- attr->show = old_attr->show;
- if(attr->store == NULL)
- attr->store = old_attr->store;
- (*class_attrs)[modify] = attr;
- } else {
- (*class_attrs)[num_attrs++] = attr;
- (*class_attrs)[num_attrs] = NULL;
- }
-
- return 0;
-}
-EXPORT_SYMBOL(scsi_sysfs_modify_shost_attribute);
-
-/** scsi_sysfs_modify_sdev_attribute - modify or add a host device attribute
- *
- * @dev_attrs: pointer to the attribute list to be added to or modified
- * @attr: individual attribute to change or added
- *
- * returns zero if successful or error if not
- **/
-int scsi_sysfs_modify_sdev_attribute(struct device_attribute ***dev_attrs,
- struct device_attribute *attr)
-{
- int modify = -1;
- int num_attrs;
-
- if(*dev_attrs == NULL)
- *dev_attrs = scsi_sysfs_sdev_attrs;
-
- for(num_attrs=0; (*dev_attrs)[num_attrs] != NULL; num_attrs++)
- if(strcmp((*dev_attrs)[num_attrs]->attr.name,
- attr->attr.name) == 0)
- modify = num_attrs;
-
- if(*dev_attrs == scsi_sysfs_sdev_attrs || modify < 0) {
- /* note: need space for null at the end as well */
- struct device_attribute **tmp_attrs =
- kmalloc(sizeof(*tmp_attrs) *
- (num_attrs + (modify >= 0 ? 1 : 2)),
- GFP_KERNEL);
- if(tmp_attrs == NULL)
- return -ENOMEM;
- memcpy(tmp_attrs, *dev_attrs, sizeof(*tmp_attrs) *
- (num_attrs + 1));
- if(*dev_attrs != scsi_sysfs_sdev_attrs)
- kfree(*dev_attrs);
- *dev_attrs = tmp_attrs;
- }
- if(modify >= 0) {
- /* spare the caller from having to copy things it's
- * not interested in */
- struct device_attribute *old_attr =
- (*dev_attrs)[modify];
- /* extend permissions */
- attr->attr.mode |= old_attr->attr.mode;
-
- /* override null show/store with default */
- if(attr->show == NULL)
- attr->show = old_attr->show;
- if(attr->store == NULL)
- attr->store = old_attr->store;
- (*dev_attrs)[modify] = attr;
- } else {
- (*dev_attrs)[num_attrs++] = attr;
- (*dev_attrs)[num_attrs] = NULL;
- }
-
- return 0;
-}
-EXPORT_SYMBOL(scsi_sysfs_modify_sdev_attribute);
-
-void scsi_sysfs_release_attributes(struct scsi_host_template *hostt)
-{
- if(hostt->sdev_attrs != scsi_sysfs_sdev_attrs)
- kfree(hostt->sdev_attrs);
-
- if(hostt->shost_attrs != scsi_sysfs_shost_attrs)
- kfree(hostt->shost_attrs);
+ class_device_del(&shost->shost_classdev);
+ device_del(&shost->shost_gendev);
}
-EXPORT_SYMBOL(scsi_sysfs_release_attributes);
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index dead50aa989e..441ca6e58cfc 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -606,35 +606,8 @@ not_present:
static void sd_rescan(struct device *dev)
{
- struct scsi_device *sdp = to_scsi_device(dev);
struct scsi_disk *sdkp = dev_get_drvdata(dev);
- struct gendisk *gd;
- struct scsi_request *SRpnt;
- unsigned char *buffer;
-
- if (!sdkp || sdp->online == FALSE || !sdkp->media_present)
- return;
-
- gd = sdkp->disk;
-
- SCSI_LOG_HLQUEUE(3, printk("sd_rescan: disk=%s\n", gd->disk_name));
-
- SRpnt = scsi_allocate_request(sdp);
- if (!SRpnt) {
- printk(KERN_WARNING "(sd_rescan:) Request allocation "
- "failure.\n");
- return;
- }
-
- if (sdkp->device->host->unchecked_isa_dma)
- buffer = kmalloc(512, GFP_DMA);
- else
- buffer = kmalloc(512, GFP_KERNEL);
-
- sd_read_capacity(sdkp, gd->disk_name, SRpnt, buffer);
- set_capacity(gd, sdkp->capacity);
- scsi_release_request(SRpnt);
- kfree(buffer);
+ sd_revalidate_disk(sdkp->disk);
}
static struct block_device_operations sd_fops = {
@@ -1318,7 +1291,7 @@ static int sd_probe(struct device *dev)
sd_revalidate_disk(gd);
- gd->driverfs_dev = &sdp->sdev_driverfs_dev;
+ gd->driverfs_dev = &sdp->sdev_gendev;
gd->flags = GENHD_FL_DRIVERFS;
if (sdp->removable)
gd->flags |= GENHD_FL_REMOVABLE;
diff --git a/drivers/scsi/sim710.c b/drivers/scsi/sim710.c
index d5b8cb39b485..5132357c8fd8 100644
--- a/drivers/scsi/sim710.c
+++ b/drivers/scsi/sim710.c
@@ -138,7 +138,8 @@ sim710_probe_common(struct device *dev, unsigned long base_addr,
goto out_unregister;
}
- scsi_add_host(host, dev);
+ scsi_add_host(host, dev); /* XXX handle failure */
+ scsi_scan_host(host);
hostdata->dev = dev;
return 0;
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index e38e8d1d2231..7c24b78e45e6 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -533,7 +533,7 @@ static int sr_probe(struct device *dev)
snprintf(disk->devfs_name, sizeof(disk->devfs_name),
"%s/cd", sdev->devfs_name);
- disk->driverfs_dev = &sdev->sdev_driverfs_dev;
+ disk->driverfs_dev = &sdev->sdev_gendev;
register_cdrom(&cd->cdi);
set_capacity(disk, cd->capacity);
disk->private_data = &cd->driver;
diff --git a/drivers/scsi/sym53c8xx.c b/drivers/scsi/sym53c8xx.c
index 246e3ff0209c..8a6c3972a7c4 100644
--- a/drivers/scsi/sym53c8xx.c
+++ b/drivers/scsi/sym53c8xx.c
@@ -1327,7 +1327,7 @@ MODULE_PARM(sym53c8xx, "s");
#define SetScsiAbortResult(cmd) SetScsiResult(cmd, DID_ABORT, 0xff)
#endif
-static void sym53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs);
+static irqreturn_t sym53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs);
static void sym53c8xx_timeout(unsigned long np);
#define initverbose (driver_setup.verbose)
@@ -7374,7 +7374,7 @@ void ncr_complete (ncb_p np, ccb_p cp)
}
if (cp->xerr_status & XE_BAD_PHASE) {
PRINT_ADDR(cmd);
- printk ("illegal scsi phase (4/5).\n");
+ printk ("invalid scsi phase (4/5).\n");
}
if (cp->xerr_status & XE_SODL_UNRUN) {
PRINT_ADDR(cmd);
@@ -13660,7 +13660,7 @@ printk("sym53c8xx : command successfully queued\n");
** routine for each host that uses this IRQ.
*/
-static void sym53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs)
+static irqreturn_t sym53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs)
{
unsigned long flags;
ncb_p np = (ncb_p) dev_id;
@@ -13685,6 +13685,7 @@ static void sym53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs)
ncr_flush_done_cmds(done_list);
NCR_UNLOCK_SCSI_DONE(done_list->device->host, flags);
}
+ return IRQ_HANDLED;
}
/*
diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c
index be1548c00e3d..b0266f645172 100644
--- a/drivers/scsi/sym53c8xx_2/sym_glue.c
+++ b/drivers/scsi/sym53c8xx_2/sym_glue.c
@@ -1110,6 +1110,7 @@ static int sym_eh_handler(int op, char *opname, Scsi_Cmnd *cmd)
int sts = -1;
struct sym_eh_wait eh, *ep = &eh;
char devname[20];
+ unsigned long flags;
sprintf(devname, "%s:%d:%d", sym_name(np), cmd->device->id, cmd->device->lun);
@@ -1201,7 +1202,11 @@ finish:
ep->timer.data = (u_long)cmd;
ep->timed_out = 1; /* Be pessimistic for once :) */
add_timer(&ep->timer);
+ local_save_flags(flags);
+ spin_unlock_irq(cmd->device->host->host_lock);
down(&ep->sem);
+ local_irq_restore(flags);
+ spin_lock(cmd->device->host->host_lock);
if (ep->timed_out)
sts = -2;
}
diff --git a/drivers/scsi/zalon.c b/drivers/scsi/zalon.c
index bed64aaec0bc..05700528818b 100644
--- a/drivers/scsi/zalon.c
+++ b/drivers/scsi/zalon.c
@@ -85,7 +85,7 @@ zalon_scsi_callback(struct parisc_device *dev)
{
struct gsc_irq gsc_irq;
u32 zalon_vers;
- int irq;
+ int irq, error = -ENODEV;
unsigned long zalon = dev->hpa;
unsigned long io_port = zalon + GSC_SCSI_ZALON_OFFSET;
static int unit = 0;
@@ -147,11 +147,18 @@ zalon_scsi_callback(struct parisc_device *dev)
dev_set_drvdata(&dev->dev, host);
- scsi_add_host(host, &dev->dev);
+ error = scsi_add_host(host, &dev->dev);
+ if (error)
+ goto fail_free_irq;
+ scsi_scan_host(host);
return 0;
+
+ fail_free_irq:
+ free_irq(irq, host);
fail:
- return -ENODEV;
+ ncr53c8xx_release(host);
+ return error;
}
static struct parisc_device_id zalon_tbl[] = {
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 94b36c3a01c8..cae6bc1239ec 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -404,14 +404,19 @@ config SERIAL_SUNSAB_CONSOLE
on your Sparc system as the console, you can do so by answering
Y to this option.
-config V850E_NB85E_UART
+config V850E_UART
bool "NEC V850E on-chip UART support"
- depends on V850E_NB85E || V850E2_ANNA || V850E_AS85EP1
+ depends on V850E_MA1 || V850E_ME2 || V850E_TEG || V850E2_ANNA || V850E_AS85EP1
default y
-config V850E_NB85E_UART_CONSOLE
+config V850E_UARTB
+ bool
+ depends V850E_UART && V850E_ME2
+ default y
+
+config V850E_UART_CONSOLE
bool "Use NEC V850E on-chip UART for console"
- depends on V850E_NB85E_UART
+ depends on V850E_UART
config SERIAL98
tristate "PC-9800 8251-based primary serial port support"
@@ -426,12 +431,12 @@ config SERIAL98_CONSOLE
config SERIAL_CORE
tristate
- default m if SERIAL_AMBA!=y && SERIAL_CLPS711X!=y && SERIAL_21285!=y && !SERIAL_SA1100 && !SERIAL_ANAKIN && !SERIAL_UART00 && SERIAL_8250!=y && SERIAL_MUX!=y && !SERIAL_ROCKETPORT && !SERIAL_SUNCORE && !V850E_NB85E_UART && (SERIAL_AMBA=m || SERIAL_CLPS711X=m || SERIAL_21285=m || SERIAL_8250=m || SERIAL_MUX=m || SERIAL98=m)
- default y if SERIAL_AMBA=y || SERIAL_CLPS711X=y || SERIAL_21285=y || SERIAL_SA1100 || SERIAL_ANAKIN || SERIAL_UART00 || SERIAL_8250=y || SERIAL_MUX=y || SERIAL_ROCKETPORT || SERIAL_SUNCORE || V850E_NB85E_UART || SERIAL98=y
+ default m if SERIAL_AMBA!=y && SERIAL_CLPS711X!=y && SERIAL_21285!=y && !SERIAL_SA1100 && !SERIAL_ANAKIN && !SERIAL_UART00 && SERIAL_8250!=y && SERIAL_MUX!=y && !SERIAL_ROCKETPORT && !SERIAL_SUNCORE && !V850E_UART && (SERIAL_AMBA=m || SERIAL_CLPS711X=m || SERIAL_21285=m || SERIAL_8250=m || SERIAL_MUX=m || SERIAL98=m)
+ default y if SERIAL_AMBA=y || SERIAL_CLPS711X=y || SERIAL_21285=y || SERIAL_SA1100 || SERIAL_ANAKIN || SERIAL_UART00 || SERIAL_8250=y || SERIAL_MUX=y || SERIAL_ROCKETPORT || SERIAL_SUNCORE || V850E_UART || SERIAL98=y
config SERIAL_CORE_CONSOLE
bool
- depends on SERIAL_AMBA_CONSOLE || SERIAL_CLPS711X_CONSOLE || SERIAL_21285_CONSOLE || SERIAL_SA1100_CONSOLE || SERIAL_ANAKIN_CONSOLE || SERIAL_UART00_CONSOLE || SERIAL_8250_CONSOLE || SERIAL_MUX_CONSOLE || SERIAL_SUNZILOG_CONSOLE || SERIAL_SUNSU_CONSOLE || SERIAL_SUNSAB_CONSOLE || V850E_NB85E_UART_CONSOLE || SERIAL98_CONSOLE
+ depends on SERIAL_AMBA_CONSOLE || SERIAL_CLPS711X_CONSOLE || SERIAL_21285_CONSOLE || SERIAL_SA1100_CONSOLE || SERIAL_ANAKIN_CONSOLE || SERIAL_UART00_CONSOLE || SERIAL_8250_CONSOLE || SERIAL_MUX_CONSOLE || SERIAL_SUNZILOG_CONSOLE || SERIAL_SUNSU_CONSOLE || SERIAL_SUNSAB_CONSOLE || V850E_UART_CONSOLE || SERIAL98_CONSOLE
default y
config SERIAL_68328
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index 13a7dc306853..c6e1fba4a2ad 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -29,5 +29,5 @@ obj-$(CONFIG_SERIAL_MUX) += mux.o
obj-$(CONFIG_SERIAL_68328) += 68328serial.o
obj-$(CONFIG_SERIAL_68360) += 68360serial.o
obj-$(CONFIG_SERIAL_COLDFIRE) += mcfserial.o
-obj-$(CONFIG_V850E_NB85E_UART) += nb85e_uart.o
+obj-$(CONFIG_V850E_UART) += v850e_uart.o
obj-$(CONFIG_SERIAL98) += serial98.o
diff --git a/drivers/serial/core.c b/drivers/serial/core.c
index 17c43594f9c4..a264d72ca695 100644
--- a/drivers/serial/core.c
+++ b/drivers/serial/core.c
@@ -1667,23 +1667,25 @@ static int uart_line_info(char *buf, struct uart_driver *drv, int i)
return ret + 1;
}
- status = port->ops->get_mctrl(port);
-
- ret += sprintf(buf + ret, " tx:%d rx:%d",
- port->icount.tx, port->icount.rx);
- if (port->icount.frame)
- ret += sprintf(buf + ret, " fe:%d",
- port->icount.frame);
- if (port->icount.parity)
- ret += sprintf(buf + ret, " pe:%d",
- port->icount.parity);
- if (port->icount.brk)
- ret += sprintf(buf + ret, " brk:%d",
- port->icount.brk);
- if (port->icount.overrun)
- ret += sprintf(buf + ret, " oe:%d",
- port->icount.overrun);
-
+ if(capable(CAP_SYS_ADMIN))
+ {
+ status = port->ops->get_mctrl(port);
+
+ ret += sprintf(buf + ret, " tx:%d rx:%d",
+ port->icount.tx, port->icount.rx);
+ if (port->icount.frame)
+ ret += sprintf(buf + ret, " fe:%d",
+ port->icount.frame);
+ if (port->icount.parity)
+ ret += sprintf(buf + ret, " pe:%d",
+ port->icount.parity);
+ if (port->icount.brk)
+ ret += sprintf(buf + ret, " brk:%d",
+ port->icount.brk);
+ if (port->icount.overrun)
+ ret += sprintf(buf + ret, " oe:%d",
+ port->icount.overrun);
+
#define INFOBIT(bit,str) \
if (port->mctrl & (bit)) \
strncat(stat_buf, (str), sizeof(stat_buf) - \
@@ -1693,19 +1695,22 @@ static int uart_line_info(char *buf, struct uart_driver *drv, int i)
strncat(stat_buf, (str), sizeof(stat_buf) - \
strlen(stat_buf) - 2)
- stat_buf[0] = '\0';
- stat_buf[1] = '\0';
- INFOBIT(TIOCM_RTS, "|RTS");
- STATBIT(TIOCM_CTS, "|CTS");
- INFOBIT(TIOCM_DTR, "|DTR");
- STATBIT(TIOCM_DSR, "|DSR");
- STATBIT(TIOCM_CAR, "|CD");
- STATBIT(TIOCM_RNG, "|RI");
- if (stat_buf[0])
- stat_buf[0] = ' ';
- strcat(stat_buf, "\n");
-
- ret += sprintf(buf + ret, stat_buf);
+ stat_buf[0] = '\0';
+ stat_buf[1] = '\0';
+ INFOBIT(TIOCM_RTS, "|RTS");
+ STATBIT(TIOCM_CTS, "|CTS");
+ INFOBIT(TIOCM_DTR, "|DTR");
+ STATBIT(TIOCM_DSR, "|DSR");
+ STATBIT(TIOCM_CAR, "|CD");
+ STATBIT(TIOCM_RNG, "|RI");
+ if (stat_buf[0])
+ stat_buf[0] = ' ';
+ strcat(stat_buf, "\n");
+
+ ret += sprintf(buf + ret, stat_buf);
+ }
+#undef STATBIT
+#undef INFOBIT
return ret;
}
diff --git a/drivers/serial/nb85e_uart.c b/drivers/serial/nb85e_uart.c
deleted file mode 100644
index 883be05241df..000000000000
--- a/drivers/serial/nb85e_uart.c
+++ /dev/null
@@ -1,610 +0,0 @@
-/*
- * drivers/serial/nb85e_uart.c -- Serial I/O using V850E/NB85E on-chip UART
- *
- * Copyright (C) 2001,02,03 NEC Corporation
- * Copyright (C) 2001,02,03 Miles Bader <miles@gnu.org>
- *
- * This file is subject to the terms and conditions of the GNU General
- * Public License. See the file COPYING in the main directory of this
- * archive for more details.
- *
- * Written by Miles Bader <miles@gnu.org>
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/console.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial.h>
-#include <linux/serial_core.h>
-
-#include <asm/nb85e_uart.h>
-#include <asm/nb85e_utils.h>
-
-/* Initial UART state. This may be overridden by machine-dependent headers. */
-#ifndef NB85E_UART_INIT_BAUD
-#define NB85E_UART_INIT_BAUD 115200
-#endif
-#ifndef NB85E_UART_INIT_CFLAGS
-#define NB85E_UART_INIT_CFLAGS (B115200 | CS8 | CREAD)
-#endif
-
-/* XXX This should be in a header file. */
-#define NB85E_UART_BRGC_MIN 8
-
-/* A string used for prefixing printed descriptions; since the same UART
- macro is actually used on other chips than the V850E/NB85E. This must
- be a constant string. */
-#ifndef NB85E_UART_CHIP_NAME
-#define NB85E_UART_CHIP_NAME "V850E/NB85E"
-#endif
-
-
-/* Helper functions for doing baud-rate/frequency calculations. */
-
-/* Calculate the minimum value for CKSR on this processor. */
-static inline unsigned cksr_min (void)
-{
- int min = 0;
- unsigned freq = NB85E_UART_BASE_FREQ;
- while (freq > NB85E_UART_CKSR_MAX_FREQ) {
- freq >>= 1;
- min++;
- }
- return min;
-}
-
-/* Minimum baud rate possible. */
-#define min_baud() \
- ((NB85E_UART_BASE_FREQ >> NB85E_UART_CKSR_MAX) / (2 * 255) + 1)
-
-/* Maximum baud rate possible. The error is quite high at max, though. */
-#define max_baud() \
- ((NB85E_UART_BASE_FREQ >> cksr_min()) / (2 * NB85E_UART_BRGC_MIN))
-
-
-/* Low-level UART functions. */
-
-/* These masks define which control bits affect TX/RX modes, respectively. */
-#define RX_BITS \
- (NB85E_UART_ASIM_PS_MASK | NB85E_UART_ASIM_CL_8 | NB85E_UART_ASIM_ISRM)
-#define TX_BITS \
- (NB85E_UART_ASIM_PS_MASK | NB85E_UART_ASIM_CL_8 | NB85E_UART_ASIM_SL_2)
-
-/* The UART require various delays after writing control registers. */
-static inline void nb85e_uart_delay (unsigned cycles)
-{
- /* The loop takes 2 insns, so loop CYCLES / 2 times. */
- register unsigned count = cycles >> 1;
- while (--count != 0)
- /* nothing */;
-}
-
-/* Configure and turn on uart channel CHAN, using the termios `control
- modes' bits in CFLAGS, and a baud-rate of BAUD. */
-void nb85e_uart_configure (unsigned chan, unsigned cflags, unsigned baud)
-{
- int flags;
- unsigned new_config = 0; /* What we'll write to the control reg. */
- unsigned new_clk_divlog2; /* New baud-rate generate clock divider. */
- unsigned new_brgen_count; /* New counter max for baud-rate generator.*/
- /* These are the current values corresponding to the above. */
- unsigned old_config, old_clk_divlog2, old_brgen_count;
-
- /* Calculate new baud-rate generator config values. */
-
- /* Calculate the log2 clock divider and baud-rate counter values
- (note that the UART divides the resulting clock by 2, so
- multiply BAUD by 2 here to compensate). */
- calc_counter_params (NB85E_UART_BASE_FREQ, baud * 2,
- cksr_min(), NB85E_UART_CKSR_MAX, 8/*bits*/,
- &new_clk_divlog2, &new_brgen_count);
-
- /* Figure out new configuration of control register. */
- if (cflags & CSTOPB)
- /* Number of stop bits, 1 or 2. */
- new_config |= NB85E_UART_ASIM_SL_2;
- if ((cflags & CSIZE) == CS8)
- /* Number of data bits, 7 or 8. */
- new_config |= NB85E_UART_ASIM_CL_8;
- if (! (cflags & PARENB))
- /* No parity check/generation. */
- new_config |= NB85E_UART_ASIM_PS_NONE;
- else if (cflags & PARODD)
- /* Odd parity check/generation. */
- new_config |= NB85E_UART_ASIM_PS_ODD;
- else
- /* Even parity check/generation. */
- new_config |= NB85E_UART_ASIM_PS_EVEN;
- if (cflags & CREAD)
- /* Reading enabled. */
- new_config |= NB85E_UART_ASIM_RXE;
-
- new_config |= NB85E_UART_ASIM_TXE; /* Writing is always enabled. */
- new_config |= NB85E_UART_ASIM_CAE;
- new_config |= NB85E_UART_ASIM_ISRM; /* Errors generate a read-irq. */
-
- /* Disable interrupts while we're twiddling the hardware. */
- local_irq_save (flags);
-
-#ifdef NB85E_UART_PRE_CONFIGURE
- NB85E_UART_PRE_CONFIGURE (chan, cflags, baud);
-#endif
-
- old_config = NB85E_UART_ASIM (chan);
- old_clk_divlog2 = NB85E_UART_CKSR (chan);
- old_brgen_count = NB85E_UART_BRGC (chan);
-
- if (new_clk_divlog2 != old_clk_divlog2
- || new_brgen_count != old_brgen_count)
- {
- /* The baud rate has changed. First, disable the UART. */
- NB85E_UART_ASIM (chan) = 0;
- old_config = 0;
- /* Reprogram the baud-rate generator. */
- NB85E_UART_CKSR (chan) = new_clk_divlog2;
- NB85E_UART_BRGC (chan) = new_brgen_count;
- }
-
- if (! (old_config & NB85E_UART_ASIM_CAE)) {
- /* If we are enabling the uart for the first time, start
- by turning on the enable bit, which must be done
- before turning on any other bits. */
- NB85E_UART_ASIM (chan) = NB85E_UART_ASIM_CAE;
- /* Enabling the uart also resets it. */
- old_config = NB85E_UART_ASIM_CAE;
- }
-
- if (new_config != old_config) {
- /* Which of the TXE/RXE bits we'll temporarily turn off
- before changing other control bits. */
- unsigned temp_disable = 0;
- /* Which of the TXE/RXE bits will be enabled. */
- unsigned enable = 0;
- unsigned changed_bits = new_config ^ old_config;
-
- /* Which of RX/TX will be enabled in the new configuration. */
- if (new_config & RX_BITS)
- enable |= (new_config & NB85E_UART_ASIM_RXE);
- if (new_config & TX_BITS)
- enable |= (new_config & NB85E_UART_ASIM_TXE);
-
- /* Figure out which of RX/TX needs to be disabled; note
- that this will only happen if they're not already
- disabled. */
- if (changed_bits & RX_BITS)
- temp_disable |= (old_config & NB85E_UART_ASIM_RXE);
- if (changed_bits & TX_BITS)
- temp_disable |= (old_config & NB85E_UART_ASIM_TXE);
-
- /* We have to turn off RX and/or TX mode before changing
- any associated control bits. */
- if (temp_disable)
- NB85E_UART_ASIM (chan) = old_config & ~temp_disable;
-
- /* Write the new control bits, while RX/TX are disabled. */
- if (changed_bits & ~enable)
- NB85E_UART_ASIM (chan) = new_config & ~enable;
-
- /* The UART may not be reset properly unless we
- wait at least 2 `basic-clocks' until turning
- on the TXE/RXE bits again. A `basic clock'
- is the clock used by the baud-rate generator, i.e.,
- the cpu clock divided by the 2^new_clk_divlog2. */
- nb85e_uart_delay (1 << (new_clk_divlog2 + 1));
-
- /* Write the final version, with enable bits turned on. */
- NB85E_UART_ASIM (chan) = new_config;
- }
-
- local_irq_restore (flags);
-}
-
-
-/* Low-level console. */
-
-#ifdef CONFIG_V850E_NB85E_UART_CONSOLE
-
-static void nb85e_uart_cons_write (struct console *co,
- const char *s, unsigned count)
-{
- if (count > 0) {
- unsigned chan = co->index;
- unsigned irq = IRQ_INTST (chan);
- int irq_was_enabled, irq_was_pending, flags;
-
- /* We don't want to get `transmission completed' (INTST)
- interrupts, since we're busy-waiting, so we disable
- them while sending (we don't disable interrupts
- entirely because sending over a serial line is really
- slow). We save the status of INTST and restore it
- when we're done so that using printk doesn't
- interfere with normal serial transmission (other than
- interleaving the output, of course!). This should
- work correctly even if this function is interrupted
- and the interrupt printks something. */
-
- /* Disable interrupts while fiddling with INTST. */
- local_irq_save (flags);
- /* Get current INTST status. */
- irq_was_enabled = nb85e_intc_irq_enabled (irq);
- irq_was_pending = nb85e_intc_irq_pending (irq);
- /* Disable INTST if necessary. */
- if (irq_was_enabled)
- nb85e_intc_disable_irq (irq);
- /* Turn interrupts back on. */
- local_irq_restore (flags);
-
- /* Send characters. */
- while (count > 0) {
- int ch = *s++;
-
- if (ch == '\n') {
- /* We don't have the benefit of a tty
- driver, so translate NL into CR LF. */
- nb85e_uart_wait_for_xmit_ok (chan);
- nb85e_uart_putc (chan, '\r');
- }
-
- nb85e_uart_wait_for_xmit_ok (chan);
- nb85e_uart_putc (chan, ch);
-
- count--;
- }
-
- /* Restore saved INTST status. */
- if (irq_was_enabled) {
- /* Wait for the last character we sent to be
- completely transmitted (as we'll get an INTST
- interrupt at that point). */
- nb85e_uart_wait_for_xmit_done (chan);
- /* Clear pending interrupts received due
- to our transmission, unless there was already
- one pending, in which case we want the
- handler to be called. */
- if (! irq_was_pending)
- nb85e_intc_clear_pending_irq (irq);
- /* ... and then turn back on handling. */
- nb85e_intc_enable_irq (irq);
- }
- }
-}
-
-extern struct uart_driver nb85e_uart_driver;
-static struct console nb85e_uart_cons =
-{
- .name = "ttyS",
- .write = nb85e_uart_cons_write,
- .device = uart_console_device,
- .flags = CON_PRINTBUFFER,
- .cflag = NB85E_UART_INIT_CFLAGS,
- .index = -1,
- .data = &nb85e_uart_driver,
-};
-
-void nb85e_uart_cons_init (unsigned chan)
-{
- nb85e_uart_configure (chan, NB85E_UART_INIT_CFLAGS,
- NB85E_UART_INIT_BAUD);
- nb85e_uart_cons.index = chan;
- register_console (&nb85e_uart_cons);
- printk ("Console: %s on-chip UART channel %d\n",
- NB85E_UART_CHIP_NAME, chan);
-}
-
-#define NB85E_UART_CONSOLE &nb85e_uart_cons
-
-#else /* !CONFIG_V850E_NB85E_UART_CONSOLE */
-#define NB85E_UART_CONSOLE 0
-#endif /* CONFIG_V850E_NB85E_UART_CONSOLE */
-
-/* TX/RX interrupt handlers. */
-
-static void nb85e_uart_stop_tx (struct uart_port *port, unsigned tty_stop);
-
-void nb85e_uart_tx (struct uart_port *port)
-{
- struct circ_buf *xmit = &port->info->xmit;
- int stopped = uart_tx_stopped (port);
-
- if (nb85e_uart_xmit_ok (port->line)) {
- int tx_ch;
-
- if (port->x_char) {
- tx_ch = port->x_char;
- port->x_char = 0;
- } else if (!uart_circ_empty (xmit) && !stopped) {
- tx_ch = xmit->buf[xmit->tail];
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- } else
- goto no_xmit;
-
- nb85e_uart_putc (port->line, tx_ch);
- port->icount.tx++;
-
- if (uart_circ_chars_pending (xmit) < WAKEUP_CHARS)
- uart_write_wakeup (port);
- }
-
- no_xmit:
- if (uart_circ_empty (xmit) || stopped)
- nb85e_uart_stop_tx (port, stopped);
-}
-
-static void nb85e_uart_tx_irq (int irq, void *data, struct pt_regs *regs)
-{
- struct uart_port *port = data;
- nb85e_uart_tx (port);
-}
-
-static void nb85e_uart_rx_irq (int irq, void *data, struct pt_regs *regs)
-{
- struct uart_port *port = data;
- unsigned ch_stat = TTY_NORMAL;
- unsigned ch = NB85E_UART_RXB (port->line);
- unsigned err = NB85E_UART_ASIS (port->line);
-
- if (err) {
- if (err & NB85E_UART_ASIS_OVE) {
- ch_stat = TTY_OVERRUN;
- port->icount.overrun++;
- } else if (err & NB85E_UART_ASIS_FE) {
- ch_stat = TTY_FRAME;
- port->icount.frame++;
- } else if (err & NB85E_UART_ASIS_PE) {
- ch_stat = TTY_PARITY;
- port->icount.parity++;
- }
- }
-
- port->icount.rx++;
-
- tty_insert_flip_char (port->info->tty, ch, ch_stat);
- tty_schedule_flip (port->info->tty);
-}
-
-/* Control functions for the serial framework. */
-
-static void nb85e_uart_nop (struct uart_port *port) { }
-static int nb85e_uart_success (struct uart_port *port) { return 0; }
-
-static unsigned nb85e_uart_tx_empty (struct uart_port *port)
-{
- return TIOCSER_TEMT; /* Can't detect. */
-}
-
-static void nb85e_uart_set_mctrl (struct uart_port *port, unsigned mctrl)
-{
-#ifdef NB85E_UART_SET_RTS
- NB85E_UART_SET_RTS (port->line, (mctrl & TIOCM_RTS));
-#endif
-}
-
-static unsigned nb85e_uart_get_mctrl (struct uart_port *port)
-{
- /* We don't support DCD or DSR, so consider them permanently active. */
- int mctrl = TIOCM_CAR | TIOCM_DSR;
-
- /* We may support CTS. */
-#ifdef NB85E_UART_CTS
- mctrl |= NB85E_UART_CTS(port->line) ? TIOCM_CTS : 0;
-#else
- mctrl |= TIOCM_CTS;
-#endif
-
- return mctrl;
-}
-
-static void nb85e_uart_start_tx (struct uart_port *port, unsigned tty_start)
-{
- nb85e_intc_disable_irq (IRQ_INTST (port->line));
- nb85e_uart_tx (port);
- nb85e_intc_enable_irq (IRQ_INTST (port->line));
-}
-
-static void nb85e_uart_stop_tx (struct uart_port *port, unsigned tty_stop)
-{
- nb85e_intc_disable_irq (IRQ_INTST (port->line));
-}
-
-static void nb85e_uart_start_rx (struct uart_port *port)
-{
- nb85e_intc_enable_irq (IRQ_INTSR (port->line));
-}
-
-static void nb85e_uart_stop_rx (struct uart_port *port)
-{
- nb85e_intc_disable_irq (IRQ_INTSR (port->line));
-}
-
-static void nb85e_uart_break_ctl (struct uart_port *port, int break_ctl)
-{
- /* Umm, do this later. */
-}
-
-static int nb85e_uart_startup (struct uart_port *port)
-{
- int err;
-
- /* Alloc RX irq. */
- err = request_irq (IRQ_INTSR (port->line), nb85e_uart_rx_irq,
- SA_INTERRUPT, "nb85e_uart", port);
- if (err)
- return err;
-
- /* Alloc TX irq. */
- err = request_irq (IRQ_INTST (port->line), nb85e_uart_tx_irq,
- SA_INTERRUPT, "nb85e_uart", port);
- if (err) {
- free_irq (IRQ_INTSR (port->line), port);
- return err;
- }
-
- nb85e_uart_start_rx (port);
-
- return 0;
-}
-
-static void nb85e_uart_shutdown (struct uart_port *port)
-{
- /* Disable port interrupts. */
- free_irq (IRQ_INTST (port->line), port);
- free_irq (IRQ_INTSR (port->line), port);
-
- /* Turn off xmit/recv enable bits. */
- NB85E_UART_ASIM (port->line)
- &= ~(NB85E_UART_ASIM_TXE | NB85E_UART_ASIM_RXE);
- /* Then reset the channel. */
- NB85E_UART_ASIM (port->line) = 0;
-}
-
-static void
-nb85e_uart_set_termios (struct uart_port *port, struct termios *termios,
- struct termios *old)
-{
- unsigned cflags = termios->c_cflag;
-
- /* Restrict flags to legal values. */
- if ((cflags & CSIZE) != CS7 && (cflags & CSIZE) != CS8)
- /* The new value of CSIZE is invalid, use the old value. */
- cflags = (cflags & ~CSIZE)
- | (old ? (old->c_cflag & CSIZE) : CS8);
-
- termios->c_cflag = cflags;
-
- nb85e_uart_configure (port->line, cflags,
- uart_get_baud_rate (port, termios, old,
- min_baud(), max_baud()));
-}
-
-static const char *nb85e_uart_type (struct uart_port *port)
-{
- return port->type == PORT_NB85E_UART ? "nb85e_uart" : 0;
-}
-
-static void nb85e_uart_config_port (struct uart_port *port, int flags)
-{
- if (flags & UART_CONFIG_TYPE)
- port->type = PORT_NB85E_UART;
-}
-
-static int
-nb85e_uart_verify_port (struct uart_port *port, struct serial_struct *ser)
-{
- if (ser->type != PORT_UNKNOWN && ser->type != PORT_NB85E_UART)
- return -EINVAL;
- if (ser->irq != IRQ_INTST (port->line))
- return -EINVAL;
- return 0;
-}
-
-static struct uart_ops nb85e_uart_ops = {
- .tx_empty = nb85e_uart_tx_empty,
- .get_mctrl = nb85e_uart_get_mctrl,
- .set_mctrl = nb85e_uart_set_mctrl,
- .start_tx = nb85e_uart_start_tx,
- .stop_tx = nb85e_uart_stop_tx,
- .stop_rx = nb85e_uart_stop_rx,
- .enable_ms = nb85e_uart_nop,
- .break_ctl = nb85e_uart_break_ctl,
- .startup = nb85e_uart_startup,
- .shutdown = nb85e_uart_shutdown,
- .set_termios = nb85e_uart_set_termios,
- .type = nb85e_uart_type,
- .release_port = nb85e_uart_nop,
- .request_port = nb85e_uart_success,
- .config_port = nb85e_uart_config_port,
- .verify_port = nb85e_uart_verify_port,
-};
-
-/* Initialization and cleanup. */
-
-static struct uart_driver nb85e_uart_driver = {
- .owner = THIS_MODULE,
- .driver_name = "nb85e_uart",
- .devfs_name = "tts/",
- .dev_name = "ttyS",
- .major = TTY_MAJOR,
- .minor = NB85E_UART_MINOR_BASE,
- .nr = NB85E_UART_NUM_CHANNELS,
- .cons = NB85E_UART_CONSOLE,
-};
-
-
-static struct uart_port nb85e_uart_ports[NB85E_UART_NUM_CHANNELS];
-
-static int __init nb85e_uart_init (void)
-{
- int rval;
-
- printk (KERN_INFO "%s on-chip UART\n", NB85E_UART_CHIP_NAME);
-
- rval = uart_register_driver (&nb85e_uart_driver);
- if (rval == 0) {
- unsigned chan;
-
- for (chan = 0; chan < NB85E_UART_NUM_CHANNELS; chan++) {
- struct uart_port *port = &nb85e_uart_ports[chan];
-
- memset (port, 0, sizeof *port);
-
- port->ops = &nb85e_uart_ops;
- port->line = chan;
- port->iotype = SERIAL_IO_MEM;
- port->flags = UPF_BOOT_AUTOCONF;
-
- /* We actually use multiple IRQs, but the serial
- framework seems to mainly use this for
- informational purposes anyway. Here we use the TX
- irq. */
- port->irq = IRQ_INTST (chan);
-
- /* The serial framework doesn't really use these
- membase/mapbase fields for anything useful, but
- it requires that they be something non-zero to
- consider the port `valid', and also uses them
- for informational purposes. */
- port->membase = (void *)NB85E_UART_BASE_ADDR (chan);
- port->mapbase = NB85E_UART_BASE_ADDR (chan);
-
- /* The framework insists on knowing the uart's master
- clock freq, though it doesn't seem to do anything
- useful for us with it. We must make it at least
- higher than (the maximum baud rate * 16), otherwise
- the framework will puke during its internal
- calculations, and force the baud rate to be 9600.
- To be accurate though, just repeat the calculation
- we use when actually setting the speed.
-
- The `* 8' means `* 16 / 2': 16 to account for for
- the serial framework's built-in bias, and 2 because
- there's an additional / 2 in the hardware. */
- port->uartclk =
- (NB85E_UART_BASE_FREQ >> cksr_min()) * 8;
-
- uart_add_one_port (&nb85e_uart_driver, port);
- }
- }
-
- return rval;
-}
-
-static void __exit nb85e_uart_exit (void)
-{
- unsigned chan;
-
- for (chan = 0; chan < NB85E_UART_NUM_CHANNELS; chan++)
- uart_remove_one_port (&nb85e_uart_driver,
- &nb85e_uart_ports[chan]);
-
- uart_unregister_driver (&nb85e_uart_driver);
-}
-
-module_init (nb85e_uart_init);
-module_exit (nb85e_uart_exit);
-
-MODULE_AUTHOR ("Miles Bader");
-MODULE_DESCRIPTION ("NEC " NB85E_UART_CHIP_NAME " on-chip UART");
-MODULE_LICENSE ("GPL");
diff --git a/drivers/serial/v850e_uart.c b/drivers/serial/v850e_uart.c
new file mode 100644
index 000000000000..bb482780a41d
--- /dev/null
+++ b/drivers/serial/v850e_uart.c
@@ -0,0 +1,549 @@
+/*
+ * drivers/serial/v850e_uart.c -- Serial I/O using V850E on-chip UART or UARTB
+ *
+ * Copyright (C) 2001,02,03 NEC Electronics Corporation
+ * Copyright (C) 2001,02,03 Miles Bader <miles@gnu.org>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file COPYING in the main directory of this
+ * archive for more details.
+ *
+ * Written by Miles Bader <miles@gnu.org>
+ */
+
+/* This driver supports both the original V850E UART interface (called
+ merely `UART' in the docs) and the newer `UARTB' interface, which is
+ roughly a superset of the first one. The selection is made at
+ configure time -- if CONFIG_V850E_UARTB is defined, then UARTB is
+ presumed, otherwise the old UART -- as these are on-CPU UARTS, a system
+ can never have both.
+
+ The UARTB interface also has a 16-entry FIFO mode, which is not
+ yet supported by this driver. */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/console.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+
+#include <asm/v850e_uart.h>
+
+/* Initial UART state. This may be overridden by machine-dependent headers. */
+#ifndef V850E_UART_INIT_BAUD
+#define V850E_UART_INIT_BAUD 115200
+#endif
+#ifndef V850E_UART_INIT_CFLAGS
+#define V850E_UART_INIT_CFLAGS (B115200 | CS8 | CREAD)
+#endif
+
+/* A string used for prefixing printed descriptions; since the same UART
+ macro is actually used on other chips than the V850E. This must be a
+ constant string. */
+#ifndef V850E_UART_CHIP_NAME
+#define V850E_UART_CHIP_NAME "V850E"
+#endif
+
+#define V850E_UART_MINOR_BASE 64 /* First tty minor number */
+
+
+/* Low-level UART functions. */
+
+/* Configure and turn on uart channel CHAN, using the termios `control
+ modes' bits in CFLAGS, and a baud-rate of BAUD. */
+void v850e_uart_configure (unsigned chan, unsigned cflags, unsigned baud)
+{
+ int flags;
+ v850e_uart_speed_t old_speed;
+ v850e_uart_config_t old_config;
+ v850e_uart_speed_t new_speed = v850e_uart_calc_speed (baud);
+ v850e_uart_config_t new_config = v850e_uart_calc_config (cflags);
+
+ /* Disable interrupts while we're twiddling the hardware. */
+ local_irq_save (flags);
+
+#ifdef V850E_UART_PRE_CONFIGURE
+ V850E_UART_PRE_CONFIGURE (chan, cflags, baud);
+#endif
+
+ old_config = V850E_UART_CONFIG (chan);
+ old_speed = v850e_uart_speed (chan);
+
+ if (! v850e_uart_speed_eq (old_speed, new_speed)) {
+ /* The baud rate has changed. First, disable the UART. */
+ V850E_UART_CONFIG (chan) = V850E_UART_CONFIG_FINI;
+ old_config = 0; /* Force the uart to be re-initialized. */
+
+ /* Reprogram the baud-rate generator. */
+ v850e_uart_set_speed (chan, new_speed);
+ }
+
+ if (! (old_config & V850E_UART_CONFIG_ENABLED)) {
+ /* If we are using the uart for the first time, start by
+ enabling it, which must be done before turning on any
+ other bits. */
+ V850E_UART_CONFIG (chan) = V850E_UART_CONFIG_INIT;
+ /* See the initial state. */
+ old_config = V850E_UART_CONFIG (chan);
+ }
+
+ if (new_config != old_config) {
+ /* Which of the TXE/RXE bits we'll temporarily turn off
+ before changing other control bits. */
+ unsigned temp_disable = 0;
+ /* Which of the TXE/RXE bits will be enabled. */
+ unsigned enable = 0;
+ unsigned changed_bits = new_config ^ old_config;
+
+ /* Which of RX/TX will be enabled in the new configuration. */
+ if (new_config & V850E_UART_CONFIG_RX_BITS)
+ enable |= (new_config & V850E_UART_CONFIG_RX_ENABLE);
+ if (new_config & V850E_UART_CONFIG_TX_BITS)
+ enable |= (new_config & V850E_UART_CONFIG_TX_ENABLE);
+
+ /* Figure out which of RX/TX needs to be disabled; note
+ that this will only happen if they're not already
+ disabled. */
+ if (changed_bits & V850E_UART_CONFIG_RX_BITS)
+ temp_disable
+ |= (old_config & V850E_UART_CONFIG_RX_ENABLE);
+ if (changed_bits & V850E_UART_CONFIG_TX_BITS)
+ temp_disable
+ |= (old_config & V850E_UART_CONFIG_TX_ENABLE);
+
+ /* We have to turn off RX and/or TX mode before changing
+ any associated control bits. */
+ if (temp_disable)
+ V850E_UART_CONFIG (chan) = old_config & ~temp_disable;
+
+ /* Write the new control bits, while RX/TX are disabled. */
+ if (changed_bits & ~enable)
+ V850E_UART_CONFIG (chan) = new_config & ~enable;
+
+ v850e_uart_config_delay (new_config, new_speed);
+
+ /* Write the final version, with enable bits turned on. */
+ V850E_UART_CONFIG (chan) = new_config;
+ }
+
+ local_irq_restore (flags);
+}
+
+
+/* Low-level console. */
+
+#ifdef CONFIG_V850E_UART_CONSOLE
+
+static void v850e_uart_cons_write (struct console *co,
+ const char *s, unsigned count)
+{
+ if (count > 0) {
+ unsigned chan = co->index;
+ unsigned irq = V850E_UART_TX_IRQ (chan);
+ int irq_was_enabled, irq_was_pending, flags;
+
+ /* We don't want to get `transmission completed'
+ interrupts, since we're busy-waiting, so we disable them
+ while sending (we don't disable interrupts entirely
+ because sending over a serial line is really slow). We
+ save the status of the tx interrupt and restore it when
+ we're done so that using printk doesn't interfere with
+ normal serial transmission (other than interleaving the
+ output, of course!). This should work correctly even if
+ this function is interrupted and the interrupt printks
+ something. */
+
+ /* Disable interrupts while fiddling with tx interrupt. */
+ local_irq_save (flags);
+ /* Get current tx interrupt status. */
+ irq_was_enabled = v850e_intc_irq_enabled (irq);
+ irq_was_pending = v850e_intc_irq_pending (irq);
+ /* Disable tx interrupt if necessary. */
+ if (irq_was_enabled)
+ v850e_intc_disable_irq (irq);
+ /* Turn interrupts back on. */
+ local_irq_restore (flags);
+
+ /* Send characters. */
+ while (count > 0) {
+ int ch = *s++;
+
+ if (ch == '\n') {
+ /* We don't have the benefit of a tty
+ driver, so translate NL into CR LF. */
+ v850e_uart_wait_for_xmit_ok (chan);
+ v850e_uart_putc (chan, '\r');
+ }
+
+ v850e_uart_wait_for_xmit_ok (chan);
+ v850e_uart_putc (chan, ch);
+
+ count--;
+ }
+
+ /* Restore saved tx interrupt status. */
+ if (irq_was_enabled) {
+ /* Wait for the last character we sent to be
+ completely transmitted (as we'll get an
+ interrupt interrupt at that point). */
+ v850e_uart_wait_for_xmit_done (chan);
+ /* Clear pending interrupts received due
+ to our transmission, unless there was already
+ one pending, in which case we want the
+ handler to be called. */
+ if (! irq_was_pending)
+ v850e_intc_clear_pending_irq (irq);
+ /* ... and then turn back on handling. */
+ v850e_intc_enable_irq (irq);
+ }
+ }
+}
+
+extern struct uart_driver v850e_uart_driver;
+static struct console v850e_uart_cons =
+{
+ .name = "ttyS",
+ .write = v850e_uart_cons_write,
+ .device = uart_console_device,
+ .flags = CON_PRINTBUFFER,
+ .cflag = V850E_UART_INIT_CFLAGS,
+ .index = -1,
+ .data = &v850e_uart_driver,
+};
+
+void v850e_uart_cons_init (unsigned chan)
+{
+ v850e_uart_configure (chan, V850E_UART_INIT_CFLAGS,
+ V850E_UART_INIT_BAUD);
+ v850e_uart_cons.index = chan;
+ register_console (&v850e_uart_cons);
+ printk ("Console: %s on-chip UART channel %d\n",
+ V850E_UART_CHIP_NAME, chan);
+}
+
+/* This is what the init code actually calls. */
+static int v850e_uart_console_init (void)
+{
+ v850e_uart_cons_init (V850E_UART_CONSOLE_CHANNEL);
+ return 0;
+}
+console_initcall(v850e_uart_console_init);
+
+#define V850E_UART_CONSOLE &v850e_uart_cons
+
+#else /* !CONFIG_V850E_UART_CONSOLE */
+#define V850E_UART_CONSOLE 0
+#endif /* CONFIG_V850E_UART_CONSOLE */
+
+/* TX/RX interrupt handlers. */
+
+static void v850e_uart_stop_tx (struct uart_port *port, unsigned tty_stop);
+
+void v850e_uart_tx (struct uart_port *port)
+{
+ struct circ_buf *xmit = &port->info->xmit;
+ int stopped = uart_tx_stopped (port);
+
+ if (v850e_uart_xmit_ok (port->line)) {
+ int tx_ch;
+
+ if (port->x_char) {
+ tx_ch = port->x_char;
+ port->x_char = 0;
+ } else if (!uart_circ_empty (xmit) && !stopped) {
+ tx_ch = xmit->buf[xmit->tail];
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ } else
+ goto no_xmit;
+
+ v850e_uart_putc (port->line, tx_ch);
+ port->icount.tx++;
+
+ if (uart_circ_chars_pending (xmit) < WAKEUP_CHARS)
+ uart_write_wakeup (port);
+ }
+
+ no_xmit:
+ if (uart_circ_empty (xmit) || stopped)
+ v850e_uart_stop_tx (port, stopped);
+}
+
+static irqreturn_t v850e_uart_tx_irq(int irq, void *data, struct pt_regs *regs)
+{
+ struct uart_port *port = data;
+ v850e_uart_tx (port);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t v850e_uart_rx_irq(int irq, void *data, struct pt_regs *regs)
+{
+ struct uart_port *port = data;
+ unsigned ch_stat = TTY_NORMAL;
+ unsigned ch = v850e_uart_getc (port->line);
+ unsigned err = v850e_uart_err (port->line);
+
+ if (err) {
+ if (err & V850E_UART_ERR_OVERRUN) {
+ ch_stat = TTY_OVERRUN;
+ port->icount.overrun++;
+ } else if (err & V850E_UART_ERR_FRAME) {
+ ch_stat = TTY_FRAME;
+ port->icount.frame++;
+ } else if (err & V850E_UART_ERR_PARITY) {
+ ch_stat = TTY_PARITY;
+ port->icount.parity++;
+ }
+ }
+
+ port->icount.rx++;
+
+ tty_insert_flip_char (port->info->tty, ch, ch_stat);
+ tty_schedule_flip (port->info->tty);
+
+ return IRQ_HANDLED;
+}
+
+
+/* Control functions for the serial framework. */
+
+static void v850e_uart_nop (struct uart_port *port) { }
+static int v850e_uart_success (struct uart_port *port) { return 0; }
+
+static unsigned v850e_uart_tx_empty (struct uart_port *port)
+{
+ return TIOCSER_TEMT; /* Can't detect. */
+}
+
+static void v850e_uart_set_mctrl (struct uart_port *port, unsigned mctrl)
+{
+#ifdef V850E_UART_SET_RTS
+ V850E_UART_SET_RTS (port->line, (mctrl & TIOCM_RTS));
+#endif
+}
+
+static unsigned v850e_uart_get_mctrl (struct uart_port *port)
+{
+ /* We don't support DCD or DSR, so consider them permanently active. */
+ int mctrl = TIOCM_CAR | TIOCM_DSR;
+
+ /* We may support CTS. */
+#ifdef V850E_UART_CTS
+ mctrl |= V850E_UART_CTS(port->line) ? TIOCM_CTS : 0;
+#else
+ mctrl |= TIOCM_CTS;
+#endif
+
+ return mctrl;
+}
+
+static void v850e_uart_start_tx (struct uart_port *port, unsigned tty_start)
+{
+ v850e_intc_disable_irq (V850E_UART_TX_IRQ (port->line));
+ v850e_uart_tx (port);
+ v850e_intc_enable_irq (V850E_UART_TX_IRQ (port->line));
+}
+
+static void v850e_uart_stop_tx (struct uart_port *port, unsigned tty_stop)
+{
+ v850e_intc_disable_irq (V850E_UART_TX_IRQ (port->line));
+}
+
+static void v850e_uart_start_rx (struct uart_port *port)
+{
+ v850e_intc_enable_irq (V850E_UART_RX_IRQ (port->line));
+}
+
+static void v850e_uart_stop_rx (struct uart_port *port)
+{
+ v850e_intc_disable_irq (V850E_UART_RX_IRQ (port->line));
+}
+
+static void v850e_uart_break_ctl (struct uart_port *port, int break_ctl)
+{
+ /* Umm, do this later. */
+}
+
+static int v850e_uart_startup (struct uart_port *port)
+{
+ int err;
+
+ /* Alloc RX irq. */
+ err = request_irq (V850E_UART_RX_IRQ (port->line), v850e_uart_rx_irq,
+ SA_INTERRUPT, "v850e_uart", port);
+ if (err)
+ return err;
+
+ /* Alloc TX irq. */
+ err = request_irq (V850E_UART_TX_IRQ (port->line), v850e_uart_tx_irq,
+ SA_INTERRUPT, "v850e_uart", port);
+ if (err) {
+ free_irq (V850E_UART_RX_IRQ (port->line), port);
+ return err;
+ }
+
+ v850e_uart_start_rx (port);
+
+ return 0;
+}
+
+static void v850e_uart_shutdown (struct uart_port *port)
+{
+ /* Disable port interrupts. */
+ free_irq (V850E_UART_TX_IRQ (port->line), port);
+ free_irq (V850E_UART_RX_IRQ (port->line), port);
+
+ /* Turn off xmit/recv enable bits. */
+ V850E_UART_CONFIG (port->line)
+ &= ~(V850E_UART_CONFIG_TX_ENABLE
+ | V850E_UART_CONFIG_RX_ENABLE);
+ /* Then reset the channel. */
+ V850E_UART_CONFIG (port->line) = 0;
+}
+
+static void
+v850e_uart_set_termios (struct uart_port *port, struct termios *termios,
+ struct termios *old)
+{
+ unsigned cflags = termios->c_cflag;
+
+ /* Restrict flags to legal values. */
+ if ((cflags & CSIZE) != CS7 && (cflags & CSIZE) != CS8)
+ /* The new value of CSIZE is invalid, use the old value. */
+ cflags = (cflags & ~CSIZE)
+ | (old ? (old->c_cflag & CSIZE) : CS8);
+
+ termios->c_cflag = cflags;
+
+ v850e_uart_configure (port->line, cflags,
+ uart_get_baud_rate (port, termios, old,
+ v850e_uart_min_baud(),
+ v850e_uart_max_baud()));
+}
+
+static const char *v850e_uart_type (struct uart_port *port)
+{
+ return port->type == PORT_V850E_UART ? "v850e_uart" : 0;
+}
+
+static void v850e_uart_config_port (struct uart_port *port, int flags)
+{
+ if (flags & UART_CONFIG_TYPE)
+ port->type = PORT_V850E_UART;
+}
+
+static int
+v850e_uart_verify_port (struct uart_port *port, struct serial_struct *ser)
+{
+ if (ser->type != PORT_UNKNOWN && ser->type != PORT_V850E_UART)
+ return -EINVAL;
+ if (ser->irq != V850E_UART_TX_IRQ (port->line))
+ return -EINVAL;
+ return 0;
+}
+
+static struct uart_ops v850e_uart_ops = {
+ .tx_empty = v850e_uart_tx_empty,
+ .get_mctrl = v850e_uart_get_mctrl,
+ .set_mctrl = v850e_uart_set_mctrl,
+ .start_tx = v850e_uart_start_tx,
+ .stop_tx = v850e_uart_stop_tx,
+ .stop_rx = v850e_uart_stop_rx,
+ .enable_ms = v850e_uart_nop,
+ .break_ctl = v850e_uart_break_ctl,
+ .startup = v850e_uart_startup,
+ .shutdown = v850e_uart_shutdown,
+ .set_termios = v850e_uart_set_termios,
+ .type = v850e_uart_type,
+ .release_port = v850e_uart_nop,
+ .request_port = v850e_uart_success,
+ .config_port = v850e_uart_config_port,
+ .verify_port = v850e_uart_verify_port,
+};
+
+/* Initialization and cleanup. */
+
+static struct uart_driver v850e_uart_driver = {
+ .owner = THIS_MODULE,
+ .driver_name = "v850e_uart",
+ .devfs_name = "tts/",
+ .dev_name = "ttyS",
+ .major = TTY_MAJOR,
+ .minor = V850E_UART_MINOR_BASE,
+ .nr = V850E_UART_NUM_CHANNELS,
+ .cons = V850E_UART_CONSOLE,
+};
+
+
+static struct uart_port v850e_uart_ports[V850E_UART_NUM_CHANNELS];
+
+static int __init v850e_uart_init (void)
+{
+ int rval;
+
+ printk (KERN_INFO "%s on-chip UART\n", V850E_UART_CHIP_NAME);
+
+ rval = uart_register_driver (&v850e_uart_driver);
+ if (rval == 0) {
+ unsigned chan;
+
+ for (chan = 0; chan < V850E_UART_NUM_CHANNELS; chan++) {
+ struct uart_port *port = &v850e_uart_ports[chan];
+
+ memset (port, 0, sizeof *port);
+
+ port->ops = &v850e_uart_ops;
+ port->line = chan;
+ port->iotype = SERIAL_IO_MEM;
+ port->flags = UPF_BOOT_AUTOCONF;
+
+ /* We actually use multiple IRQs, but the serial
+ framework seems to mainly use this for
+ informational purposes anyway. Here we use the TX
+ irq. */
+ port->irq = V850E_UART_TX_IRQ (chan);
+
+ /* The serial framework doesn't really use these
+ membase/mapbase fields for anything useful, but
+ it requires that they be something non-zero to
+ consider the port `valid', and also uses them
+ for informational purposes. */
+ port->membase = (void *)V850E_UART_BASE_ADDR (chan);
+ port->mapbase = V850E_UART_BASE_ADDR (chan);
+
+ /* The framework insists on knowing the uart's master
+ clock freq, though it doesn't seem to do anything
+ useful for us with it. We must make it at least
+ higher than (the maximum baud rate * 16), otherwise
+ the framework will puke during its internal
+ calculations, and force the baud rate to be 9600.
+ To be accurate though, just repeat the calculation
+ we use when actually setting the speed. */
+ port->uartclk = v850e_uart_max_clock() * 16;
+
+ uart_add_one_port (&v850e_uart_driver, port);
+ }
+ }
+
+ return rval;
+}
+
+static void __exit v850e_uart_exit (void)
+{
+ unsigned chan;
+
+ for (chan = 0; chan < V850E_UART_NUM_CHANNELS; chan++)
+ uart_remove_one_port (&v850e_uart_driver,
+ &v850e_uart_ports[chan]);
+
+ uart_unregister_driver (&v850e_uart_driver);
+}
+
+module_init (v850e_uart_init);
+module_exit (v850e_uart_exit);
+
+MODULE_AUTHOR ("Miles Bader");
+MODULE_DESCRIPTION ("NEC " V850E_UART_CHIP_NAME " on-chip UART");
+MODULE_LICENSE ("GPL");
diff --git a/drivers/telephony/Kconfig b/drivers/telephony/Kconfig
index c51a4a09bfbf..b162876c83f7 100644
--- a/drivers/telephony/Kconfig
+++ b/drivers/telephony/Kconfig
@@ -39,7 +39,7 @@ config PHONE_IXJ
config PHONE_IXJ_PCMCIA
tristate "QuickNet Internet LineJack/PhoneJack PCMCIA support"
- depends on PHONE_IXJ
+ depends on PHONE_IXJ && PCMCIA
help
Say Y here to configure in PCMCIA service support for the Quicknet
cards manufactured by Quicknet Technologies, Inc. This changes the
diff --git a/drivers/usb/image/hpusbscsi.c b/drivers/usb/image/hpusbscsi.c
index cc1768849fcc..bc323a4c74bf 100644
--- a/drivers/usb/image/hpusbscsi.c
+++ b/drivers/usb/image/hpusbscsi.c
@@ -109,7 +109,8 @@ hpusbscsi_usb_probe(struct usb_interface *intf,
goto out_unlink_controlurb;
new->host->hostdata[0] = (unsigned long)new;
- scsi_add_host(new->host, &intf->dev);
+ scsi_add_host(new->host, &intf->dev); /* XXX handle failure */
+ scsi_scan_host(new->host);
new->sense_command[0] = REQUEST_SENSE;
new->sense_command[4] = HPUSBSCSI_SENSE_LENGTH;
diff --git a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c
index dcef1e90929d..e5f1a12dc2bb 100644
--- a/drivers/usb/image/microtek.c
+++ b/drivers/usb/image/microtek.c
@@ -817,7 +817,8 @@ static int mts_usb_probe(struct usb_interface *intf,
goto out_free_urb;
new_desc->host->hostdata[0] = (unsigned long)new_desc;
- scsi_add_host(new_desc->host, NULL);
+ scsi_add_host(new_desc->host, NULL); /* XXX handle failure */
+ scsi_scan_host(new_desc->host);
usb_set_intfdata(intf, new_desc);
return 0;
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index ef495072850f..ee67b5340adc 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -958,6 +958,8 @@ static int storage_probe(struct usb_interface *intf,
goto BadDevice;
}
+ scsi_scan_host(us->host);
+
printk(KERN_DEBUG
"WARNING: USB Mass Storage data integrity not assured\n");
printk(KERN_DEBUG
diff --git a/drivers/video/vesafb.c b/drivers/video/vesafb.c
index 24a207b98937..88571b368ddb 100644
--- a/drivers/video/vesafb.c
+++ b/drivers/video/vesafb.c
@@ -51,7 +51,7 @@ static struct fb_info fb_info;
static u32 pseudo_palette[17];
static int inverse = 0;
-static int mtrr = 0;
+static int mtrr = 1;
static int pmi_setpal = 0; /* pmi for palette changes ??? */
static int ypan = 0; /* 0..nothing, 1..ypan, 2..ywrap */
@@ -208,6 +208,8 @@ int __init vesafb_setup(char *options)
pmi_setpal=1;
else if (! strcmp(this_opt, "mtrr"))
mtrr=1;
+ else if (! strcmp(this_opt, "nomtrr"))
+ mtrr=0;
}
return 0;
}
@@ -231,6 +233,12 @@ int __init vesafb_init(void)
vesafb_fix.visual = (vesafb_defined.bits_per_pixel == 8) ?
FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
+ /* limit framebuffer size to 16 MB. Otherwise we'll eat tons of
+ * kernel address space for nothing if the gfx card has alot of
+ * memory (>= 128 MB isn't uncommon these days ...) */
+ if (vesafb_fix.smem_len > 16 * 1024 * 1024)
+ vesafb_fix.smem_len = 16 * 1024 * 1024;
+
#ifndef __i386__
screen_info.vesapm_seg = 0;
#endif
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index d808a9dfc9ec..53938f81c696 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -1158,7 +1158,7 @@ static int elf_dump_thread_status(long signr, struct task_struct * p, struct lis
t->num_notes++;
sz += notesize(&t->notes[0]);
- if ((t->prstatus.pr_fpvalid = elf_core_copy_task_fpregs(p, &t->fpu))) {
+ if ((t->prstatus.pr_fpvalid = elf_core_copy_task_fpregs(p, NULL, &t->fpu))) {
fill_note(&t->notes[1], "CORE", NT_PRFPREG, sizeof(t->fpu), &(t->fpu));
t->num_notes++;
sz += notesize(&t->notes[1]);
@@ -1286,7 +1286,7 @@ static int elf_core_dump(long signr, struct pt_regs * regs, struct file * file)
fill_note(notes +2, "CORE", NT_TASKSTRUCT, sizeof(*current), current);
/* Try to dump the FPU. */
- if ((prstatus->pr_fpvalid = elf_core_copy_task_fpregs(current, fpu)))
+ if ((prstatus->pr_fpvalid = elf_core_copy_task_fpregs(current, regs, fpu)))
fill_note(notes +3, "CORE", NT_PRFPREG, sizeof(*fpu), fpu);
else
--numnote;
diff --git a/fs/devfs/base.c b/fs/devfs/base.c
index f724de9f7f7d..54a3e5a9dc49 100644
--- a/fs/devfs/base.c
+++ b/fs/devfs/base.c
@@ -676,6 +676,7 @@
#include <linux/smp.h>
#include <linux/version.h>
#include <linux/rwsem.h>
+#include <linux/sched.h>
#include <asm/uaccess.h>
#include <asm/io.h>
@@ -1325,8 +1326,20 @@ static void free_dentry (struct devfs_entry *de)
static int is_devfsd_or_child (struct fs_info *fs_info)
{
- if (current == fs_info->devfsd_task) return (TRUE);
- if (current->pgrp == fs_info->devfsd_pgrp) return (TRUE);
+ struct task_struct *p = current;
+
+ if (p == fs_info->devfsd_task) return (TRUE);
+ if (p->pgrp == fs_info->devfsd_pgrp) return (TRUE);
+ read_lock(&tasklist_lock);
+ for ( ; p != &init_task; p = p->real_parent)
+ {
+ if (p == fs_info->devfsd_task)
+ {
+ read_unlock (&tasklist_lock);
+ return (TRUE);
+ }
+ }
+ read_unlock (&tasklist_lock);
return (FALSE);
} /* End Function is_devfsd_or_child */
diff --git a/fs/ext3/acl.c b/fs/ext3/acl.c
index 2416e214280f..53051432b4bf 100644
--- a/fs/ext3/acl.c
+++ b/fs/ext3/acl.c
@@ -425,7 +425,7 @@ ext3_acl_chmod(struct inode *inode)
if (!error) {
handle_t *handle;
- handle = ext3_journal_start(inode, EXT3_XATTR_TRANS_BLOCKS);
+ handle = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS);
if (IS_ERR(handle)) {
error = PTR_ERR(handle);
ext3_std_error(inode->i_sb, error);
@@ -531,7 +531,7 @@ ext3_xattr_set_acl(struct inode *inode, int type, const void *value,
} else
acl = NULL;
- handle = ext3_journal_start(inode, EXT3_XATTR_TRANS_BLOCKS);
+ handle = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS);
if (IS_ERR(handle))
return PTR_ERR(handle);
error = ext3_set_acl(handle, inode, type, acl);
diff --git a/fs/ext3/xattr.c b/fs/ext3/xattr.c
index 6fbda077bdbe..402e30ca81fd 100644
--- a/fs/ext3/xattr.c
+++ b/fs/ext3/xattr.c
@@ -875,7 +875,7 @@ ext3_xattr_set(struct inode *inode, int name_index, const char *name,
handle_t *handle;
int error, error2;
- handle = ext3_journal_start(inode, EXT3_XATTR_TRANS_BLOCKS);
+ handle = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS);
if (IS_ERR(handle))
error = PTR_ERR(handle);
else
@@ -1050,12 +1050,10 @@ ext3_xattr_cache_find(handle_t *handle, struct inode *inode,
ext3_error(inode->i_sb, "ext3_xattr_cache_find",
"inode %ld: block %ld read error",
inode->i_ino, (unsigned long) ce->e_block);
- } else {
+ } else if (ext3_journal_get_write_access_credits(
+ handle, bh, credits) == 0) {
/* ext3_journal_get_write_access() requires an unlocked
* bh, which complicates things here. */
- if (ext3_journal_get_write_access_credits(handle, bh,
- credits) != 0)
- return NULL;
lock_buffer(bh);
if (le32_to_cpu(HDR(bh)->h_refcount) >
EXT3_XATTR_REFCOUNT_MAX) {
@@ -1070,6 +1068,7 @@ ext3_xattr_cache_find(handle_t *handle, struct inode *inode,
}
unlock_buffer(bh);
journal_release_buffer(handle, bh, *credits);
+ *credits = 0;
brelse(bh);
}
ce = mb_cache_entry_find_next(ce, 0, inode->i_sb->s_bdev, hash);
diff --git a/fs/jbd/transaction.c b/fs/jbd/transaction.c
index 1423dadf3db9..fd274a984f34 100644
--- a/fs/jbd/transaction.c
+++ b/fs/jbd/transaction.c
@@ -742,7 +742,7 @@ int journal_get_write_access(handle_t *handle,
/* We do not want to get caught playing with fields which the
* log thread also manipulates. Make sure that the buffer
* completes any outstanding IO before proceeding. */
- rc = do_get_write_access(handle, jh, 0, NULL);
+ rc = do_get_write_access(handle, jh, 0, credits);
journal_put_journal_head(jh);
return rc;
}
@@ -1088,6 +1088,7 @@ int journal_dirty_metadata(handle_t *handle, struct buffer_head *bh)
transaction_t *transaction = handle->h_transaction;
journal_t *journal = transaction->t_journal;
struct journal_head *jh = bh2jh(bh);
+ int console_loglevel_saved = console_loglevel;
jbd_debug(5, "journal_head %p\n", jh);
JBUFFER_TRACE(jh, "entry");
@@ -1106,16 +1107,6 @@ int journal_dirty_metadata(handle_t *handle, struct buffer_head *bh)
if (jh->b_transaction == handle->h_transaction &&
jh->b_jlist == BJ_Metadata) {
JBUFFER_TRACE(jh, "fastpath");
- console_verbose();
- if (jh->b_transaction != journal->j_running_transaction) {
- printk("jh->b_transaction=%p\n", jh->b_transaction);
- printk("journal->j_running_transaction=%p\n",
- journal->j_running_transaction);
- printk("handle->h_transaction=%p\n",
- handle->h_transaction);
- printk("journal->j_committing_transaction=%p\n",
- journal->j_committing_transaction);
- }
J_ASSERT_JH(jh, jh->b_transaction ==
journal->j_running_transaction);
goto out_unlock_bh;
@@ -1156,6 +1147,7 @@ out_unlock_bh:
jbd_unlock_bh_state(bh);
out:
JBUFFER_TRACE(jh, "exit");
+ console_loglevel = console_loglevel_saved;
return 0;
}
@@ -1328,9 +1320,6 @@ int journal_stop(handle_t *handle)
journal_t *journal = transaction->t_journal;
int old_handle_count, err;
- if (!handle)
- return 0;
-
J_ASSERT(transaction->t_updates > 0);
J_ASSERT(journal_current_handle() == handle);
diff --git a/fs/jffs2/Makefile b/fs/jffs2/Makefile
index cd9871f6ec20..de0e41895ae1 100644
--- a/fs/jffs2/Makefile
+++ b/fs/jffs2/Makefile
@@ -13,6 +13,7 @@ JFFS2_OBJS := dir.o file.o ioctl.o nodelist.o malloc.o \
LINUX_OBJS-24 := super-v24.o crc32.o
LINUX_OBJS-25 := super.o
+LINUX_OBJS-26 := super.o
NAND_OBJS-$(CONFIG_JFFS2_FS_NAND) := wbuf.o
diff --git a/fs/namespace.c b/fs/namespace.c
index 12a8c8146829..8a3552bd6660 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -1158,3 +1158,13 @@ void __init mnt_init(unsigned long mempages)
init_rootfs();
init_mount_tree();
}
+
+void __put_namespace(struct namespace *namespace)
+{
+ down_write(&namespace->sem);
+ spin_lock(&vfsmount_lock);
+ umount_tree(namespace->root);
+ spin_unlock(&vfsmount_lock);
+ up_write(&namespace->sem);
+ kfree(namespace);
+}
diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c
index 7b359269f58e..0c60862ba9c0 100644
--- a/fs/nfs/nfs3xdr.c
+++ b/fs/nfs/nfs3xdr.c
@@ -124,8 +124,6 @@ xdr_decode_fhandle(u32 *p, struct nfs_fh *fh)
/*
* Encode/decode time.
- * Since the VFS doesn't care for fractional times, we ignore the
- * nanosecond field.
*/
static inline u32 *
xdr_encode_time3(u32 *p, struct timespec *timep)
diff --git a/fs/partitions/check.c b/fs/partitions/check.c
index 8e27770e2910..5b21b60c20b5 100644
--- a/fs/partitions/check.c
+++ b/fs/partitions/check.c
@@ -347,6 +347,9 @@ void register_disk(struct gendisk *disk)
return;
}
+ /* always add handle for the whole disk */
+ devfs_add_partitioned(disk);
+
/* No such device (e.g., media were just removed) */
if (!get_capacity(disk))
return;
@@ -355,7 +358,6 @@ void register_disk(struct gendisk *disk)
if (blkdev_get(bdev, FMODE_READ, 0, BDEV_RAW) < 0)
return;
state = check_partition(disk, bdev);
- devfs_add_partitioned(disk);
if (state) {
for (j = 1; j < state->limit; j++) {
sector_t size = state->parts[j].size;
diff --git a/include/asm-i386/thread_info.h b/include/asm-i386/thread_info.h
index a278e34aa158..1574d103074b 100644
--- a/include/asm-i386/thread_info.h
+++ b/include/asm-i386/thread_info.h
@@ -87,8 +87,8 @@ static inline struct thread_info *current_thread_info(void)
/* thread information allocation */
#define THREAD_SIZE (2*PAGE_SIZE)
-#define alloc_thread_info(tsk) ((struct thread_info *) __get_free_pages(GFP_KERNEL,1))
-#define free_thread_info(ti) free_pages((unsigned long) (ti), 1)
+#define alloc_thread_info(task) ((struct thread_info *)kmalloc(THREAD_SIZE, GFP_KERNEL))
+#define free_thread_info(info) kfree(info)
#define get_thread_info(ti) get_task_struct((ti)->task)
#define put_thread_info(ti) put_task_struct((ti)->task)
diff --git a/include/asm-v850/anna.h b/include/asm-v850/anna.h
index df5caefdc157..3be77d5ecfce 100644
--- a/include/asm-v850/anna.h
+++ b/include/asm-v850/anna.h
@@ -1,8 +1,8 @@
/*
* include/asm-v850/anna.h -- Anna V850E2 evaluation cpu chip/board
*
- * Copyright (C) 2001,2002 NEC Corporation
- * Copyright (C) 2001,2002 Miles Bader <miles@gnu.org>
+ * Copyright (C) 2001,02,03 NEC Electronics Corporation
+ * Copyright (C) 2001,02,03 Miles Bader <miles@gnu.org>
*
* This file is subject to the terms and conditions of the GNU General
* Public License. See the file COPYING in the main directory of this
@@ -14,8 +14,9 @@
#ifndef __V850_ANNA_H__
#define __V850_ANNA_H__
+#include <asm/v850e2.h> /* Based on V850E2 core. */
+
-#define CPU_ARCH "v850e2"
#define CPU_MODEL "v850e2/anna"
#define CPU_MODEL_LONG "NEC V850E2/Anna"
#define PLATFORM "anna"
@@ -48,30 +49,6 @@
/* Anna specific control registers. */
-#define ANNA_CSC_ADDR(n) (0xFFFFF060 + (n) * 2)
-#define ANNA_CSC(n) (*(volatile u16 *)ANNA_CSC_ADDR(n))
-#define ANNA_BPC_ADDR 0xFFFFF064
-#define ANNA_BPC (*(volatile u16 *)ANNA_BPC_ADDR)
-#define ANNA_BSC_ADDR 0xFFFFF066
-#define ANNA_BSC (*(volatile u16 *)ANNA_BSC_ADDR)
-#define ANNA_BEC_ADDR 0xFFFFF068
-#define ANNA_BEC (*(volatile u16 *)ANNA_BEC_ADDR)
-#define ANNA_BHC_ADDR 0xFFFFF06A
-#define ANNA_BHC (*(volatile u16 *)ANNA_BHC_ADDR)
-#define ANNA_BCT_ADDR(n) (0xFFFFF480 + (n) * 2)
-#define ANNA_BCT(n) (*(volatile u16 *)ANNA_BCT_ADDR(n))
-#define ANNA_DWC_ADDR(n) (0xFFFFF484 + (n) * 2)
-#define ANNA_DWC(n) (*(volatile u16 *)ANNA_DWC_ADDR(n))
-#define ANNA_BCC_ADDR 0xFFFFF488
-#define ANNA_BCC (*(volatile u16 *)ANNA_BCC_ADDR)
-#define ANNA_ASC_ADDR 0xFFFFF48A
-#define ANNA_ASC (*(volatile u16 *)ANNA_ASC_ADDR)
-#define ANNA_LBS_ADDR 0xFFFFF48E
-#define ANNA_LBS (*(volatile u16 *)ANNA_LBS_ADDR)
-#define ANNA_SCR3_ADDR 0xFFFFF4AC
-#define ANNA_SCR3 (*(volatile u16 *)ANNA_SCR3_ADDR)
-#define ANNA_RFS3_ADDR 0xFFFFF4AE
-#define ANNA_RFS3 (*(volatile u16 *)ANNA_RFS3_ADDR)
#define ANNA_ILBEN_ADDR 0xFFFFF7F2
#define ANNA_ILBEN (*(volatile u16 *)ANNA_ILBEN_ADDR)
@@ -85,9 +62,6 @@
#define ANNA_PORT_PM(n) (*(volatile u8 *)ANNA_PORT_PM_ADDR(n))
-/* NB85E-style interrupt system. */
-#include <asm/nb85e_intc.h>
-
/* Hardware-specific interrupt numbers (in the kernel IRQ namespace). */
#define IRQ_INTP(n) (n) /* Pnnn (pin) interrupts 0-15 */
#define IRQ_INTP_NUM 16
@@ -116,12 +90,15 @@ extern void anna_init_irqs (void);
/* Anna UART details (basically the same as the V850E/MA1, but 2 channels). */
-#define NB85E_UART_NUM_CHANNELS 2
-#define NB85E_UART_BASE_FREQ (SYS_CLOCK_FREQ / 2)
-#define NB85E_UART_CHIP_NAME "V850E2/NA85E2A"
+#define V850E_UART_NUM_CHANNELS 2
+#define V850E_UART_BASE_FREQ (SYS_CLOCK_FREQ / 2)
+#define V850E_UART_CHIP_NAME "V850E2/NA85E2A"
+
+/* This is the UART channel that's actually connected on the board. */
+#define V850E_UART_CONSOLE_CHANNEL 1
/* This is a function that gets called before configuring the UART. */
-#define NB85E_UART_PRE_CONFIGURE anna_uart_pre_configure
+#define V850E_UART_PRE_CONFIGURE anna_uart_pre_configure
#ifndef __ASSEMBLY__
extern void anna_uart_pre_configure (unsigned chan,
unsigned cflags, unsigned baud);
@@ -130,9 +107,9 @@ extern void anna_uart_pre_configure (unsigned chan,
/* This board supports RTS/CTS for the on-chip UART, but only for channel 1. */
/* CTS for UART channel 1 is pin P37 (bit 7 of port 3). */
-#define NB85E_UART_CTS(chan) ((chan) == 1 ? !(ANNA_PORT_IO(3) & 0x80) : 1)
+#define V850E_UART_CTS(chan) ((chan) == 1 ? !(ANNA_PORT_IO(3) & 0x80) : 1)
/* RTS for UART channel 1 is pin P07 (bit 7 of port 0). */
-#define NB85E_UART_SET_RTS(chan, val) \
+#define V850E_UART_SET_RTS(chan, val) \
do { \
if (chan == 1) { \
unsigned old = ANNA_PORT_IO(0); \
@@ -145,16 +122,16 @@ extern void anna_uart_pre_configure (unsigned chan,
/* Timer C details. */
-#define NB85E_TIMER_C_BASE_ADDR 0xFFFFF600
+#define V850E_TIMER_C_BASE_ADDR 0xFFFFF600
/* Timer D details (the Anna actually has 5 of these; should change later). */
-#define NB85E_TIMER_D_BASE_ADDR 0xFFFFF540
-#define NB85E_TIMER_D_TMD_BASE_ADDR (NB85E_TIMER_D_BASE_ADDR + 0x0)
-#define NB85E_TIMER_D_CMD_BASE_ADDR (NB85E_TIMER_D_BASE_ADDR + 0x2)
-#define NB85E_TIMER_D_TMCD_BASE_ADDR (NB85E_TIMER_D_BASE_ADDR + 0x4)
+#define V850E_TIMER_D_BASE_ADDR 0xFFFFF540
+#define V850E_TIMER_D_TMD_BASE_ADDR (V850E_TIMER_D_BASE_ADDR + 0x0)
+#define V850E_TIMER_D_CMD_BASE_ADDR (V850E_TIMER_D_BASE_ADDR + 0x2)
+#define V850E_TIMER_D_TMCD_BASE_ADDR (V850E_TIMER_D_BASE_ADDR + 0x4)
-#define NB85E_TIMER_D_BASE_FREQ SYS_CLOCK_FREQ
-#define NB85E_TIMER_D_TMCD_CS_MIN 1 /* min 2^1 divider */
+#define V850E_TIMER_D_BASE_FREQ SYS_CLOCK_FREQ
+#define V850E_TIMER_D_TMCD_CS_MIN 1 /* min 2^1 divider */
/* For <asm/param.h> */
diff --git a/include/asm-v850/as85ep1.h b/include/asm-v850/as85ep1.h
index 4216309005b6..659bc910ffd7 100644
--- a/include/asm-v850/as85ep1.h
+++ b/include/asm-v850/as85ep1.h
@@ -1,8 +1,8 @@
/*
* include/asm-v850/as85ep1.h -- AS85EP1 evaluation CPU chip/board
*
- * Copyright (C) 2001,2002 NEC Corporation
- * Copyright (C) 2001,2002 Miles Bader <miles@gnu.org>
+ * Copyright (C) 2001,02,03 NEC Electronics Corporation
+ * Copyright (C) 2001,02,03 Miles Bader <miles@gnu.org>
*
* This file is subject to the terms and conditions of the GNU General
* Public License. See the file COPYING in the main directory of this
@@ -14,8 +14,9 @@
#ifndef __V850_AS85EP1_H__
#define __V850_AS85EP1_H__
+#include <asm/v850e.h>
+
-#define CPU_ARCH "v850e"
#define CPU_MODEL "as85ep1"
#define CPU_MODEL_LONG "NEC V850E/AS85EP1"
#define PLATFORM "AS85EP1"
@@ -86,9 +87,6 @@
#define AS85EP1_PORT_PMC(n) (*(volatile u8 *)AS85EP1_PORT_PMC_ADDR(n))
-/* NB85E-style interrupt system. */
-#include <asm/nb85e_intc.h>
-
/* Hardware-specific interrupt numbers (in the kernel IRQ namespace). */
#define IRQ_INTCCC(n) (0x0C + (n))
#define IRQ_INTCCC_NUM 8
@@ -110,12 +108,12 @@ extern void as85ep1_init_irqs (void);
/* AS85EP1 UART details (basically the same as the V850E/MA1, but 2 channels). */
-#define NB85E_UART_NUM_CHANNELS 2
-#define NB85E_UART_BASE_FREQ (SYS_CLOCK_FREQ / 4)
-#define NB85E_UART_CHIP_NAME "V850E/NA85E"
+#define V850E_UART_NUM_CHANNELS 2
+#define V850E_UART_BASE_FREQ (SYS_CLOCK_FREQ / 4)
+#define V850E_UART_CHIP_NAME "V850E/NA85E"
/* This is a function that gets called before configuring the UART. */
-#define NB85E_UART_PRE_CONFIGURE as85ep1_uart_pre_configure
+#define V850E_UART_PRE_CONFIGURE as85ep1_uart_pre_configure
#ifndef __ASSEMBLY__
extern void as85ep1_uart_pre_configure (unsigned chan,
unsigned cflags, unsigned baud);
@@ -124,9 +122,9 @@ extern void as85ep1_uart_pre_configure (unsigned chan,
/* This board supports RTS/CTS for the on-chip UART, but only for channel 1. */
/* CTS for UART channel 1 is pin P54 (bit 4 of port 5). */
-#define NB85E_UART_CTS(chan) ((chan) == 1 ? !(AS85EP1_PORT_IO(5) & 0x10) : 1)
+#define V850E_UART_CTS(chan) ((chan) == 1 ? !(AS85EP1_PORT_IO(5) & 0x10) : 1)
/* RTS for UART channel 1 is pin P53 (bit 3 of port 5). */
-#define NB85E_UART_SET_RTS(chan, val) \
+#define V850E_UART_SET_RTS(chan, val) \
do { \
if (chan == 1) { \
unsigned old = AS85EP1_PORT_IO(5); \
@@ -139,16 +137,16 @@ extern void as85ep1_uart_pre_configure (unsigned chan,
/* Timer C details. */
-#define NB85E_TIMER_C_BASE_ADDR 0xFFFFF600
+#define V850E_TIMER_C_BASE_ADDR 0xFFFFF600
/* Timer D details (the AS85EP1 actually has 5 of these; should change later). */
-#define NB85E_TIMER_D_BASE_ADDR 0xFFFFF540
-#define NB85E_TIMER_D_TMD_BASE_ADDR (NB85E_TIMER_D_BASE_ADDR + 0x0)
-#define NB85E_TIMER_D_CMD_BASE_ADDR (NB85E_TIMER_D_BASE_ADDR + 0x2)
-#define NB85E_TIMER_D_TMCD_BASE_ADDR (NB85E_TIMER_D_BASE_ADDR + 0x4)
+#define V850E_TIMER_D_BASE_ADDR 0xFFFFF540
+#define V850E_TIMER_D_TMD_BASE_ADDR (V850E_TIMER_D_BASE_ADDR + 0x0)
+#define V850E_TIMER_D_CMD_BASE_ADDR (V850E_TIMER_D_BASE_ADDR + 0x2)
+#define V850E_TIMER_D_TMCD_BASE_ADDR (V850E_TIMER_D_BASE_ADDR + 0x4)
-#define NB85E_TIMER_D_BASE_FREQ SYS_CLOCK_FREQ
-#define NB85E_TIMER_D_TMCD_CS_MIN 2 /* min 2^2 divider */
+#define V850E_TIMER_D_BASE_FREQ SYS_CLOCK_FREQ
+#define V850E_TIMER_D_TMCD_CS_MIN 2 /* min 2^2 divider */
/* For <asm/param.h> */
diff --git a/include/asm-v850/asm.h b/include/asm-v850/asm.h
index 5b207f869017..bf1e785a5dde 100644
--- a/include/asm-v850/asm.h
+++ b/include/asm-v850/asm.h
@@ -1,7 +1,7 @@
/*
* include/asm-v850/asm.h -- Macros for writing assembly code
*
- * Copyright (C) 2001,02,03 NEC Corporation
+ * Copyright (C) 2001,02,03 NEC Electronics Corporation
* Copyright (C) 2001,02,03 Miles Bader <miles@gnu.org>
*
* This file is subject to the terms and conditions of the GNU General
diff --git a/include/asm-v850/cacheflush.h b/include/asm-v850/cacheflush.h
index 3584a7ee9f14..de27e98490f8 100644
--- a/include/asm-v850/cacheflush.h
+++ b/include/asm-v850/cacheflush.h
@@ -1,8 +1,8 @@
/*
* include/asm-v850/cacheflush.h
*
- * Copyright (C) 2001,02 NEC Corporation
- * Copyright (C) 2001,02 Miles Bader <miles@gnu.org>
+ * Copyright (C) 2001,02,03 NEC Electronics Corporation
+ * Copyright (C) 2001,02,03 Miles Bader <miles@gnu.org>
*
* This file is subject to the terms and conditions of the GNU General
* Public License. See the file COPYING in the main directory of this
@@ -21,21 +21,40 @@
#include <asm/machdep.h>
-#ifndef flush_cache_all
-/* If there's no flush_cache_all macro defined by <asm/machdep.h>, then
- this processor has no cache, so just define these as nops. */
-
+/* The following are all used by the kernel in ways that only affect
+ systems with MMUs, so we don't need them. */
#define flush_cache_all() ((void)0)
#define flush_cache_mm(mm) ((void)0)
#define flush_cache_range(vma, start, end) ((void)0)
#define flush_cache_page(vma, vmaddr) ((void)0)
#define flush_dcache_page(page) ((void)0)
+
+#ifdef CONFIG_NO_CACHE
+
+/* Some systems have no cache at all, in which case we don't need these
+ either. */
#define flush_icache() ((void)0)
#define flush_icache_range(start, end) ((void)0)
#define flush_icache_page(vma,pg) ((void)0)
#define flush_icache_user_range(vma,pg,adr,len) ((void)0)
#define flush_cache_sigtramp(vaddr) ((void)0)
-#endif /* !flush_cache_all */
+#else /* !CONFIG_NO_CACHE */
+
+struct page;
+struct mm_struct;
+struct vm_area_struct;
+
+/* Otherwise, somebody had better define them. */
+extern void flush_icache (void);
+extern void flush_icache_range (unsigned long start, unsigned long end);
+extern void flush_icache_page (struct vm_area_struct *vma, struct page *page);
+extern void flush_icache_user_range (struct vm_area_struct *vma,
+ struct page *page,
+ unsigned long adr, int len);
+extern void flush_cache_sigtramp (unsigned long addr);
+
+#endif /* CONFIG_NO_CACHE */
+
#endif /* __V850_CACHEFLUSH_H__ */
diff --git a/include/asm-v850/entry.h b/include/asm-v850/entry.h
index 7d239eb1cad0..d9df8ac48584 100644
--- a/include/asm-v850/entry.h
+++ b/include/asm-v850/entry.h
@@ -65,10 +65,10 @@
#define RESET_GUARD_ACTIVE 0xFAB4BEEF
#endif /* CONFIG_RESET_GUARD */
-#ifdef CONFIG_V850E_MA1_HIGHRES_TIMER
+#ifdef CONFIG_V850E_HIGHRES_TIMER
#define HIGHRES_TIMER_SLOW_TICKS_ADDR (KERNEL_VAR_SPACE_ADDR + 32)
#define HIGHRES_TIMER_SLOW_TICKS KERNEL_VAR (HIGHRES_TIMER_SLOW_TICKS_ADDR)
-#endif /* CONFIG_V850E_MA1_HIGHRES_TIMER */
+#endif /* CONFIG_V850E_HIGHRES_TIMER */
#ifndef __ASSEMBLY__
diff --git a/include/asm-v850/fpga85e2c.h b/include/asm-v850/fpga85e2c.h
index 54343b18e650..d32f04504b13 100644
--- a/include/asm-v850/fpga85e2c.h
+++ b/include/asm-v850/fpga85e2c.h
@@ -2,8 +2,8 @@
* include/asm-v850/fpga85e2c.h -- Machine-dependent defs for
* FPGA implementation of V850E2/NA85E2C
*
- * Copyright (C) 2002 NEC Corporation
- * Copyright (C) 2002 Miles Bader <miles@gnu.org>
+ * Copyright (C) 2002,03 NEC Electronics Corporation
+ * Copyright (C) 2002,03 Miles Bader <miles@gnu.org>
*
* This file is subject to the terms and conditions of the GNU General
* Public License. See the file COPYING in the main directory of this
@@ -15,11 +15,10 @@
#ifndef __V850_FPGA85E2C_H__
#define __V850_FPGA85E2C_H__
-
+#include <asm/v850e2.h>
#include <asm/clinkage.h>
-#define CPU_ARCH "v850e2"
#define CPU_MODEL "v850e2/fpga85e2c"
#define CPU_MODEL_LONG "NEC V850E2/NA85E2C"
#define PLATFORM "fpga85e2c"
@@ -42,27 +41,6 @@
#define CSDEV_ADDR(n) (0xFFE80110 + 2*(n))
#define CSDEV(n) (*(volatile unsigned char *)CSDEV_ADDR (n))
-/* The BSC register controls bus-sizing. Each memory area CSn uses a pair
- of bits N*2 and N*2+1, where 00 means an 8-bit bus size, 01 16-bit, and
- 10 32-bit. */
-#define BSC_ADDR 0xFFFFF066
-#define BSC (*(volatile unsigned short *)BSC_ADDR)
-
-#define DWC_ADDR(n) (0xFFFFF484 + 2*(n))
-#define DWC(n) (*(volatile unsigned short *)DWC_ADDR (n))
-
-#define ASC_ADDR 0xFFFFF48A
-#define ASC (*(volatile unsigned short *)ASC_ADDR)
-
-#define BTSC_ADDR 0xFFFFF070
-#define BTSC (*(volatile unsigned short *)BTSC_ADDR)
-
-#define BHC_ADDR 0xFFFFF06A
-#define BHC (*(volatile unsigned short *)BHC_ADDR)
-
-
-/* NB85E-style interrupt system. */
-#include <asm/nb85e_intc.h>
/* Timer interrupts 0-3, interrupt at intervals from CLK/4096 to CLK/16384. */
#define IRQ_RPU(n) (60 + (n))
diff --git a/include/asm-v850/highres_timer.h b/include/asm-v850/highres_timer.h
index c63b8cd1bff4..486fb49ceab6 100644
--- a/include/asm-v850/highres_timer.h
+++ b/include/asm-v850/highres_timer.h
@@ -1,8 +1,8 @@
/*
* include/asm-v850/highres_timer.h -- High resolution timing routines
*
- * Copyright (C) 2001 NEC Corporation
- * Copyright (C) 2001 Miles Bader <miles@gnu.org>
+ * Copyright (C) 2001,03 NEC Electronics Corporation
+ * Copyright (C) 2001,03 Miles Bader <miles@gnu.org>
*
* This file is subject to the terms and conditions of the GNU General
* Public License. See the file COPYING in the main directory of this
@@ -25,7 +25,7 @@
counter overflows). */
#define HIGHRES_TIMER_SLOW_TICK_RATE 25
-/* Which timer in the nb85e `Timer D' we use. */
+/* Which timer in the V850E `Timer D' we use. */
#define HIGHRES_TIMER_TIMER_D_UNIT 3
diff --git a/include/asm-v850/ma.h b/include/asm-v850/ma.h
index ed153b642360..89e66473a176 100644
--- a/include/asm-v850/ma.h
+++ b/include/asm-v850/ma.h
@@ -1,8 +1,8 @@
/*
* include/asm-v850/ma.h -- V850E/MA series of cpu chips
*
- * Copyright (C) 2001,02 NEC Corporation
- * Copyright (C) 2001,02 Miles Bader <miles@gnu.org>
+ * Copyright (C) 2001,02,03 NEC Electronics Corporation
+ * Copyright (C) 2001,02,03 Miles Bader <miles@gnu.org>
*
* This file is subject to the terms and conditions of the GNU General
* Public License. See the file COPYING in the main directory of this
@@ -14,9 +14,8 @@
#ifndef __V850_MA_H__
#define __V850_MA_H__
-
-/* The MA series uses the NB85E cpu core. */
-#include <asm/nb85e.h>
+/* The MA series uses the V850E cpu core. */
+#include <asm/v850e.h>
/* For <asm/entry.h> */
@@ -28,10 +27,10 @@
/* MA series UART details. */
-#define NB85E_UART_BASE_FREQ CPU_CLOCK_FREQ
+#define V850E_UART_BASE_FREQ CPU_CLOCK_FREQ
/* This is a function that gets called before configuring the UART. */
-#define NB85E_UART_PRE_CONFIGURE ma_uart_pre_configure
+#define V850E_UART_PRE_CONFIGURE ma_uart_pre_configure
#ifndef __ASSEMBLY__
extern void ma_uart_pre_configure (unsigned chan,
unsigned cflags, unsigned baud);
@@ -39,16 +38,16 @@ extern void ma_uart_pre_configure (unsigned chan,
/* MA series timer C details. */
-#define NB85E_TIMER_C_BASE_ADDR 0xFFFFF600
+#define V850E_TIMER_C_BASE_ADDR 0xFFFFF600
/* MA series timer D details. */
-#define NB85E_TIMER_D_BASE_ADDR 0xFFFFF540
-#define NB85E_TIMER_D_TMD_BASE_ADDR (NB85E_TIMER_D_BASE_ADDR + 0x0)
-#define NB85E_TIMER_D_CMD_BASE_ADDR (NB85E_TIMER_D_BASE_ADDR + 0x2)
-#define NB85E_TIMER_D_TMCD_BASE_ADDR (NB85E_TIMER_D_BASE_ADDR + 0x4)
+#define V850E_TIMER_D_BASE_ADDR 0xFFFFF540
+#define V850E_TIMER_D_TMD_BASE_ADDR (V850E_TIMER_D_BASE_ADDR + 0x0)
+#define V850E_TIMER_D_CMD_BASE_ADDR (V850E_TIMER_D_BASE_ADDR + 0x2)
+#define V850E_TIMER_D_TMCD_BASE_ADDR (V850E_TIMER_D_BASE_ADDR + 0x4)
-#define NB85E_TIMER_D_BASE_FREQ CPU_CLOCK_FREQ
+#define V850E_TIMER_D_BASE_FREQ CPU_CLOCK_FREQ
/* Port 0 */
diff --git a/include/asm-v850/ma1.h b/include/asm-v850/ma1.h
index 034eea17a02f..ede1f1de2b7a 100644
--- a/include/asm-v850/ma1.h
+++ b/include/asm-v850/ma1.h
@@ -1,8 +1,8 @@
/*
* include/asm-v850/ma1.h -- V850E/MA1 cpu chip
*
- * Copyright (C) 2001,02 NEC Corporation
- * Copyright (C) 2001,02 Miles Bader <miles@gnu.org>
+ * Copyright (C) 2001,02,03 NEC Electronics Corporation
+ * Copyright (C) 2001,02,03 Miles Bader <miles@gnu.org>
*
* This file is subject to the terms and conditions of the GNU General
* Public License. See the file COPYING in the main directory of this
@@ -40,12 +40,11 @@
#define IRQ_INTST(n) (0x27 + (n)*4) /* UART 0-2 transmission completion */
#define IRQ_INTST_NUM 3
-/* For <asm/irq.h> */
#define NUM_CPU_IRQS 0x30
/* The MA1 has a UART with 3 channels. */
-#define NB85E_UART_NUM_CHANNELS 3
+#define V850E_UART_NUM_CHANNELS 3
#endif /* __V850_MA1_H__ */
diff --git a/include/asm-v850/machdep.h b/include/asm-v850/machdep.h
index 88b3a6fe24a3..98d8bf63970e 100644
--- a/include/asm-v850/machdep.h
+++ b/include/asm-v850/machdep.h
@@ -1,8 +1,8 @@
/*
* include/asm-v850/machdep.h -- Machine-dependent definitions
*
- * Copyright (C) 2001,02 NEC Corporation
- * Copyright (C) 2001,02 Miles Bader <miles@gnu.org>
+ * Copyright (C) 2001,02,03 NEC Electronics Corporation
+ * Copyright (C) 2001,02,03 Miles Bader <miles@gnu.org>
*
* This file is subject to the terms and conditions of the GNU General
* Public License. See the file COPYING in the main directory of this
@@ -20,6 +20,9 @@
#ifdef CONFIG_V850E_MA1
#include <asm/ma1.h>
#endif
+#ifdef CONFIG_V850E_ME2
+#include <asm/me2.h>
+#endif
#ifdef CONFIG_V850E_TEG
#include <asm/teg.h>
#endif
@@ -36,6 +39,9 @@
#ifdef CONFIG_RTE_CB_MA1
#include <asm/rte_ma1_cb.h>
#endif
+#ifdef CONFIG_RTE_CB_ME2
+#include <asm/rte_me2_cb.h>
+#endif
#ifdef CONFIG_RTE_CB_NB85E
#include <asm/rte_nb85e_cb.h>
#endif
@@ -45,6 +51,9 @@
#ifdef CONFIG_V850E2_SIM85E2C
#include <asm/sim85e2c.h>
#endif
+#ifdef CONFIG_V850E2_SIM85E2S
+#include <asm/sim85e2s.h>
+#endif
#ifdef CONFIG_V850E2_FPGA85E2C
#include <asm/fpga85e2c.h>
#endif
diff --git a/include/asm-v850/me2.h b/include/asm-v850/me2.h
new file mode 100644
index 000000000000..ac7c9ce0bdc1
--- /dev/null
+++ b/include/asm-v850/me2.h
@@ -0,0 +1,182 @@
+/*
+ * include/asm-v850/me2.h -- V850E/ME2 cpu chip
+ *
+ * Copyright (C) 2001,02,03 NEC Electronics Corporation
+ * Copyright (C) 2001,02,03 Miles Bader <miles@gnu.org>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file COPYING in the main directory of this
+ * archive for more details.
+ *
+ * Written by Miles Bader <miles@gnu.org>
+ */
+
+#ifndef __V850_ME2_H__
+#define __V850_ME2_H__
+
+#include <asm/v850e.h>
+#include <asm/v850e_cache.h>
+
+
+#define CPU_MODEL "v850e/me2"
+#define CPU_MODEL_LONG "NEC V850E/ME2"
+
+
+/* Hardware-specific interrupt numbers (in the kernel IRQ namespace). */
+#define IRQ_INTP(n) (n) /* Pnnn (pin) interrupts */
+#define IRQ_INTP_NUM 31
+#define IRQ_INTCMD(n) (0x31 + (n)) /* interval timer interrupts 0-3 */
+#define IRQ_INTCMD_NUM 4
+#define IRQ_INTDMA(n) (0x41 + (n)) /* DMA interrupts 0-3 */
+#define IRQ_INTDMA_NUM 4
+#define IRQ_INTUBTIRE(n) (0x49 + (n)*5)/* UARTB 0-1 reception error */
+#define IRQ_INTUBTIRE_NUM 2
+#define IRQ_INTUBTIR(n) (0x4a + (n)*5) /* UARTB 0-1 reception complete */
+#define IRQ_INTUBTIR_NUM 2
+#define IRQ_INTUBTIT(n) (0x4b + (n)*5) /* UARTB 0-1 transmission complete */
+#define IRQ_INTUBTIT_NUM 2
+#define IRQ_INTUBTIF(n) (0x4c + (n)*5) /* UARTB 0-1 FIFO trans. complete */
+#define IRQ_INTUBTIF_NUM 2
+#define IRQ_INTUBTITO(n) (0x4d + (n)*5) /* UARTB 0-1 reception timeout */
+#define IRQ_INTUBTITO_NUM 2
+
+/* For <asm/irq.h> */
+#define NUM_CPU_IRQS 0x59 /* V850E/ME2 */
+
+
+/* For <asm/entry.h> */
+/* We use on-chip RAM, for a few miscellaneous variables that must be
+ accessible using a load instruction relative to R0. */
+#define R0_RAM_ADDR 0xFFFFB000 /* V850E/ME2 */
+
+
+/* V850E/ME2 UARTB details.*/
+#define V850E_UART_NUM_CHANNELS 2
+#define V850E_UARTB_BASE_FREQ (CPU_CLOCK_FREQ / 4)
+
+/* This is a function that gets called before configuring the UART. */
+#define V850E_UART_PRE_CONFIGURE me2_uart_pre_configure
+#ifndef __ASSEMBLY__
+extern void me2_uart_pre_configure (unsigned chan,
+ unsigned cflags, unsigned baud);
+#endif /* __ASSEMBLY__ */
+
+
+/* V850E/ME2 timer C details. */
+#define V850E_TIMER_C_BASE_ADDR 0xFFFFF600
+
+
+/* V850E/ME2 timer D details. */
+#define V850E_TIMER_D_BASE_ADDR 0xFFFFF540
+#define V850E_TIMER_D_TMD_BASE_ADDR (V850E_TIMER_D_BASE_ADDR + 0x0)
+#define V850E_TIMER_D_CMD_BASE_ADDR (V850E_TIMER_D_BASE_ADDR + 0x2)
+#define V850E_TIMER_D_TMCD_BASE_ADDR (V850E_TIMER_D_BASE_ADDR + 0x4)
+
+#define V850E_TIMER_D_BASE_FREQ (CPU_CLOCK_FREQ / 2)
+
+
+/* Select iRAM mode. */
+#define ME2_IRAMM_ADDR 0xFFFFF80A
+#define ME2_IRAMM (*(volatile u8*)ME2_IRAMM_ADDR)
+
+
+/* Interrupt edge-detection configuration. INTF(n) and INTR(n) are only
+ valid for n == 1, 2, or 5. */
+#define ME2_INTF_ADDR(n) (0xFFFFFC00 + (n) * 0x2)
+#define ME2_INTF(n) (*(volatile u8*)ME2_INTF_ADDR(n))
+#define ME2_INTR_ADDR(n) (0xFFFFFC20 + (n) * 0x2)
+#define ME2_INTR(n) (*(volatile u8*)ME2_INTR_ADDR(n))
+#define ME2_INTFAL_ADDR 0xFFFFFC10
+#define ME2_INTFAL (*(volatile u8*)ME2_INTFAL_ADDR)
+#define ME2_INTRAL_ADDR 0xFFFFFC30
+#define ME2_INTRAL (*(volatile u8*)ME2_INTRAL_ADDR)
+#define ME2_INTFDH_ADDR 0xFFFFFC16
+#define ME2_INTFDH (*(volatile u16*)ME2_INTFDH_ADDR)
+#define ME2_INTRDH_ADDR 0xFFFFFC36
+#define ME2_INTRDH (*(volatile u16*)ME2_INTRDH_ADDR)
+#define ME2_SESC_ADDR(n) (0xFFFFF609 + (n) * 0x10)
+#define ME2_SESC(n) (*(volatile u8*)ME2_SESC_ADDR(n))
+#define ME2_SESA10_ADDR 0xFFFFF5AD
+#define ME2_SESA10 (*(volatile u8*)ME2_SESA10_ADDR)
+#define ME2_SESA11_ADDR 0xFFFFF5DD
+#define ME2_SESA11 (*(volatile u8*)ME2_SESA11_ADDR)
+
+
+/* Port 1 */
+/* Direct I/O. Bits 0-3 are pins P10-P13. */
+#define ME2_PORT1_IO_ADDR 0xFFFFF402
+#define ME2_PORT1_IO (*(volatile u8 *)ME2_PORT1_IO_ADDR)
+/* Port mode (for direct I/O, 0 = output, 1 = input). */
+#define ME2_PORT1_PM_ADDR 0xFFFFF422
+#define ME2_PORT1_PM (*(volatile u8 *)ME2_PORT1_PM_ADDR)
+/* Port mode control (0 = direct I/O mode, 1 = alternative I/O mode). */
+#define ME2_PORT1_PMC_ADDR 0xFFFFF442
+#define ME2_PORT1_PMC (*(volatile u8 *)ME2_PORT1_PMC_ADDR)
+/* Port function control (for serial interfaces, 0 = CSI30, 1 = UARTB0 ). */
+#define ME2_PORT1_PFC_ADDR 0xFFFFF462
+#define ME2_PORT1_PFC (*(volatile u8 *)ME2_PORT1_PFC_ADDR)
+
+/* Port 2 */
+/* Direct I/O. Bits 0-3 are pins P20-P25. */
+#define ME2_PORT2_IO_ADDR 0xFFFFF404
+#define ME2_PORT2_IO (*(volatile u8 *)ME2_PORT2_IO_ADDR)
+/* Port mode (for direct I/O, 0 = output, 1 = input). */
+#define ME2_PORT2_PM_ADDR 0xFFFFF424
+#define ME2_PORT2_PM (*(volatile u8 *)ME2_PORT2_PM_ADDR)
+/* Port mode control (0 = direct I/O mode, 1 = alternative I/O mode). */
+#define ME2_PORT2_PMC_ADDR 0xFFFFF444
+#define ME2_PORT2_PMC (*(volatile u8 *)ME2_PORT2_PMC_ADDR)
+/* Port function control (for serial interfaces, 0 = INTP2x, 1 = UARTB1 ). */
+#define ME2_PORT2_PFC_ADDR 0xFFFFF464
+#define ME2_PORT2_PFC (*(volatile u8 *)ME2_PORT2_PFC_ADDR)
+
+/* Port 5 */
+/* Direct I/O. Bits 0-5 are pins P50-P55. */
+#define ME2_PORT5_IO_ADDR 0xFFFFF40A
+#define ME2_PORT5_IO (*(volatile u8 *)ME2_PORT5_IO_ADDR)
+/* Port mode (for direct I/O, 0 = output, 1 = input). */
+#define ME2_PORT5_PM_ADDR 0xFFFFF42A
+#define ME2_PORT5_PM (*(volatile u8 *)ME2_PORT5_PM_ADDR)
+/* Port mode control (0 = direct I/O mode, 1 = alternative I/O mode). */
+#define ME2_PORT5_PMC_ADDR 0xFFFFF44A
+#define ME2_PORT5_PMC (*(volatile u8 *)ME2_PORT5_PMC_ADDR)
+/* Port function control (). */
+#define ME2_PORT5_PFC_ADDR 0xFFFFF46A
+#define ME2_PORT5_PFC (*(volatile u8 *)ME2_PORT5_PFC_ADDR)
+
+/* Port 6 */
+/* Direct I/O. Bits 5-7 are pins P65-P67. */
+#define ME2_PORT6_IO_ADDR 0xFFFFF40C
+#define ME2_PORT6_IO (*(volatile u8 *)ME2_PORT6_IO_ADDR)
+/* Port mode (for direct I/O, 0 = output, 1 = input). */
+#define ME2_PORT6_PM_ADDR 0xFFFFF42C
+#define ME2_PORT6_PM (*(volatile u8 *)ME2_PORT6_PM_ADDR)
+/* Port mode control (0 = direct I/O mode, 1 = alternative I/O mode). */
+#define ME2_PORT6_PMC_ADDR 0xFFFFF44C
+#define ME2_PORT6_PMC (*(volatile u8 *)ME2_PORT6_PMC_ADDR)
+/* Port function control (). */
+#define ME2_PORT6_PFC_ADDR 0xFFFFF46C
+#define ME2_PORT6_PFC (*(volatile u8 *)ME2_PORT6_PFC_ADDR)
+
+/* Port 7 */
+/* Direct I/O. Bits 2-7 are pins P72-P77. */
+#define ME2_PORT7_IO_ADDR 0xFFFFF40E
+#define ME2_PORT7_IO (*(volatile u8 *)ME2_PORT7_IO_ADDR)
+/* Port mode (for direct I/O, 0 = output, 1 = input). */
+#define ME2_PORT7_PM_ADDR 0xFFFFF42E
+#define ME2_PORT7_PM (*(volatile u8 *)ME2_PORT7_PM_ADDR)
+/* Port mode control (0 = direct I/O mode, 1 = alternative I/O mode). */
+#define ME2_PORT7_PMC_ADDR 0xFFFFF44E
+#define ME2_PORT7_PMC (*(volatile u8 *)ME2_PORT7_PMC_ADDR)
+/* Port function control (). */
+#define ME2_PORT7_PFC_ADDR 0xFFFFF46E
+#define ME2_PORT7_PFC (*(volatile u8 *)ME2_PORT7_PFC_ADDR)
+
+
+#ifndef __ASSEMBLY__
+/* Initialize V850E/ME2 chip interrupts. */
+extern void me2_init_irqs (void);
+#endif /* !__ASSEMBLY__ */
+
+
+#endif /* __V850_ME2_H__ */
diff --git a/include/asm-v850/nb85e.h b/include/asm-v850/nb85e.h
deleted file mode 100644
index bdfa136d85d1..000000000000
--- a/include/asm-v850/nb85e.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * include/asm-v850/nb85e.h -- NB85E cpu core
- *
- * Copyright (C) 2001,02 NEC Corporation
- * Copyright (C) 2001,02 Miles Bader <miles@gnu.org>
- *
- * This file is subject to the terms and conditions of the GNU General
- * Public License. See the file COPYING in the main directory of this
- * archive for more details.
- *
- * Written by Miles Bader <miles@gnu.org>
- */
-
-#ifndef __V850_NB85E_H__
-#define __V850_NB85E_H__
-
-#include <asm/nb85e_intc.h>
-
-#define CPU_ARCH "v850e"
-
-#endif /* __V850_NB85E_H__ */
diff --git a/include/asm-v850/nb85e_cache.h b/include/asm-v850/nb85e_cache.h
deleted file mode 100644
index 82b02547ad83..000000000000
--- a/include/asm-v850/nb85e_cache.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * include/asm-v850/nb85e_cache_cache.h -- Cache control for NB85E_CACHE212 and
- * NB85E_CACHE213 cache memories
- *
- * Copyright (C) 2001,03 NEC Electronics Corporation
- * Copyright (C) 2001,03 Miles Bader <miles@gnu.org>
- *
- * This file is subject to the terms and conditions of the GNU General
- * Public License. See the file COPYING in the main directory of this
- * archive for more details.
- *
- * Written by Miles Bader <miles@gnu.org>
- */
-
-#ifndef __V850_NB85E_CACHE_H__
-#define __V850_NB85E_CACHE_H__
-
-#include <asm/types.h>
-
-
-/* Cache control registers. */
-#define NB85E_CACHE_BHC_ADDR 0xFFFFF06A
-#define NB85E_CACHE_BHC (*(volatile u16 *)NB85E_CACHE_BHC_ADDR)
-#define NB85E_CACHE_ICC_ADDR 0xFFFFF070
-#define NB85E_CACHE_ICC (*(volatile u16 *)NB85E_CACHE_ICC_ADDR)
-#define NB85E_CACHE_ISI_ADDR 0xFFFFF072
-#define NB85E_CACHE_ISI (*(volatile u16 *)NB85E_CACHE_ISI_ADDR)
-#define NB85E_CACHE_DCC_ADDR 0xFFFFF078
-#define NB85E_CACHE_DCC (*(volatile u16 *)NB85E_CACHE_DCC_ADDR)
-
-/* Size of a cache line in bytes. */
-#define NB85E_CACHE_LINE_SIZE 16
-
-/* For <asm/cache.h> */
-#define L1_CACHE_BYTES NB85E_CACHE_LINE_SIZE
-
-
-#if defined(__KERNEL__) && !defined(__ASSEMBLY__)
-
-/* Set caching params via the BHC and DCC registers. */
-void nb85e_cache_enable (u16 bhc, u16 dcc);
-
-struct page;
-struct mm_struct;
-struct vm_area_struct;
-
-extern void nb85e_cache_flush_all (void);
-extern void nb85e_cache_flush_mm (struct mm_struct *mm);
-extern void nb85e_cache_flush_range (struct mm_struct *mm,
- unsigned long start,
- unsigned long end);
-extern void nb85e_cache_flush_page (struct vm_area_struct *vma,
- unsigned long page_addr);
-extern void nb85e_cache_flush_dcache_page (struct page *page);
-extern void nb85e_cache_flush_icache (void);
-extern void nb85e_cache_flush_icache_range (unsigned long start,
- unsigned long end);
-extern void nb85e_cache_flush_icache_page (struct vm_area_struct *vma,
- struct page *page);
-extern void nb85e_cache_flush_icache_user_range (struct vm_area_struct *vma,
- struct page *page,
- unsigned long adr, int len);
-extern void nb85e_cache_flush_sigtramp (unsigned long addr);
-
-#define flush_cache_all nb85e_cache_flush_all
-#define flush_cache_mm nb85e_cache_flush_mm
-#define flush_cache_range nb85e_cache_flush_range
-#define flush_cache_page nb85e_cache_flush_page
-#define flush_dcache_page nb85e_cache_flush_dcache_page
-#define flush_icache nb85e_cache_flush_icache
-#define flush_icache_range nb85e_cache_flush_icache_range
-#define flush_icache_page nb85e_cache_flush_icache_page
-#define flush_icache_user_range nb85e_cache_flush_icache_user_range
-#define flush_cache_sigtramp nb85e_cache_flush_sigtramp
-
-#endif /* __KERNEL__ && !__ASSEMBLY__ */
-
-#endif /* __V850_NB85E_CACHE_H__ */
diff --git a/include/asm-v850/nb85e_timer_c.h b/include/asm-v850/nb85e_timer_c.h
deleted file mode 100644
index 069513b6de33..000000000000
--- a/include/asm-v850/nb85e_timer_c.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * include/asm-v850/nb85e_timer_c.h -- `Timer C' component often used
- * with the NB85E cpu core
- *
- * Copyright (C) 2001 NEC Corporation
- * Copyright (C) 2001 Miles Bader <miles@gnu.org>
- *
- * This file is subject to the terms and conditions of the GNU General
- * Public License. See the file COPYING in the main directory of this
- * archive for more details.
- *
- * Written by Miles Bader <miles@gnu.org>
- */
-
-/* NOTE: this include file currently contains only enough to allow us to
- use timer C as an interrupt pass-through. */
-
-#ifndef __V850_NB85E_TIMER_C_H__
-#define __V850_NB85E_TIMER_C_H__
-
-#include <asm/types.h>
-#include <asm/machdep.h> /* Pick up chip-specific defs. */
-
-
-/* Timer C (16-bit interval timers). */
-
-/* Control register 0 for timer C. */
-#define NB85E_TIMER_C_TMCC0_ADDR(n) (NB85E_TIMER_C_BASE_ADDR + 0x6 + 0x10 *(n))
-#define NB85E_TIMER_C_TMCC0(n) (*(volatile u8 *)NB85E_TIMER_C_TMCC0_ADDR(n))
-#define NB85E_TIMER_C_TMCC0_CAE 0x01 /* clock action enable */
-#define NB85E_TIMER_C_TMCC0_CE 0x02 /* count enable */
-/* ... */
-
-/* Control register 1 for timer C. */
-#define NB85E_TIMER_C_TMCC1_ADDR(n) (NB85E_TIMER_C_BASE_ADDR + 0x8 + 0x10 *(n))
-#define NB85E_TIMER_C_TMCC1(n) (*(volatile u8 *)NB85E_TIMER_C_TMCC1_ADDR(n))
-#define NB85E_TIMER_C_TMCC1_CMS0 0x01 /* capture/compare mode select (ccc0) */
-#define NB85E_TIMER_C_TMCC1_CMS1 0x02 /* capture/compare mode select (ccc1) */
-/* ... */
-
-/* Interrupt edge-sensitivity control for timer C. */
-#define NB85E_TIMER_C_SESC_ADDR(n) (NB85E_TIMER_C_BASE_ADDR + 0x9 + 0x10 *(n))
-#define NB85E_TIMER_C_SESC(n) (*(volatile u8 *)NB85E_TIMER_C_SESC_ADDR(n))
-
-/* ...etc... */
-
-
-#endif /* __V850_NB85E_TIMER_C_H__ */
diff --git a/include/asm-v850/nb85e_uart.h b/include/asm-v850/nb85e_uart.h
deleted file mode 100644
index ac8e8b1375fe..000000000000
--- a/include/asm-v850/nb85e_uart.h
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * include/asm-v850/nb85e_uart.h -- On-chip UART often used with the
- * NB85E cpu core
- *
- * Copyright (C) 2001,02 NEC Corporation
- * Copyright (C) 2001,02 Miles Bader <miles@gnu.org>
- *
- * This file is subject to the terms and conditions of the GNU General
- * Public License. See the file COPYING in the main directory of this
- * archive for more details.
- *
- * Written by Miles Bader <miles@gnu.org>
- */
-
-/* There's not actually a single UART implementation used by nb85e
- derivatives, but rather a series of implementations that are all
- `close' to one another. This file attempts to capture some
- commonality between them. */
-
-#ifndef __V850_NB85E_UART_H__
-#define __V850_NB85E_UART_H__
-
-#include <asm/types.h>
-#include <asm/machdep.h> /* Pick up chip-specific defs. */
-
-
-/* The base address of the UART control registers for channel N.
- The default is the address used on the V850E/MA1. */
-#ifndef NB85E_UART_BASE_ADDR
-#define NB85E_UART_BASE_ADDR(n) (0xFFFFFA00 + 0x10 * (n))
-#endif
-
-/* Addresses of specific UART control registers for channel N.
- The defaults are the addresses used on the V850E/MA1; if a platform
- wants to redefine any of these, it must redefine them all. */
-#ifndef NB85E_UART_ASIM_ADDR
-#define NB85E_UART_ASIM_ADDR(n) (NB85E_UART_BASE_ADDR(n) + 0x0)
-#define NB85E_UART_RXB_ADDR(n) (NB85E_UART_BASE_ADDR(n) + 0x2)
-#define NB85E_UART_ASIS_ADDR(n) (NB85E_UART_BASE_ADDR(n) + 0x3)
-#define NB85E_UART_TXB_ADDR(n) (NB85E_UART_BASE_ADDR(n) + 0x4)
-#define NB85E_UART_ASIF_ADDR(n) (NB85E_UART_BASE_ADDR(n) + 0x5)
-#define NB85E_UART_CKSR_ADDR(n) (NB85E_UART_BASE_ADDR(n) + 0x6)
-#define NB85E_UART_BRGC_ADDR(n) (NB85E_UART_BASE_ADDR(n) + 0x7)
-#endif
-
-#ifndef NB85E_UART_CKSR_MAX_FREQ
-#define NB85E_UART_CKSR_MAX_FREQ (25*1000*1000)
-#endif
-
-/* UART config registers. */
-#define NB85E_UART_ASIM(n) (*(volatile u8 *)NB85E_UART_ASIM_ADDR(n))
-/* Control bits for config registers. */
-#define NB85E_UART_ASIM_CAE 0x80 /* clock enable */
-#define NB85E_UART_ASIM_TXE 0x40 /* transmit enable */
-#define NB85E_UART_ASIM_RXE 0x20 /* receive enable */
-#define NB85E_UART_ASIM_PS_MASK 0x18 /* mask covering parity-select bits */
-#define NB85E_UART_ASIM_PS_NONE 0x00 /* no parity */
-#define NB85E_UART_ASIM_PS_ZERO 0x08 /* zero parity */
-#define NB85E_UART_ASIM_PS_ODD 0x10 /* odd parity */
-#define NB85E_UART_ASIM_PS_EVEN 0x18 /* even parity */
-#define NB85E_UART_ASIM_CL_8 0x04 /* char len is 8 bits (otherwise, 7) */
-#define NB85E_UART_ASIM_SL_2 0x02 /* 2 stop bits (otherwise, 1) */
-#define NB85E_UART_ASIM_ISRM 0x01 /* generate INTSR interrupt on errors
- (otherwise, generate INTSER) */
-
-/* UART serial interface status registers. */
-#define NB85E_UART_ASIS(n) (*(volatile u8 *)NB85E_UART_ASIS_ADDR(n))
-/* Control bits for status registers. */
-#define NB85E_UART_ASIS_PE 0x04 /* parity error */
-#define NB85E_UART_ASIS_FE 0x02 /* framing error */
-#define NB85E_UART_ASIS_OVE 0x01 /* overrun error */
-
-/* UART serial interface transmission status registers. */
-#define NB85E_UART_ASIF(n) (*(volatile u8 *)NB85E_UART_ASIF_ADDR(n))
-#define NB85E_UART_ASIF_TXBF 0x02 /* transmit buffer flag (data in TXB) */
-#define NB85E_UART_ASIF_TXSF 0x01 /* transmit shift flag (sending data) */
-
-/* UART receive buffer register. */
-#define NB85E_UART_RXB(n) (*(volatile u8 *)NB85E_UART_RXB_ADDR(n))
-
-/* UART transmit buffer register. */
-#define NB85E_UART_TXB(n) (*(volatile u8 *)NB85E_UART_TXB_ADDR(n))
-
-/* UART baud-rate generator control registers. */
-#define NB85E_UART_CKSR(n) (*(volatile u8 *)NB85E_UART_CKSR_ADDR(n))
-#define NB85E_UART_CKSR_MAX 11
-#define NB85E_UART_BRGC(n) (*(volatile u8 *)NB85E_UART_BRGC_ADDR(n))
-
-
-/* This UART doesn't implement RTS/CTS by default, but some platforms
- implement them externally, so check to see if <asm/machdep.h> defined
- anything. */
-#ifdef NB85E_UART_CTS
-#define nb85e_uart_cts(n) NB85E_UART_CTS(n)
-#else
-#define nb85e_uart_cts(n) (1)
-#endif
-
-/* Do the same for RTS. */
-#ifdef NB85E_UART_SET_RTS
-#define nb85e_uart_set_rts(n,v) NB85E_UART_SET_RTS(n,v)
-#else
-#define nb85e_uart_set_rts(n,v) ((void)0)
-#endif
-
-/* Return true if all characters awaiting transmission on uart channel N
- have been transmitted. */
-#define nb85e_uart_xmit_done(n) \
- (! (NB85E_UART_ASIF(n) & NB85E_UART_ASIF_TXBF))
-/* Wait for this to be true. */
-#define nb85e_uart_wait_for_xmit_done(n) \
- do { } while (! nb85e_uart_xmit_done (n))
-
-/* Return true if uart channel N is ready to transmit a character. */
-#define nb85e_uart_xmit_ok(n) \
- (nb85e_uart_xmit_done(n) && nb85e_uart_cts(n))
-/* Wait for this to be true. */
-#define nb85e_uart_wait_for_xmit_ok(n) \
- do { } while (! nb85e_uart_xmit_ok (n))
-
-/* Write character CH to uart channel N. */
-#define nb85e_uart_putc(n, ch) (NB85E_UART_TXB(n) = (ch))
-
-
-#define NB85E_UART_MINOR_BASE 64
-
-
-#ifndef __ASSEMBLY__
-
-/* Setup a console using channel 0 of the builtin uart. */
-extern void nb85e_uart_cons_init (unsigned chan);
-
-/* Configure and turn on uart channel CHAN, using the termios `control
- modes' bits in CFLAGS, and a baud-rate of BAUD. */
-void nb85e_uart_configure (unsigned chan, unsigned cflags, unsigned baud);
-
-/* If the macro NB85E_UART_PRE_CONFIGURE is defined (presumably by a
- <asm/machdep.h>), it is called from nb85e_uart_pre_configure before
- anything else is done, with interrupts disabled. */
-
-#endif /* !__ASSEMBLY__ */
-
-
-#endif /* __V850_NB85E_UART_H__ */
diff --git a/include/asm-v850/processor.h b/include/asm-v850/processor.h
index 0d97022804ac..025202b4df7e 100644
--- a/include/asm-v850/processor.h
+++ b/include/asm-v850/processor.h
@@ -1,7 +1,7 @@
/*
* include/asm-v850/processor.h
*
- * Copyright (C) 2001,02,03 NEC Corporation
+ * Copyright (C) 2001,02,03 NEC Electronics Corporation
* Copyright (C) 2001,02,03 Miles Bader <miles@gnu.org>
*
* This file is subject to the terms and conditions of the GNU General
diff --git a/include/asm-v850/ptrace.h b/include/asm-v850/ptrace.h
index 8c7c759b42a3..62b2b3822d88 100644
--- a/include/asm-v850/ptrace.h
+++ b/include/asm-v850/ptrace.h
@@ -1,7 +1,7 @@
/*
* include/asm-v850/ptrace.h -- Access to CPU registers
*
- * Copyright (C) 2001,02,03 NEC Corporation
+ * Copyright (C) 2001,02,03 NEC Electronics Corporation
* Copyright (C) 2001,02,03 Miles Bader <miles@gnu.org>
*
* This file is subject to the terms and conditions of the GNU General
diff --git a/include/asm-v850/rte_cb.h b/include/asm-v850/rte_cb.h
index fd8ff5350624..9f7f02cb0391 100644
--- a/include/asm-v850/rte_cb.h
+++ b/include/asm-v850/rte_cb.h
@@ -1,7 +1,7 @@
/*
* include/asm-v850/rte_cb.h -- Midas labs RTE-CB series of evaluation boards
*
- * Copyright (C) 2001,02,03 NEC Corporation
+ * Copyright (C) 2001,02,03 NEC Electronics Corporation
* Copyright (C) 2001,02,03 Miles Bader <miles@gnu.org>
*
* This file is subject to the terms and conditions of the GNU General
@@ -20,42 +20,54 @@
#define MB_A_SRAM_SIZE 0x00200000 /* 2MB */
+#ifdef CONFIG_RTE_GBUS_INT
/* GBUS interrupt support. */
-#define GBUS_INT_BASE_IRQ NUM_CPU_IRQS
-#define GBUS_INT_BASE_ADDR (GCS2_ADDR + 0x00006000)
-#include <asm/gbus_int.h>
-/* We define NUM_MACH_IRQS to include extra interrupts from the GBUS. */
-#define NUM_MACH_IRQS (NUM_CPU_IRQS + IRQ_GBUS_INT_NUM)
+# include <asm/gbus_int.h>
+
+# define GBUS_INT_BASE_IRQ NUM_RTE_CB_IRQS
+# define GBUS_INT_BASE_ADDR (GCS2_ADDR + 0x00006000)
/* Some specific interrupts. */
-#define IRQ_MB_A_LAN IRQ_GBUS_INT(10)
-#define IRQ_MB_A_PCI1(n) (IRQ_GBUS_INT(16) + (n))
-#define IRQ_MB_A_PCI1_NUM 4
-#define IRQ_MB_A_PCI2(n) (IRQ_GBUS_INT(20) + (n))
-#define IRQ_MB_A_PCI2_NUM 4
-#define IRQ_MB_A_EXT(n) (IRQ_GBUS_INT(24) + (n))
-#define IRQ_MB_A_EXT_NUM 4
-#define IRQ_MB_A_USB_OC(n) (IRQ_GBUS_INT(28) + (n))
-#define IRQ_MB_A_USB_OC_NUM 2
-#define IRQ_MB_A_PCMCIA_OC IRQ_GBUS_INT(30)
+# define IRQ_MB_A_LAN IRQ_GBUS_INT(10)
+# define IRQ_MB_A_PCI1(n) (IRQ_GBUS_INT(16) + (n))
+# define IRQ_MB_A_PCI1_NUM 4
+# define IRQ_MB_A_PCI2(n) (IRQ_GBUS_INT(20) + (n))
+# define IRQ_MB_A_PCI2_NUM 4
+# define IRQ_MB_A_EXT(n) (IRQ_GBUS_INT(24) + (n))
+# define IRQ_MB_A_EXT_NUM 4
+# define IRQ_MB_A_USB_OC(n) (IRQ_GBUS_INT(28) + (n))
+# define IRQ_MB_A_USB_OC_NUM 2
+# define IRQ_MB_A_PCMCIA_OC IRQ_GBUS_INT(30)
+
+/* We define NUM_MACH_IRQS to include extra interrupts from the GBUS. */
+# define NUM_MACH_IRQS (NUM_RTE_CB_IRQS + IRQ_GBUS_INT_NUM)
+#else /* !CONFIG_RTE_GBUS_INT */
+# define NUM_MACH_IRQS NUM_RTE_CB_IRQS
+
+#endif /* CONFIG_RTE_GBUS_INT */
+
+
+#ifdef CONFIG_RTE_MB_A_PCI
/* Mother-A PCI bus support. */
-#include <asm/rte_mb_a_pci.h>
+
+# include <asm/rte_mb_a_pci.h>
/* These are the base addresses used for allocating device address
space. 512K of the motherboard SRAM is in the same space, so we have
to be careful not to let it be allocated. */
-#define PCIBIOS_MIN_MEM (MB_A_PCI_MEM_ADDR + 0x80000)
-#define PCIBIOS_MIN_IO MB_A_PCI_IO_ADDR
+# define PCIBIOS_MIN_MEM (MB_A_PCI_MEM_ADDR + 0x80000)
+# define PCIBIOS_MIN_IO MB_A_PCI_IO_ADDR
/* As we don't really support PCI DMA to cpu memory, and use bounce-buffers
instead, perversely enough, this becomes always true! */
-#define pci_dma_supported(dev, mask) 1
-#define pci_dac_dma_supported(dev, mask) 0
-#define pcibios_assign_all_busses() 1
+# define pci_dma_supported(dev, mask) 1
+# define pci_dac_dma_supported(dev, mask) 0
+# define pcibios_assign_all_busses() 1
+#endif /* CONFIG_RTE_MB_A_PCI */
/* For <asm/param.h> */
diff --git a/include/asm-v850/rte_ma1_cb.h b/include/asm-v850/rte_ma1_cb.h
index c9e7fb89e34d..bd3162ab9844 100644
--- a/include/asm-v850/rte_ma1_cb.h
+++ b/include/asm-v850/rte_ma1_cb.h
@@ -17,25 +17,6 @@
#include <asm/rte_cb.h> /* Common defs for Midas RTE-CB boards. */
-/* CPU addresses of GBUS memory spaces. */
-#define GCS0_ADDR 0x05000000 /* GCS0 - Common SRAM (2MB) */
-#define GCS0_SIZE 0x00200000 /* 2MB */
-#define GCS1_ADDR 0x06000000 /* GCS1 - Flash ROM (8MB) */
-#define GCS1_SIZE 0x00800000 /* 8MB */
-#define GCS2_ADDR 0x07900000 /* GCS2 - I/O registers */
-#define GCS2_SIZE 0x00400000 /* 4MB */
-#define GCS5_ADDR 0x04000000 /* GCS5 - PCI bus space */
-#define GCS5_SIZE 0x01000000 /* 16MB */
-#define GCS6_ADDR 0x07980000 /* GCS6 - PCI control registers */
-#define GCS6_SIZE 0x00000200 /* 512B */
-
-
-/* The GBUS GINT0 - GINT4 interrupts are connected to the INTP000 - INTP011
- pins on the CPU. These are shared among the GBUS interrupts. */
-#define IRQ_GINT(n) IRQ_INTP(n)
-#define IRQ_GINT_NUM 4
-
-
#define PLATFORM "rte-v850e/ma1-cb"
#define PLATFORM_LONG "Midas lab RTE-V850E/MA1-CB"
@@ -53,10 +34,32 @@
#define SDRAM_SIZE 0x02000000 /* 32MB */
+/* CPU addresses of GBUS memory spaces. */
+#define GCS0_ADDR 0x05000000 /* GCS0 - Common SRAM (2MB) */
+#define GCS0_SIZE 0x00200000 /* 2MB */
+#define GCS1_ADDR 0x06000000 /* GCS1 - Flash ROM (8MB) */
+#define GCS1_SIZE 0x00800000 /* 8MB */
+#define GCS2_ADDR 0x07900000 /* GCS2 - I/O registers */
+#define GCS2_SIZE 0x00400000 /* 4MB */
+#define GCS5_ADDR 0x04000000 /* GCS5 - PCI bus space */
+#define GCS5_SIZE 0x01000000 /* 16MB */
+#define GCS6_ADDR 0x07980000 /* GCS6 - PCI control registers */
+#define GCS6_SIZE 0x00000200 /* 512B */
+
+
/* For <asm/page.h> */
#define PAGE_OFFSET SRAM_ADDR
+/* The GBUS GINT0 - GINT3 interrupts are connected to the INTP000 - INTP011
+ pins on the CPU. These are shared among the GBUS interrupts. */
+#define IRQ_GINT(n) IRQ_INTP(n)
+#define IRQ_GINT_NUM 4
+
+/* Used by <asm/rte_cb.h> to derive NUM_MACH_IRQS. */
+#define NUM_RTE_CB_IRQS NUM_CPU_IRQS
+
+
#ifdef CONFIG_ROM_KERNEL
/* Kernel is in ROM, starting at address 0. */
@@ -98,8 +101,8 @@
/* Override the basic MA uart pre-initialization so that we can
initialize extra stuff. */
-#undef NB85E_UART_PRE_CONFIGURE /* should be defined by <asm/ma.h> */
-#define NB85E_UART_PRE_CONFIGURE rte_ma1_cb_uart_pre_configure
+#undef V850E_UART_PRE_CONFIGURE /* should be defined by <asm/ma.h> */
+#define V850E_UART_PRE_CONFIGURE rte_ma1_cb_uart_pre_configure
#ifndef __ASSEMBLY__
extern void rte_ma1_cb_uart_pre_configure (unsigned chan,
unsigned cflags, unsigned baud);
@@ -108,9 +111,9 @@ extern void rte_ma1_cb_uart_pre_configure (unsigned chan,
/* This board supports RTS/CTS for the on-chip UART, but only for channel 0. */
/* CTS for UART channel 0 is pin P43 (bit 3 of port 4). */
-#define NB85E_UART_CTS(chan) ((chan) == 0 ? !(MA_PORT4_IO & 0x8) : 1)
+#define V850E_UART_CTS(chan) ((chan) == 0 ? !(MA_PORT4_IO & 0x8) : 1)
/* RTS for UART channel 0 is pin P42 (bit 2 of port 4). */
-#define NB85E_UART_SET_RTS(chan, val) \
+#define V850E_UART_SET_RTS(chan, val) \
do { \
if (chan == 0) { \
unsigned old = MA_PORT4_IO; \
diff --git a/include/asm-v850/rte_me2_cb.h b/include/asm-v850/rte_me2_cb.h
new file mode 100644
index 000000000000..bdb7df71410e
--- /dev/null
+++ b/include/asm-v850/rte_me2_cb.h
@@ -0,0 +1,202 @@
+/*
+ * include/asm-v850/rte_me2_cb.h -- Midas labs RTE-V850E/ME2-CB board
+ *
+ * Copyright (C) 2001,02,03 NEC Corporation
+ * Copyright (C) 2001,02,03 Miles Bader <miles@gnu.org>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file COPYING in the main directory of this
+ * archive for more details.
+ *
+ * Written by Miles Bader <miles@gnu.org>
+ */
+
+#ifndef __V850_RTE_ME2_CB_H__
+#define __V850_RTE_ME2_CB_H__
+
+#include <asm/rte_cb.h> /* Common defs for Midas RTE-CB boards. */
+
+
+#define PLATFORM "rte-v850e/me2-cb"
+#define PLATFORM_LONG "Midas lab RTE-V850E/ME2-CB"
+
+#define CPU_CLOCK_FREQ 150000000 /* 150MHz */
+#define FIXED_BOGOMIPS 50
+
+/* 32MB of onbard SDRAM. */
+#define SDRAM_ADDR 0x00800000
+#define SDRAM_SIZE 0x02000000 /* 32MB */
+
+
+/* CPU addresses of GBUS memory spaces. */
+#define GCS0_ADDR 0x04000000 /* GCS0 - Common SRAM (2MB) */
+#define GCS0_SIZE 0x00800000 /* 8MB */
+#define GCS1_ADDR 0x04800000 /* GCS1 - Flash ROM (8MB) */
+#define GCS1_SIZE 0x00800000 /* 8MB */
+#define GCS2_ADDR 0x07000000 /* GCS2 - I/O registers */
+#define GCS2_SIZE 0x00800000 /* 8MB */
+#define GCS5_ADDR 0x08000000 /* GCS5 - PCI bus space */
+#define GCS5_SIZE 0x02000000 /* 32MB */
+#define GCS6_ADDR 0x07800000 /* GCS6 - PCI control registers */
+#define GCS6_SIZE 0x00800000 /* 8MB */
+
+
+/* For <asm/page.h> */
+#define PAGE_OFFSET SDRAM_ADDR
+
+
+#ifdef CONFIG_ROM_KERNEL
+/* Kernel is in ROM, starting at address 0. */
+
+#define INTV_BASE 0
+#define ROOT_FS_IMAGE_RW 0
+
+#else /* !CONFIG_ROM_KERNEL */
+/* Using RAM-kernel. Assume some sort of boot-loader got us loaded at
+ address 0. */
+
+#define INTV_BASE 0
+#define ROOT_FS_IMAGE_RW 1
+
+#endif /* CONFIG_ROM_KERNEL */
+
+
+/* Some misc. on-board devices. */
+
+/* Seven-segment LED display (four digits). */
+#define LED_ADDR(n) (0x0FE02000 + (n))
+#define LED(n) (*(volatile unsigned char *)LED_ADDR(n))
+#define LED_NUM_DIGITS 4
+
+
+/* On-board PIC. */
+
+#define CB_PIC_BASE_ADDR 0x0FE04000
+
+#define CB_PIC_INT0M_ADDR (CB_PIC_BASE_ADDR + 0x00)
+#define CB_PIC_INT0M (*(volatile u16 *)CB_PIC_INT0M_ADDR)
+#define CB_PIC_INT1M_ADDR (CB_PIC_BASE_ADDR + 0x10)
+#define CB_PIC_INT1M (*(volatile u16 *)CB_PIC_INT1M_ADDR)
+#define CB_PIC_INTR_ADDR (CB_PIC_BASE_ADDR + 0x20)
+#define CB_PIC_INTR (*(volatile u16 *)CB_PIC_INTR_ADDR)
+#define CB_PIC_INTEN_ADDR (CB_PIC_BASE_ADDR + 0x30)
+#define CB_PIC_INTEN (*(volatile u16 *)CB_PIC_INTEN_ADDR)
+
+#define CB_PIC_INT0EN 0x0001
+#define CB_PIC_INT1EN 0x0002
+#define CB_PIC_INT0SEL 0x0080
+
+/* The PIC interrupts themselves. */
+#define CB_PIC_BASE_IRQ NUM_CPU_IRQS
+#define IRQ_CB_PIC_NUM 10
+
+/* Some specific CB_PIC interrupts. */
+#define IRQ_CB_EXTTM0 (CB_PIC_BASE_IRQ + 0)
+#define IRQ_CB_EXTSIO (CB_PIC_BASE_IRQ + 1)
+#define IRQ_CB_TOVER (CB_PIC_BASE_IRQ + 2)
+#define IRQ_CB_GINT0 (CB_PIC_BASE_IRQ + 3)
+#define IRQ_CB_USB (CB_PIC_BASE_IRQ + 4)
+#define IRQ_CB_LANC (CB_PIC_BASE_IRQ + 5)
+#define IRQ_CB_USB_VBUS_ON (CB_PIC_BASE_IRQ + 6)
+#define IRQ_CB_USB_VBUS_OFF (CB_PIC_BASE_IRQ + 7)
+#define IRQ_CB_EXTTM1 (CB_PIC_BASE_IRQ + 8)
+#define IRQ_CB_EXTTM2 (CB_PIC_BASE_IRQ + 9)
+
+/* The GBUS GINT1 - GINT3 (note, not GINT0!) interrupts are connected to
+ the INTP65 - INTP67 pins on the CPU. These are shared among the GBUS
+ interrupts. */
+#define IRQ_GINT(n) IRQ_INTP((n) + 9) /* 0 is unused! */
+#define IRQ_GINT_NUM 4 /* 0 is unused! */
+
+/* The shared interrupt line from the PIC is connected to CPU pin INTP23. */
+#define IRQ_CB_PIC IRQ_INTP(4) /* P23 */
+
+/* Used by <asm/rte_cb.h> to derive NUM_MACH_IRQS. */
+#define NUM_RTE_CB_IRQS (NUM_CPU_IRQS + IRQ_CB_PIC_NUM)
+
+
+#ifndef __ASSEMBLY__
+struct cb_pic_irq_init {
+ const char *name; /* name of interrupt type */
+
+ /* Range of kernel irq numbers for this type:
+ BASE, BASE+INTERVAL, ..., BASE+INTERVAL*NUM */
+ unsigned base, num, interval;
+
+ unsigned priority; /* interrupt priority to assign */
+};
+struct hw_interrupt_type; /* fwd decl */
+
+/* Enable interrupt handling for interrupt IRQ. */
+extern void cb_pic_enable_irq (unsigned irq);
+/* Disable interrupt handling for interrupt IRQ. Note that any interrupts
+ received while disabled will be delivered once the interrupt is enabled
+ again, unless they are explicitly cleared using `cb_pic_clear_pending_irq'. */
+extern void cb_pic_disable_irq (unsigned irq);
+/* Initialize HW_IRQ_TYPES for PIC irqs described in array INITS (which is
+ terminated by an entry with the name field == 0). */
+extern void cb_pic_init_irq_types (struct cb_pic_irq_init *inits,
+ struct hw_interrupt_type *hw_irq_types);
+/* Initialize PIC interrupts. */
+extern void cb_pic_init_irqs (void);
+#endif /* __ASSEMBLY__ */
+
+
+/* TL16C550C on board UART see also asm/serial.h */
+#define CB_UART_BASE 0x0FE08000
+#define CB_UART_REG_GAP 0x10
+#define CB_UART_CLOCK 0x16000000
+
+/* CompactFlash setting see also asm/ide.h, asm/hdreg.h. */
+#define CB_CF_BASE 0x0FE0C000
+#define CB_CF_CCR_ADDR (CB_CF_BASE+0x200)
+#define CB_CF_CCR (*(volatile u8 *)CB_CF_CCR_ADDR)
+#define CB_CF_REG0_ADDR (CB_CF_BASE+0x1000)
+#define CB_CF_REG0 (*(volatile u16 *)CB_CF_REG0_ADDR)
+#define CB_CF_STS0_ADDR (CB_CF_BASE+0x1004)
+#define CB_CF_STS0 (*(volatile u16 *)CB_CF_STS0_ADDR)
+#define CB_PCATA_BASE (CB_CF_BASE+0x800)
+#define CB_IDE_BASE (CB_CF_BASE+0x9F0)
+#define CB_IDE_CTRL (CB_CF_BASE+0xBF6)
+#define CB_IDE_REG_OFFS 0x1
+
+
+/* SMSC LAN91C111 setting */
+#if defined(CONFIG_SMC91111)
+#define CB_LANC_BASE 0x0FE10300
+#define CONFIG_SMC16BITONLY
+#define ETH0_ADDR CB_LANC_BASE
+#define ETH0_IRQ IRQ_CB_LANC
+#endif /* CONFIG_SMC16BITONLY */
+
+
+#undef V850E_UART_PRE_CONFIGURE
+#define V850E_UART_PRE_CONFIGURE rte_me2_cb_uart_pre_configure
+#ifndef __ASSEMBLY__
+extern void rte_me2_cb_uart_pre_configure (unsigned chan,
+ unsigned cflags, unsigned baud);
+#endif /* __ASSEMBLY__ */
+
+/* This board supports RTS/CTS for the on-chip UART, but only for channel 0. */
+
+/* CTS for UART channel 0 is pin P22 (bit 2 of port 2). */
+#define V850E_UART_CTS(chan) ((chan) == 0 ? !(ME2_PORT2_IO & 0x4) : 1)
+/* RTS for UART channel 0 is pin P21 (bit 1 of port 2). */
+#define V850E_UART_SET_RTS(chan, val) \
+ do { \
+ if (chan == 0) { \
+ unsigned old = ME2_PORT2_IO; \
+ if (val) \
+ ME2_PORT2_IO = old & ~0x2; \
+ else \
+ ME2_PORT2_IO = old | 0x2; \
+ } \
+ } while (0)
+
+
+#ifndef __ASSEMBLY__
+extern void rte_me2_cb_init_irqs (void);
+#endif /* !__ASSEMBLY__ */
+
+
+#endif /* __V850_RTE_ME2_CB_H__ */
diff --git a/include/asm-v850/rte_nb85e_cb.h b/include/asm-v850/rte_nb85e_cb.h
index e3799a1ec831..f56591cad90a 100644
--- a/include/asm-v850/rte_nb85e_cb.h
+++ b/include/asm-v850/rte_nb85e_cb.h
@@ -17,6 +17,21 @@
#include <asm/rte_cb.h> /* Common defs for Midas RTE-CB boards. */
+#define PLATFORM "rte-v850e/nb85e-cb"
+#define PLATFORM_LONG "Midas lab RTE-V850E/NB85E-CB"
+
+#define CPU_CLOCK_FREQ 50000000 /* 50MHz */
+
+/* 1MB of onboard SRAM. Note that the monitor ROM uses parts of this
+ for its own purposes, so care must be taken. */
+#define SRAM_ADDR 0x03C00000
+#define SRAM_SIZE 0x00100000 /* 1MB */
+
+/* 16MB of onbard SDRAM. */
+#define SDRAM_ADDR 0x01000000
+#define SDRAM_SIZE 0x01000000 /* 16MB */
+
+
/* CPU addresses of GBUS memory spaces. */
#define GCS0_ADDR 0x00400000 /* GCS0 - Common SRAM (2MB) */
#define GCS0_SIZE 0x00400000 /* 4MB */
@@ -39,20 +54,8 @@
#define IRQ_GINT(n) (10 + (n))
#define IRQ_GINT_NUM 3
-
-#define PLATFORM "rte-v850e/nb85e-cb"
-#define PLATFORM_LONG "Midas lab RTE-V850E/NB85E-CB"
-
-#define CPU_CLOCK_FREQ 50000000 /* 50MHz */
-
-/* 1MB of onboard SRAM. Note that the monitor ROM uses parts of this
- for its own purposes, so care must be taken. */
-#define SRAM_ADDR 0x03C00000
-#define SRAM_SIZE 0x00100000 /* 1MB */
-
-/* 16MB of onbard SDRAM. */
-#define SDRAM_ADDR 0x01000000
-#define SDRAM_SIZE 0x01000000 /* 16MB */
+/* Used by <asm/rte_cb.h> to derive NUM_MACH_IRQS. */
+#define NUM_RTE_CB_IRQS NUM_CPU_IRQS
#ifdef CONFIG_ROM_KERNEL
@@ -86,8 +89,8 @@
/* Override the basic TEG UART pre-initialization so that we can
initialize extra stuff. */
-#undef NB85E_UART_PRE_CONFIGURE /* should be defined by <asm/teg.h> */
-#define NB85E_UART_PRE_CONFIGURE rte_nb85e_cb_uart_pre_configure
+#undef V850E_UART_PRE_CONFIGURE /* should be defined by <asm/teg.h> */
+#define V850E_UART_PRE_CONFIGURE rte_nb85e_cb_uart_pre_configure
#ifndef __ASSEMBLY__
extern void rte_nb85e_cb_uart_pre_configure (unsigned chan,
unsigned cflags, unsigned baud);
@@ -96,9 +99,9 @@ extern void rte_nb85e_cb_uart_pre_configure (unsigned chan,
/* This board supports RTS/CTS for the on-chip UART. */
/* CTS is pin P00. */
-#define NB85E_UART_CTS(chan) (! (TEG_PORT0_IO & 0x1))
+#define V850E_UART_CTS(chan) (! (TEG_PORT0_IO & 0x1))
/* RTS is pin P02. */
-#define NB85E_UART_SET_RTS(chan, val) \
+#define V850E_UART_SET_RTS(chan, val) \
do { \
unsigned old = TEG_PORT0_IO; \
TEG_PORT0_IO = val ? (old & ~0x4) : (old | 0x4); \
diff --git a/include/asm-v850/serial.h b/include/asm-v850/serial.h
new file mode 100644
index 000000000000..1b62e3eda886
--- /dev/null
+++ b/include/asm-v850/serial.h
@@ -0,0 +1,58 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1999 by Ralf Baechle
+ * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
+ */
+#include <linux/config.h>
+
+#ifdef CONFIG_RTE_CB_ME2
+
+#include <asm/rte_me2_cb.h>
+
+#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
+
+#define irq_cannonicalize(x) (x)
+#define BASE_BAUD 250000 /* (16MHz / (16 * 38400)) * 9600 */
+#define RS_TABLE_SIZE 1
+#define SERIAL_PORT_DFNS \
+ { 0, BASE_BAUD, CB_UART_BASE, IRQ_CB_EXTSIO, STD_COM_FLAGS },
+
+/* Redefine UART register offsets. */
+#undef UART_RX
+#undef UART_TX
+#undef UART_DLL
+#undef UART_TRG
+#undef UART_DLM
+#undef UART_IER
+#undef UART_FCTR
+#undef UART_IIR
+#undef UART_FCR
+#undef UART_EFR
+#undef UART_LCR
+#undef UART_MCR
+#undef UART_LSR
+#undef UART_MSR
+#undef UART_SCR
+#undef UART_EMSR
+
+#define UART_RX (0 * CB_UART_REG_GAP)
+#define UART_TX (0 * CB_UART_REG_GAP)
+#define UART_DLL (0 * CB_UART_REG_GAP)
+#define UART_TRG (0 * CB_UART_REG_GAP)
+#define UART_DLM (1 * CB_UART_REG_GAP)
+#define UART_IER (1 * CB_UART_REG_GAP)
+#define UART_FCTR (1 * CB_UART_REG_GAP)
+#define UART_IIR (2 * CB_UART_REG_GAP)
+#define UART_FCR (2 * CB_UART_REG_GAP)
+#define UART_EFR (2 * CB_UART_REG_GAP)
+#define UART_LCR (3 * CB_UART_REG_GAP)
+#define UART_MCR (4 * CB_UART_REG_GAP)
+#define UART_LSR (5 * CB_UART_REG_GAP)
+#define UART_MSR (6 * CB_UART_REG_GAP)
+#define UART_SCR (7 * CB_UART_REG_GAP)
+#define UART_EMSR (7 * CB_UART_REG_GAP)
+
+#endif /* CONFIG_RTE_CB_ME2 */
diff --git a/include/asm-v850/sim85e2.h b/include/asm-v850/sim85e2.h
new file mode 100644
index 000000000000..8cfb5eb13303
--- /dev/null
+++ b/include/asm-v850/sim85e2.h
@@ -0,0 +1,79 @@
+/*
+ * include/asm-v850/sim85e2.h -- Machine-dependent defs for
+ * V850E2 RTL simulator
+ *
+ * Copyright (C) 2002,03 NEC Electronics Corporation
+ * Copyright (C) 2002,03 Miles Bader <miles@gnu.org>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file COPYING in the main directory of this
+ * archive for more details.
+ *
+ * Written by Miles Bader <miles@gnu.org>
+ */
+
+#ifndef __V850_SIM85E2_H__
+#define __V850_SIM85E2_H__
+
+
+#include <asm/v850e2.h> /* Based on V850E2 core. */
+
+
+/* Various memory areas supported by the simulator.
+ These should match the corresponding definitions in the linker script. */
+
+/* `instruction RAM'; instruction fetches are much faster from IRAM than
+ from DRAM. */
+#define IRAM_ADDR 0
+#define IRAM_SIZE 0x00100000 /* 1MB */
+/* `data RAM', below and contiguous with the I/O space.
+ Data fetches are much faster from DRAM than from IRAM. */
+#define DRAM_ADDR 0xfff00000
+#define DRAM_SIZE 0x000ff000 /* 1020KB */
+/* `external ram'. Unlike the above RAM areas, this memory is cached,
+ so both instruction and data fetches should be (mostly) fast --
+ however, currently only write-through caching is supported, so writes
+ to ERAM will be slow. */
+#define ERAM_ADDR 0x00100000
+#define ERAM_SIZE 0x07f00000 /* 127MB (max) */
+/* Dynamic RAM; uses memory controller. */
+#define SDRAM_ADDR 0x10000000
+#if 0
+#define SDRAM_SIZE 0x01000000 /* 16MB */
+#else
+#define SDRAM_SIZE 0x00200000 /* Only use 2MB for testing */
+#endif
+
+
+/* Simulator specific control registers. */
+/* NOTHAL controls whether the simulator will stop at a `halt' insn. */
+#define SIM85E2_NOTHAL_ADDR 0xffffff22
+#define SIM85E2_NOTHAL (*(volatile u8 *)SIM85E2_NOTHAL_ADDR)
+/* The simulator will stop N cycles after N is written to SIMFIN. */
+#define SIM85E2_SIMFIN_ADDR 0xffffff24
+#define SIM85E2_SIMFIN (*(volatile u16 *)SIM85E2_SIMFIN_ADDR)
+
+
+/* For <asm/irq.h> */
+#define NUM_CPU_IRQS 64
+
+
+/* For <asm/page.h> */
+#define PAGE_OFFSET SDRAM_ADDR
+
+
+/* For <asm/entry.h> */
+/* `R0 RAM', used for a few miscellaneous variables that must be accessible
+ using a load instruction relative to R0. The sim85e2 simulator
+ actually puts 1020K of RAM from FFF00000 to FFFFF000, so we arbitarily
+ choose a small portion at the end of that. */
+#define R0_RAM_ADDR 0xFFFFE000
+
+
+/* For <asm/param.h> */
+#ifndef HZ
+#define HZ 24 /* Minimum supported frequency. */
+#endif
+
+
+#endif /* __V850_SIM85E2_H__ */
diff --git a/include/asm-v850/sim85e2c.h b/include/asm-v850/sim85e2c.h
index 12b87873bdef..eee543ff3af8 100644
--- a/include/asm-v850/sim85e2c.h
+++ b/include/asm-v850/sim85e2c.h
@@ -15,78 +15,12 @@
#ifndef __V850_SIM85E2C_H__
#define __V850_SIM85E2C_H__
+/* Use generic sim85e2 settings, other than the various names. */
+#include <asm/sim85e2.h>
-#define CPU_ARCH "v850e2"
#define CPU_MODEL "v850e2"
#define CPU_MODEL_LONG "NEC V850E2"
#define PLATFORM "sim85e2c"
#define PLATFORM_LONG "SIM85E2C V850E2 simulator"
-
-/* Various memory areas supported by the simulator.
- These should match the corresponding definitions in the linker script. */
-
-/* `instruction RAM'; instruction fetches are much faster from IRAM than
- from DRAM. */
-#define IRAM_ADDR 0
-#define IRAM_SIZE 0x00100000 /* 1MB */
-/* `data RAM', below and contiguous with the I/O space.
- Data fetches are much faster from DRAM than from IRAM. */
-#define DRAM_ADDR 0xfff00000
-#define DRAM_SIZE 0x000ff000 /* 1020KB */
-/* `external ram'. Unlike the above RAM areas, this memory is cached,
- so both instruction and data fetches should be (mostly) fast --
- however, currently only write-through caching is supported, so writes
- to ERAM will be slow. */
-#define ERAM_ADDR 0x00100000
-#define ERAM_SIZE 0x07f00000 /* 127MB (max) */
-
-
-/* CPU core control registers; these should be expanded and moved into
- separate header files when we support some other processors based on
- the same E2 core. */
-/* Bus Transaction Control Register */
-#define NA85E2C_CACHE_BTSC_ADDR 0xfffff070
-#define NA85E2C_CACHE_BTSC (*(volatile unsigned short *)NA85E2C_CACHE_BTSC_ADDR)
-#define NA85E2C_CACHE_BTSC_ICM 0x1 /* icache enable */
-#define NA85E2C_CACHE_BTSC_DCM0 0x4 /* dcache enable, bit 0 */
-#define NA85E2C_CACHE_BTSC_DCM1 0x8 /* dcache enable, bit 1 */
-/* Cache Configuration Register */
-#define NA85E2C_BUSM_BHC_ADDR 0xfffff06a
-#define NA85E2C_BUSM_BHC (*(volatile unsigned short *)NA85E2C_BUSM_BHC_ADDR)
-
-/* Simulator specific control registers. */
-/* NOTHAL controls whether the simulator will stop at a `halt' insn. */
-#define NOTHAL_ADDR 0xffffff22
-#define NOTHAL (*(volatile unsigned char *)NOTHAL_ADDR)
-/* The simulator will stop N cycles after N is written to SIMFIN. */
-#define SIMFIN_ADDR 0xffffff24
-#define SIMFIN (*(volatile unsigned short *)SIMFIN_ADDR)
-
-
-/* The simulator has an nb85e-style interrupt system. */
-#include <asm/nb85e_intc.h>
-
-/* For <asm/irq.h> */
-#define NUM_CPU_IRQS 64
-
-
-/* For <asm/page.h> */
-#define PAGE_OFFSET DRAM_ADDR
-
-
-/* For <asm/entry.h> */
-/* `R0 RAM', used for a few miscellaneous variables that must be accessible
- using a load instruction relative to R0. The sim85e2c simulator
- actually puts 1020K of RAM from FFF00000 to FFFFF000, so we arbitarily
- choose a small portion at the end of that. */
-#define R0_RAM_ADDR 0xFFFFE000
-
-
-/* For <asm/param.h> */
-#ifndef HZ
-#define HZ 24 /* Minimum supported frequency. */
-#endif
-
-
#endif /* __V850_SIM85E2C_H__ */
diff --git a/include/asm-v850/sim85e2s.h b/include/asm-v850/sim85e2s.h
new file mode 100644
index 000000000000..ee066d5d3c51
--- /dev/null
+++ b/include/asm-v850/sim85e2s.h
@@ -0,0 +1,28 @@
+/*
+ * include/asm-v850/sim85e2s.h -- Machine-dependent defs for
+ * V850E2 RTL simulator
+ *
+ * Copyright (C) 2003 NEC Electronics Corporation
+ * Copyright (C) 2003 Miles Bader <miles@gnu.org>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file COPYING in the main directory of this
+ * archive for more details.
+ *
+ * Written by Miles Bader <miles@gnu.org>
+ */
+
+#ifndef __V850_SIM85E2S_H__
+#define __V850_SIM85E2S_H__
+
+#include <asm/sim85e2.h> /* Use generic sim85e2 settings. */
+#if 0
+#include <asm/v850e2_cache.h> /* + cache */
+#endif
+
+#define CPU_MODEL "v850e2"
+#define CPU_MODEL_LONG "NEC V850E2"
+#define PLATFORM "sim85e2s"
+#define PLATFORM_LONG "SIM85E2S V850E2 simulator"
+
+#endif /* __V850_SIM85E2S_H__ */
diff --git a/include/asm-v850/stat.h b/include/asm-v850/stat.h
index 09a7717eaed9..c68c60d06e2f 100644
--- a/include/asm-v850/stat.h
+++ b/include/asm-v850/stat.h
@@ -1,7 +1,7 @@
/*
* include/asm-v850/stat.h -- v850 stat structure
*
- * Copyright (C) 2001,02,03 NEC Corporation
+ * Copyright (C) 2001,02,03 NEC Electronics Corporation
* Copyright (C) 2001,02,03 Miles Bader <miles@gnu.org>
*
* This file is subject to the terms and conditions of the GNU General
diff --git a/include/asm-v850/system.h b/include/asm-v850/system.h
index a183308ec44d..072a997dc5a9 100644
--- a/include/asm-v850/system.h
+++ b/include/asm-v850/system.h
@@ -1,7 +1,7 @@
/*
* include/asm-v850/system.h -- Low-level interrupt/thread ops
*
- * Copyright (C) 2001,02,03 NEC Corporation
+ * Copyright (C) 2001,02,03 NEC Electronics Corporation
* Copyright (C) 2001,02,03 Miles Bader <miles@gnu.org>
*
* This file is subject to the terms and conditions of the GNU General
diff --git a/include/asm-v850/teg.h b/include/asm-v850/teg.h
index caeac99dd611..acc8c7d95329 100644
--- a/include/asm-v850/teg.h
+++ b/include/asm-v850/teg.h
@@ -15,9 +15,9 @@
#define __V850_TEG_H__
-/* The TEG uses the NB85E cpu core. */
-#include <asm/nb85e.h>
-#include <asm/nb85e_cache.h>
+/* The TEG uses the V850E cpu core. */
+#include <asm/v850e.h>
+#include <asm/v850e_cache.h>
#define CPU_MODEL "v850e/nb85e-teg"
@@ -51,18 +51,18 @@
/* TEG UART details. */
-#define NB85E_UART_BASE_ADDR(n) (0xFFFFF600 + 0x10 * (n))
-#define NB85E_UART_ASIM_ADDR(n) (NB85E_UART_BASE_ADDR(n) + 0x0)
-#define NB85E_UART_ASIS_ADDR(n) (NB85E_UART_BASE_ADDR(n) + 0x2)
-#define NB85E_UART_ASIF_ADDR(n) (NB85E_UART_BASE_ADDR(n) + 0x4)
-#define NB85E_UART_CKSR_ADDR(n) (NB85E_UART_BASE_ADDR(n) + 0x6)
-#define NB85E_UART_BRGC_ADDR(n) (NB85E_UART_BASE_ADDR(n) + 0x8)
-#define NB85E_UART_TXB_ADDR(n) (NB85E_UART_BASE_ADDR(n) + 0xA)
-#define NB85E_UART_RXB_ADDR(n) (NB85E_UART_BASE_ADDR(n) + 0xC)
-#define NB85E_UART_NUM_CHANNELS 1
-#define NB85E_UART_BASE_FREQ CPU_CLOCK_FREQ
+#define V850E_UART_BASE_ADDR(n) (0xFFFFF600 + 0x10 * (n))
+#define V850E_UART_ASIM_ADDR(n) (V850E_UART_BASE_ADDR(n) + 0x0)
+#define V850E_UART_ASIS_ADDR(n) (V850E_UART_BASE_ADDR(n) + 0x2)
+#define V850E_UART_ASIF_ADDR(n) (V850E_UART_BASE_ADDR(n) + 0x4)
+#define V850E_UART_CKSR_ADDR(n) (V850E_UART_BASE_ADDR(n) + 0x6)
+#define V850E_UART_BRGC_ADDR(n) (V850E_UART_BASE_ADDR(n) + 0x8)
+#define V850E_UART_TXB_ADDR(n) (V850E_UART_BASE_ADDR(n) + 0xA)
+#define V850E_UART_RXB_ADDR(n) (V850E_UART_BASE_ADDR(n) + 0xC)
+#define V850E_UART_NUM_CHANNELS 1
+#define V850E_UART_BASE_FREQ CPU_CLOCK_FREQ
/* This is a function that gets called before configuring the UART. */
-#define NB85E_UART_PRE_CONFIGURE teg_uart_pre_configure
+#define V850E_UART_PRE_CONFIGURE teg_uart_pre_configure
#ifndef __ASSEMBLY__
extern void teg_uart_pre_configure (unsigned chan,
unsigned cflags, unsigned baud);
@@ -70,15 +70,15 @@ extern void teg_uart_pre_configure (unsigned chan,
/* The TEG RTPU. */
-#define NB85E_RTPU_BASE_ADDR 0xFFFFF210
+#define V850E_RTPU_BASE_ADDR 0xFFFFF210
/* TEG series timer D details. */
-#define NB85E_TIMER_D_BASE_ADDR 0xFFFFF210
-#define NB85E_TIMER_D_TMCD_BASE_ADDR (NB85E_TIMER_D_BASE_ADDR + 0x0)
-#define NB85E_TIMER_D_TMD_BASE_ADDR (NB85E_TIMER_D_BASE_ADDR + 0x4)
-#define NB85E_TIMER_D_CMD_BASE_ADDR (NB85E_TIMER_D_BASE_ADDR + 0x8)
-#define NB85E_TIMER_D_BASE_FREQ CPU_CLOCK_FREQ
+#define V850E_TIMER_D_BASE_ADDR 0xFFFFF210
+#define V850E_TIMER_D_TMCD_BASE_ADDR (V850E_TIMER_D_BASE_ADDR + 0x0)
+#define V850E_TIMER_D_TMD_BASE_ADDR (V850E_TIMER_D_BASE_ADDR + 0x4)
+#define V850E_TIMER_D_CMD_BASE_ADDR (V850E_TIMER_D_BASE_ADDR + 0x8)
+#define V850E_TIMER_D_BASE_FREQ CPU_CLOCK_FREQ
/* `Interrupt Source Select' control register. */
diff --git a/include/asm-v850/v850e.h b/include/asm-v850/v850e.h
new file mode 100644
index 000000000000..5a222eb5117f
--- /dev/null
+++ b/include/asm-v850/v850e.h
@@ -0,0 +1,21 @@
+/*
+ * include/asm-v850/v850e.h -- V850E CPU
+ *
+ * Copyright (C) 2001,02,03 NEC Electronics Corporation
+ * Copyright (C) 2001,02,03 Miles Bader <miles@gnu.org>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file COPYING in the main directory of this
+ * archive for more details.
+ *
+ * Written by Miles Bader <miles@gnu.org>
+ */
+
+#ifndef __V850_V850E_H__
+#define __V850_V850E_H__
+
+#include <asm/v850e_intc.h>
+
+#define CPU_ARCH "v850e"
+
+#endif /* __V850_V850E_H__ */
diff --git a/include/asm-v850/v850e2.h b/include/asm-v850/v850e2.h
new file mode 100644
index 000000000000..48680408ab7e
--- /dev/null
+++ b/include/asm-v850/v850e2.h
@@ -0,0 +1,69 @@
+/*
+ * include/asm-v850/v850e2.h -- Machine-dependent defs for V850E2 CPUs
+ *
+ * Copyright (C) 2002,03 NEC Electronics Corporation
+ * Copyright (C) 2002,03 Miles Bader <miles@gnu.org>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file COPYING in the main directory of this
+ * archive for more details.
+ *
+ * Written by Miles Bader <miles@gnu.org>
+ */
+
+#ifndef __V850_V850E2_H__
+#define __V850_V850E2_H__
+
+#include <asm/v850e_intc.h> /* v850e-style interrupt system. */
+
+
+#define CPU_ARCH "v850e2"
+
+
+/* Control registers. */
+
+/* Chip area select control */
+#define V850E2_CSC_ADDR(n) (0xFFFFF060 + (n) * 2)
+#define V850E2_CSC(n) (*(volatile u16 *)V850E2_CSC_ADDR(n))
+/* I/O area select control */
+#define V850E2_BPC_ADDR 0xFFFFF064
+#define V850E2_BPC (*(volatile u16 *)V850E2_BPC_ADDR)
+/* Bus size configuration */
+#define V850E2_BSC_ADDR 0xFFFFF066
+#define V850E2_BSC (*(volatile u16 *)V850E2_BSC_ADDR)
+/* Endian configuration */
+#define V850E2_BEC_ADDR 0xFFFFF068
+#define V850E2_BEC (*(volatile u16 *)V850E2_BEC_ADDR)
+/* Cache configuration */
+#define V850E2_BHC_ADDR 0xFFFFF06A
+#define V850E2_BHC (*(volatile u16 *)V850E2_BHC_ADDR)
+/* NPB strobe-wait configuration */
+#define V850E2_VSWC_ADDR 0xFFFFF06E
+#define V850E2_VSWC (*(volatile u16 *)V850E2_VSWC_ADDR)
+/* Bus cycle type */
+#define V850E2_BCT_ADDR(n) (0xFFFFF480 + (n) * 2)
+#define V850E2_BCT(n) (*(volatile u16 *)V850E2_BCT_ADDR(n))
+/* Data wait control */
+#define V850E2_DWC_ADDR(n) (0xFFFFF484 + (n) * 2)
+#define V850E2_DWC(n) (*(volatile u16 *)V850E2_DWC_ADDR(n))
+/* Bus cycle control */
+#define V850E2_BCC_ADDR 0xFFFFF488
+#define V850E2_BCC (*(volatile u16 *)V850E2_BCC_ADDR)
+/* Address wait control */
+#define V850E2_ASC_ADDR 0xFFFFF48A
+#define V850E2_ASC (*(volatile u16 *)V850E2_ASC_ADDR)
+/* Local bus sizing control */
+#define V850E2_LBS_ADDR 0xFFFFF48E
+#define V850E2_LBS (*(volatile u16 *)V850E2_LBS_ADDR)
+/* Line buffer control */
+#define V850E2_LBC_ADDR(n) (0xFFFFF490 + (n) * 2)
+#define V850E2_LBC(n) (*(volatile u16 *)V850E2_LBC_ADDR(n))
+/* SDRAM configuration */
+#define V850E2_SCR_ADDR(n) (0xFFFFF4A0 + (n) * 4)
+#define V850E2_SCR(n) (*(volatile u16 *)V850E2_SCR_ADDR(n))
+/* SDRAM refresh cycle control */
+#define V850E2_RFS_ADDR(n) (0xFFFFF4A2 + (n) * 4)
+#define V850E2_RFS(n) (*(volatile u16 *)V850E2_RFS_ADDR(n))
+
+
+#endif /* __V850_V850E2_H__ */
diff --git a/include/asm-v850/v850e2_cache.h b/include/asm-v850/v850e2_cache.h
new file mode 100644
index 000000000000..61acda1023e8
--- /dev/null
+++ b/include/asm-v850/v850e2_cache.h
@@ -0,0 +1,74 @@
+/*
+ * include/asm-v850/v850e2_cache_cache.h -- Cache control for V850E2
+ * cache memories
+ *
+ * Copyright (C) 2003 NEC Electronics Corporation
+ * Copyright (C) 2003 Miles Bader <miles@gnu.org>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file COPYING in the main directory of this
+ * archive for more details.
+ *
+ * Written by Miles Bader <miles@gnu.org>
+ */
+
+#ifndef __V850_V850E2_CACHE_H__
+#define __V850_V850E2_CACHE_H__
+
+#include <asm/types.h>
+
+
+/* Cache control registers. */
+
+/* Bus Transaction Control */
+#define V850E2_CACHE_BTSC_ADDR 0xFFFFF070
+#define V850E2_CACHE_BTSC (*(volatile u16 *)V850E2_CACHE_BTSC_ADDR)
+#define V850E2_CACHE_BTSC_ICM 0x0001 /* icache enable */
+#define V850E2_CACHE_BTSC_DCM0 0x0004 /* dcache enable, bit 0 */
+#define V850E2_CACHE_BTSC_DCM1 0x0008 /* dcache enable, bit 1 */
+#define V850E2_CACHE_BTSC_DCM_WT /* write-through */ \
+ V850E2_CACHE_BTSC_DCM0
+#ifdef CONFIG_V850E2_V850E2S
+# define V850E2_CACHE_BTSC_DCM_WB_NO_ALLOC /* write-back, non-alloc */ \
+ V850E2_CACHE_BTSC_DCM1
+# define V850E2_CACHE_BTSC_DCM_WB_ALLOC /* write-back, non-alloc */ \
+ (V850E2_CACHE_BTSC_DCM1 | V850E2_CACHE_BTSC_DCM0)
+# define V850E2_CACHE_BTSC_ISEQ 0x0010 /* icache `address sequence mode' */
+# define V850E2_CACHE_BTSC_DSEQ 0x0020 /* dcache `address sequence mode' */
+# define V850E2_CACHE_BTSC_IRFC 0x0030
+# define V850E2_CACHE_BTSC_ILCD 0x4000
+# define V850E2_CACHE_BTSC_VABE 0x8000
+#endif /* CONFIG_V850E2_V850E2S */
+
+/* Cache operation start address register (low-bits). */
+#define V850E2_CACHE_CADL_ADDR 0xFFFFF074
+#define V850E2_CACHE_CADL (*(volatile u16 *)V850E2_CACHE_CADL_ADDR)
+/* Cache operation start address register (high-bits). */
+#define V850E2_CACHE_CADH_ADDR 0xFFFFF076
+#define V850E2_CACHE_CADH (*(volatile u16 *)V850E2_CACHE_CADH_ADDR)
+/* Cache operation count register. */
+#define V850E2_CACHE_CCNT_ADDR 0xFFFFF078
+#define V850E2_CACHE_CCNT (*(volatile u16 *)V850E2_CACHE_CCNT_ADDR)
+/* Cache operation specification register. */
+#define V850E2_CACHE_COPR_ADDR 0xFFFFF07A
+#define V850E2_CACHE_COPR (*(volatile u16 *)V850E2_CACHE_COPR_ADDR)
+#define V850E2_CACHE_COPR_STRT 0x0001 /* start cache operation */
+#define V850E2_CACHE_COPR_LBSL 0x0100 /* 0 = icache, 1 = dcache */
+#define V850E2_CACHE_COPR_WSLE 0x0200 /* operate on cache way */
+#define V850E2_CACHE_COPR_WSL(way) ((way) * 0x0400) /* way select */
+#define V850E2_CACHE_COPR_CFC(op) ((op) * 0x1000) /* cache function code */
+
+
+/* Size of a cache line in bytes. */
+#define V850E2_CACHE_LINE_SIZE_BITS 4
+#define V850E2_CACHE_LINE_SIZE (1 << V850E2_CACHE_LINE_SIZE_BITS)
+
+/* The size of each cache `way' in lines. */
+#define V850E2_CACHE_WAY_SIZE 256
+
+
+/* For <asm/cache.h> */
+#define L1_CACHE_BYTES V850E2_CACHE_LINE_SIZE
+
+
+#endif /* __V850_V850E2_CACHE_H__ */
diff --git a/include/asm-v850/v850e_cache.h b/include/asm-v850/v850e_cache.h
new file mode 100644
index 000000000000..aa7d7eb9da50
--- /dev/null
+++ b/include/asm-v850/v850e_cache.h
@@ -0,0 +1,48 @@
+/*
+ * include/asm-v850/v850e_cache.h -- Cache control for V850E cache memories
+ *
+ * Copyright (C) 2001,03 NEC Electronics Corporation
+ * Copyright (C) 2001,03 Miles Bader <miles@gnu.org>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file COPYING in the main directory of this
+ * archive for more details.
+ *
+ * Written by Miles Bader <miles@gnu.org>
+ */
+
+/* This file implements cache control for the rather simple cache used on
+ some V850E CPUs, specifically the NB85E/TEG CPU-core and the V850E/ME2
+ CPU. V850E2 processors have their own (better) cache
+ implementation. */
+
+#ifndef __V850_V850E_CACHE_H__
+#define __V850_V850E_CACHE_H__
+
+#include <asm/types.h>
+
+
+/* Cache control registers. */
+#define V850E_CACHE_BHC_ADDR 0xFFFFF06A
+#define V850E_CACHE_BHC (*(volatile u16 *)V850E_CACHE_BHC_ADDR)
+#define V850E_CACHE_ICC_ADDR 0xFFFFF070
+#define V850E_CACHE_ICC (*(volatile u16 *)V850E_CACHE_ICC_ADDR)
+#define V850E_CACHE_ISI_ADDR 0xFFFFF072
+#define V850E_CACHE_ISI (*(volatile u16 *)V850E_CACHE_ISI_ADDR)
+#define V850E_CACHE_DCC_ADDR 0xFFFFF078
+#define V850E_CACHE_DCC (*(volatile u16 *)V850E_CACHE_DCC_ADDR)
+
+/* Size of a cache line in bytes. */
+#define V850E_CACHE_LINE_SIZE 16
+
+/* For <asm/cache.h> */
+#define L1_CACHE_BYTES V850E_CACHE_LINE_SIZE
+
+
+#if defined(__KERNEL__) && !defined(__ASSEMBLY__)
+/* Set caching params via the BHC, ICC, and DCC registers. */
+void v850e_cache_enable (u16 bhc, u16 icc, u16 dcc);
+#endif /* __KERNEL__ && !__ASSEMBLY__ */
+
+
+#endif /* __V850_V850E_CACHE_H__ */
diff --git a/include/asm-v850/nb85e_intc.h b/include/asm-v850/v850e_intc.h
index d81b777363cc..6fdf95708317 100644
--- a/include/asm-v850/nb85e_intc.h
+++ b/include/asm-v850/v850e_intc.h
@@ -1,5 +1,5 @@
/*
- * include/asm-v850/nb85e_intc.h -- NB85E cpu core interrupt controller (INTC)
+ * include/asm-v850/v850e_intc.h -- V850E CPU interrupt controller (INTC)
*
* Copyright (C) 2001,02,03 NEC Electronics Corporation
* Copyright (C) 2001,02,03 Miles Bader <miles@gnu.org>
@@ -11,106 +11,106 @@
* Written by Miles Bader <miles@gnu.org>
*/
-#ifndef __V850_NB85E_INTC_H__
-#define __V850_NB85E_INTC_H__
+#ifndef __V850_V850E_INTC_H__
+#define __V850_V850E_INTC_H__
/* There are 4 16-bit `Interrupt Mask Registers' located contiguously
starting from this base. Each interrupt uses a single bit to
indicated enabled/disabled status. */
-#define NB85E_INTC_IMR_BASE_ADDR 0xFFFFF100
-#define NB85E_INTC_IMR_ADDR(irq) (NB85E_INTC_IMR_BASE_ADDR + ((irq) >> 3))
-#define NB85E_INTC_IMR_BIT(irq) ((irq) & 0x7)
+#define V850E_INTC_IMR_BASE_ADDR 0xFFFFF100
+#define V850E_INTC_IMR_ADDR(irq) (V850E_INTC_IMR_BASE_ADDR + ((irq) >> 3))
+#define V850E_INTC_IMR_BIT(irq) ((irq) & 0x7)
/* Each maskable interrupt has a single-byte control register at this
address. */
-#define NB85E_INTC_IC_BASE_ADDR 0xFFFFF110
-#define NB85E_INTC_IC_ADDR(irq) (NB85E_INTC_IC_BASE_ADDR + ((irq) << 1))
-#define NB85E_INTC_IC(irq) (*(volatile u8 *)NB85E_INTC_IC_ADDR(irq))
+#define V850E_INTC_IC_BASE_ADDR 0xFFFFF110
+#define V850E_INTC_IC_ADDR(irq) (V850E_INTC_IC_BASE_ADDR + ((irq) << 1))
+#define V850E_INTC_IC(irq) (*(volatile u8 *)V850E_INTC_IC_ADDR(irq))
/* Encode priority PR for storing in an interrupt control register. */
-#define NB85E_INTC_IC_PR(pr) (pr)
+#define V850E_INTC_IC_PR(pr) (pr)
/* Interrupt disable bit in an interrupt control register. */
-#define NB85E_INTC_IC_MK_BIT 6
-#define NB85E_INTC_IC_MK (1 << NB85E_INTC_IC_MK_BIT)
+#define V850E_INTC_IC_MK_BIT 6
+#define V850E_INTC_IC_MK (1 << V850E_INTC_IC_MK_BIT)
/* Interrupt pending flag in an interrupt control register. */
-#define NB85E_INTC_IC_IF_BIT 7
-#define NB85E_INTC_IC_IF (1 << NB85E_INTC_IC_IF_BIT)
+#define V850E_INTC_IC_IF_BIT 7
+#define V850E_INTC_IC_IF (1 << V850E_INTC_IC_IF_BIT)
/* The ISPR (In-service priority register) contains one bit for each interrupt
priority level, which is set to one when that level is currently being
serviced (and thus blocking any interrupts of equal or lesser level). */
-#define NB85E_INTC_ISPR_ADDR 0xFFFFF1FA
-#define NB85E_INTC_ISPR (*(volatile u8 *)NB85E_INTC_ISPR_ADDR)
+#define V850E_INTC_ISPR_ADDR 0xFFFFF1FA
+#define V850E_INTC_ISPR (*(volatile u8 *)V850E_INTC_ISPR_ADDR)
#ifndef __ASSEMBLY__
/* Enable interrupt handling for interrupt IRQ. */
-static inline void nb85e_intc_enable_irq (unsigned irq)
+static inline void v850e_intc_enable_irq (unsigned irq)
{
__asm__ __volatile__ ("clr1 %0, [%1]"
- :: "r" (NB85E_INTC_IMR_BIT (irq)),
- "r" (NB85E_INTC_IMR_ADDR (irq))
+ :: "r" (V850E_INTC_IMR_BIT (irq)),
+ "r" (V850E_INTC_IMR_ADDR (irq))
: "memory");
}
/* Disable interrupt handling for interrupt IRQ. Note that any
interrupts received while disabled will be delivered once the
interrupt is enabled again, unless they are explicitly cleared using
- `nb85e_intc_clear_pending_irq'. */
-static inline void nb85e_intc_disable_irq (unsigned irq)
+ `v850e_intc_clear_pending_irq'. */
+static inline void v850e_intc_disable_irq (unsigned irq)
{
__asm__ __volatile__ ("set1 %0, [%1]"
- :: "r" (NB85E_INTC_IMR_BIT (irq)),
- "r" (NB85E_INTC_IMR_ADDR (irq))
+ :: "r" (V850E_INTC_IMR_BIT (irq)),
+ "r" (V850E_INTC_IMR_ADDR (irq))
: "memory");
}
/* Return true if interrupt handling for interrupt IRQ is enabled. */
-static inline int nb85e_intc_irq_enabled (unsigned irq)
+static inline int v850e_intc_irq_enabled (unsigned irq)
{
int rval;
__asm__ __volatile__ ("tst1 %1, [%2]; setf z, %0"
: "=r" (rval)
- : "r" (NB85E_INTC_IMR_BIT (irq)),
- "r" (NB85E_INTC_IMR_ADDR (irq)));
+ : "r" (V850E_INTC_IMR_BIT (irq)),
+ "r" (V850E_INTC_IMR_ADDR (irq)));
return rval;
}
/* Disable irqs from 0 until LIMIT. LIMIT must be a multiple of 8. */
-static inline void _nb85e_intc_disable_irqs (unsigned limit)
+static inline void _v850e_intc_disable_irqs (unsigned limit)
{
unsigned long addr;
- for (addr = NB85E_INTC_IMR_BASE_ADDR; limit >= 8; addr++, limit -= 8)
+ for (addr = V850E_INTC_IMR_BASE_ADDR; limit >= 8; addr++, limit -= 8)
*(char *)addr = 0xFF;
}
/* Disable all irqs. This is purposely a macro, because NUM_MACH_IRQS
will be only be defined later. */
-#define nb85e_intc_disable_irqs() _nb85e_intc_disable_irqs (NUM_MACH_IRQS)
+#define v850e_intc_disable_irqs() _v850e_intc_disable_irqs (NUM_MACH_IRQS)
/* Clear any pending interrupts for IRQ. */
-static inline void nb85e_intc_clear_pending_irq (unsigned irq)
+static inline void v850e_intc_clear_pending_irq (unsigned irq)
{
__asm__ __volatile__ ("clr1 %0, 0[%1]"
- :: "i" (NB85E_INTC_IC_IF_BIT),
- "r" (NB85E_INTC_IC_ADDR (irq))
+ :: "i" (V850E_INTC_IC_IF_BIT),
+ "r" (V850E_INTC_IC_ADDR (irq))
: "memory");
}
/* Return true if interrupt IRQ is pending (but disabled). */
-static inline int nb85e_intc_irq_pending (unsigned irq)
+static inline int v850e_intc_irq_pending (unsigned irq)
{
int rval;
__asm__ __volatile__ ("tst1 %1, 0[%2]; setf nz, %0"
: "=r" (rval)
- : "i" (NB85E_INTC_IC_IF_BIT),
- "r" (NB85E_INTC_IC_ADDR (irq)));
+ : "i" (V850E_INTC_IC_IF_BIT),
+ "r" (V850E_INTC_IC_ADDR (irq)));
return rval;
}
-struct nb85e_intc_irq_init {
+struct v850e_intc_irq_init {
const char *name; /* name of interrupt type */
/* Range of kernel irq numbers for this type:
@@ -123,11 +123,11 @@ struct hw_interrupt_type; /* fwd decl */
/* Initialize HW_IRQ_TYPES for INTC-controlled irqs described in array
INITS (which is terminated by an entry with the name field == 0). */
-extern void nb85e_intc_init_irq_types (struct nb85e_intc_irq_init *inits,
+extern void v850e_intc_init_irq_types (struct v850e_intc_irq_init *inits,
struct hw_interrupt_type *hw_irq_types);
#endif /* !__ASSEMBLY__ */
-#endif /* __V850_NB85E_INTC_H__ */
+#endif /* __V850_V850E_INTC_H__ */
diff --git a/include/asm-v850/v850e_timer_c.h b/include/asm-v850/v850e_timer_c.h
new file mode 100644
index 000000000000..f70575df6ea9
--- /dev/null
+++ b/include/asm-v850/v850e_timer_c.h
@@ -0,0 +1,48 @@
+/*
+ * include/asm-v850/v850e_timer_c.h -- `Timer C' component often used
+ * with the V850E cpu core
+ *
+ * Copyright (C) 2001,03 NEC Electronics Corporation
+ * Copyright (C) 2001,03 Miles Bader <miles@gnu.org>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file COPYING in the main directory of this
+ * archive for more details.
+ *
+ * Written by Miles Bader <miles@gnu.org>
+ */
+
+/* NOTE: this include file currently contains only enough to allow us to
+ use timer C as an interrupt pass-through. */
+
+#ifndef __V850_V850E_TIMER_C_H__
+#define __V850_V850E_TIMER_C_H__
+
+#include <asm/types.h>
+#include <asm/machdep.h> /* Pick up chip-specific defs. */
+
+
+/* Timer C (16-bit interval timers). */
+
+/* Control register 0 for timer C. */
+#define V850E_TIMER_C_TMCC0_ADDR(n) (V850E_TIMER_C_BASE_ADDR + 0x6 + 0x10 *(n))
+#define V850E_TIMER_C_TMCC0(n) (*(volatile u8 *)V850E_TIMER_C_TMCC0_ADDR(n))
+#define V850E_TIMER_C_TMCC0_CAE 0x01 /* clock action enable */
+#define V850E_TIMER_C_TMCC0_CE 0x02 /* count enable */
+/* ... */
+
+/* Control register 1 for timer C. */
+#define V850E_TIMER_C_TMCC1_ADDR(n) (V850E_TIMER_C_BASE_ADDR + 0x8 + 0x10 *(n))
+#define V850E_TIMER_C_TMCC1(n) (*(volatile u8 *)V850E_TIMER_C_TMCC1_ADDR(n))
+#define V850E_TIMER_C_TMCC1_CMS0 0x01 /* capture/compare mode select (ccc0) */
+#define V850E_TIMER_C_TMCC1_CMS1 0x02 /* capture/compare mode select (ccc1) */
+/* ... */
+
+/* Interrupt edge-sensitivity control for timer C. */
+#define V850E_TIMER_C_SESC_ADDR(n) (V850E_TIMER_C_BASE_ADDR + 0x9 + 0x10 *(n))
+#define V850E_TIMER_C_SESC(n) (*(volatile u8 *)V850E_TIMER_C_SESC_ADDR(n))
+
+/* ...etc... */
+
+
+#endif /* __V850_V850E_TIMER_C_H__ */
diff --git a/include/asm-v850/nb85e_timer_d.h b/include/asm-v850/v850e_timer_d.h
index 2243bc1732c8..417612c5b22f 100644
--- a/include/asm-v850/nb85e_timer_d.h
+++ b/include/asm-v850/v850e_timer_d.h
@@ -1,6 +1,6 @@
/*
- * include/asm-v850/nb85e_timer_d.h -- `Timer D' component often used
- * with the NB85E cpu core
+ * include/asm-v850/v850e_timer_d.h -- `Timer D' component often used
+ * with the V850E cpu core
*
* Copyright (C) 2001,02,03 NEC Electronics Corporation
* Copyright (C) 2001,02,03 Miles Bader <miles@gnu.org>
@@ -12,8 +12,8 @@
* Written by Miles Bader <miles@gnu.org>
*/
-#ifndef __V850_NB85E_TIMER_D_H__
-#define __V850_NB85E_TIMER_D_H__
+#ifndef __V850_V850E_TIMER_D_H__
+#define __V850_V850E_TIMER_D_H__
#include <asm/types.h>
#include <asm/machdep.h> /* Pick up chip-specific defs. */
@@ -22,31 +22,31 @@
/* Timer D (16-bit interval timers). */
/* Count registers for timer D. */
-#define NB85E_TIMER_D_TMD_ADDR(n) (NB85E_TIMER_D_TMD_BASE_ADDR + 0x10 * (n))
-#define NB85E_TIMER_D_TMD(n) (*(volatile u16 *)NB85E_TIMER_D_TMD_ADDR(n))
+#define V850E_TIMER_D_TMD_ADDR(n) (V850E_TIMER_D_TMD_BASE_ADDR + 0x10 * (n))
+#define V850E_TIMER_D_TMD(n) (*(volatile u16 *)V850E_TIMER_D_TMD_ADDR(n))
/* Count compare registers for timer D. */
-#define NB85E_TIMER_D_CMD_ADDR(n) (NB85E_TIMER_D_CMD_BASE_ADDR + 0x10 * (n))
-#define NB85E_TIMER_D_CMD(n) (*(volatile u16 *)NB85E_TIMER_D_CMD_ADDR(n))
+#define V850E_TIMER_D_CMD_ADDR(n) (V850E_TIMER_D_CMD_BASE_ADDR + 0x10 * (n))
+#define V850E_TIMER_D_CMD(n) (*(volatile u16 *)V850E_TIMER_D_CMD_ADDR(n))
/* Control registers for timer D. */
-#define NB85E_TIMER_D_TMCD_ADDR(n) (NB85E_TIMER_D_TMCD_BASE_ADDR + 0x10 * (n))
-#define NB85E_TIMER_D_TMCD(n) (*(volatile u8 *)NB85E_TIMER_D_TMCD_ADDR(n))
+#define V850E_TIMER_D_TMCD_ADDR(n) (V850E_TIMER_D_TMCD_BASE_ADDR + 0x10 * (n))
+#define V850E_TIMER_D_TMCD(n) (*(volatile u8 *)V850E_TIMER_D_TMCD_ADDR(n))
/* Control bits for timer D. */
-#define NB85E_TIMER_D_TMCD_CE 0x2 /* count enable */
-#define NB85E_TIMER_D_TMCD_CAE 0x1 /* clock action enable */
+#define V850E_TIMER_D_TMCD_CE 0x2 /* count enable */
+#define V850E_TIMER_D_TMCD_CAE 0x1 /* clock action enable */
/* Clock divider setting (log2). */
-#define NB85E_TIMER_D_TMCD_CS(divlog2) (((divlog2) - NB85E_TIMER_D_TMCD_CS_MIN) << 4)
+#define V850E_TIMER_D_TMCD_CS(divlog2) (((divlog2) - V850E_TIMER_D_TMCD_CS_MIN) << 4)
/* Minimum clock divider setting (log2). */
-#ifndef NB85E_TIMER_D_TMCD_CS_MIN /* Can be overridden by mach-specific hdrs */
-#define NB85E_TIMER_D_TMCD_CS_MIN 2 /* Default is correct for the v850e/ma1 */
+#ifndef V850E_TIMER_D_TMCD_CS_MIN /* Can be overridden by mach-specific hdrs */
+#define V850E_TIMER_D_TMCD_CS_MIN 2 /* Default is correct for the v850e/ma1 */
#endif
/* Maximum clock divider setting (log2). */
-#define NB85E_TIMER_D_TMCD_CS_MAX (NB85E_TIMER_D_TMCD_CS_MIN + 7)
+#define V850E_TIMER_D_TMCD_CS_MAX (V850E_TIMER_D_TMCD_CS_MIN + 7)
/* Return the clock-divider (log2) of timer D unit N. */
-#define NB85E_TIMER_D_DIVLOG2(n) \
- (((NB85E_TIMER_D_TMCD(n) >> 4) & 0x7) + NB85E_TIMER_D_TMCD_CS_MIN)
+#define V850E_TIMER_D_DIVLOG2(n) \
+ (((V850E_TIMER_D_TMCD(n) >> 4) & 0x7) + V850E_TIMER_D_TMCD_CS_MIN)
#ifndef __ASSEMBLY__
@@ -54,9 +54,9 @@
/* Start interval timer TIMER (0-3). The timer will issue the
corresponding INTCMD interrupt RATE times per second. This function
does not enable the interrupt. */
-extern void nb85e_timer_d_configure (unsigned timer, unsigned rate);
+extern void v850e_timer_d_configure (unsigned timer, unsigned rate);
#endif /* !__ASSEMBLY__ */
-#endif /* __V850_NB85E_TIMER_D_H__ */
+#endif /* __V850_V850E_TIMER_D_H__ */
diff --git a/include/asm-v850/v850e_uart.h b/include/asm-v850/v850e_uart.h
new file mode 100644
index 000000000000..5930d5990b19
--- /dev/null
+++ b/include/asm-v850/v850e_uart.h
@@ -0,0 +1,77 @@
+/*
+ * include/asm-v850/v850e_uart.h -- common V850E on-chip UART driver
+ *
+ * Copyright (C) 2001,02,03 NEC Electronics Corporation
+ * Copyright (C) 2001,02,03 Miles Bader <miles@gnu.org>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file COPYING in the main directory of this
+ * archive for more details.
+ *
+ * Written by Miles Bader <miles@gnu.org>
+ */
+
+/* There's not actually a single UART implementation used by V850E CPUs,
+ but rather a series of implementations that are all `close' to one
+ another. This file corresponds to the single driver which handles all
+ of them. */
+
+#ifndef __V850_V850E_UART_H__
+#define __V850_V850E_UART_H__
+
+#include <linux/config.h>
+#include <linux/termios.h>
+
+#include <asm/v850e_utils.h>
+#include <asm/types.h>
+#include <asm/machdep.h> /* Pick up chip-specific defs. */
+
+
+/* Include model-specific definitions. */
+#ifdef CONFIG_V850E_UART
+# ifdef CONFIG_V850E_UARTB
+# include <asm-v850/v850e_uartb.h>
+# else
+# include <asm-v850/v850e_uarta.h> /* original V850E UART */
+# endif
+#endif
+
+
+/* Optional capabilities some hardware provides. */
+
+/* This UART doesn't implement RTS/CTS by default, but some platforms
+ implement them externally, so check to see if <asm/machdep.h> defined
+ anything. */
+#ifdef V850E_UART_CTS
+#define v850e_uart_cts(n) V850E_UART_CTS(n)
+#else
+#define v850e_uart_cts(n) (1)
+#endif
+
+/* Do the same for RTS. */
+#ifdef V850E_UART_SET_RTS
+#define v850e_uart_set_rts(n,v) V850E_UART_SET_RTS(n,v)
+#else
+#define v850e_uart_set_rts(n,v) ((void)0)
+#endif
+
+
+/* This is the serial channel to use for the boot console (if desired). */
+#ifndef V850E_UART_CONSOLE_CHANNEL
+# define V850E_UART_CONSOLE_CHANNEL 0
+#endif
+
+
+#ifndef __ASSEMBLY__
+
+/* Setup a console using channel 0 of the builtin uart. */
+extern void v850e_uart_cons_init (unsigned chan);
+
+/* Configure and turn on uart channel CHAN, using the termios `control
+ modes' bits in CFLAGS, and a baud-rate of BAUD. */
+void v850e_uart_configure (unsigned chan, unsigned cflags, unsigned baud);
+
+#endif /* !__ASSEMBLY__ */
+
+
+#endif /* __V850_V850E_UART_H__ */
diff --git a/include/asm-v850/v850e_uarta.h b/include/asm-v850/v850e_uarta.h
new file mode 100644
index 000000000000..e483e0950725
--- /dev/null
+++ b/include/asm-v850/v850e_uarta.h
@@ -0,0 +1,278 @@
+/*
+ * include/asm-v850/v850e_uarta.h -- original V850E on-chip UART
+ *
+ * Copyright (C) 2001,02,03 NEC Electronics Corporation
+ * Copyright (C) 2001,02,03 Miles Bader <miles@gnu.org>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file COPYING in the main directory of this
+ * archive for more details.
+ *
+ * Written by Miles Bader <miles@gnu.org>
+ */
+
+/* This is the original V850E UART implementation is called just `UART' in
+ the docs, but we name this header file <asm/v850e_uarta.h> because the
+ name <asm/v850e_uart.h> is used for the common driver that handles both
+ `UART' and `UARTB' implementations. */
+
+#ifndef __V850_V850E_UARTA_H__
+#define __V850_V850E_UARTA_H__
+
+
+/* Raw hardware interface. */
+
+/* The base address of the UART control registers for channel N.
+ The default is the address used on the V850E/MA1. */
+#ifndef V850E_UART_BASE_ADDR
+#define V850E_UART_BASE_ADDR(n) (0xFFFFFA00 + 0x10 * (n))
+#endif
+
+/* Addresses of specific UART control registers for channel N.
+ The defaults are the addresses used on the V850E/MA1; if a platform
+ wants to redefine any of these, it must redefine them all. */
+#ifndef V850E_UART_ASIM_ADDR
+#define V850E_UART_ASIM_ADDR(n) (V850E_UART_BASE_ADDR(n) + 0x0)
+#define V850E_UART_RXB_ADDR(n) (V850E_UART_BASE_ADDR(n) + 0x2)
+#define V850E_UART_ASIS_ADDR(n) (V850E_UART_BASE_ADDR(n) + 0x3)
+#define V850E_UART_TXB_ADDR(n) (V850E_UART_BASE_ADDR(n) + 0x4)
+#define V850E_UART_ASIF_ADDR(n) (V850E_UART_BASE_ADDR(n) + 0x5)
+#define V850E_UART_CKSR_ADDR(n) (V850E_UART_BASE_ADDR(n) + 0x6)
+#define V850E_UART_BRGC_ADDR(n) (V850E_UART_BASE_ADDR(n) + 0x7)
+#endif
+
+/* UART config registers. */
+#define V850E_UART_ASIM(n) (*(volatile u8 *)V850E_UART_ASIM_ADDR(n))
+/* Control bits for config registers. */
+#define V850E_UART_ASIM_CAE 0x80 /* clock enable */
+#define V850E_UART_ASIM_TXE 0x40 /* transmit enable */
+#define V850E_UART_ASIM_RXE 0x20 /* receive enable */
+#define V850E_UART_ASIM_PS_MASK 0x18 /* mask covering parity-select bits */
+#define V850E_UART_ASIM_PS_NONE 0x00 /* no parity */
+#define V850E_UART_ASIM_PS_ZERO 0x08 /* zero parity */
+#define V850E_UART_ASIM_PS_ODD 0x10 /* odd parity */
+#define V850E_UART_ASIM_PS_EVEN 0x18 /* even parity */
+#define V850E_UART_ASIM_CL_8 0x04 /* char len is 8 bits (otherwise, 7) */
+#define V850E_UART_ASIM_SL_2 0x02 /* 2 stop bits (otherwise, 1) */
+#define V850E_UART_ASIM_ISRM 0x01 /* generate INTSR interrupt on errors
+ (otherwise, generate INTSER) */
+
+/* UART serial interface status registers. */
+#define V850E_UART_ASIS(n) (*(volatile u8 *)V850E_UART_ASIS_ADDR(n))
+/* Control bits for status registers. */
+#define V850E_UART_ASIS_PE 0x04 /* parity error */
+#define V850E_UART_ASIS_FE 0x02 /* framing error */
+#define V850E_UART_ASIS_OVE 0x01 /* overrun error */
+
+/* UART serial interface transmission status registers. */
+#define V850E_UART_ASIF(n) (*(volatile u8 *)V850E_UART_ASIF_ADDR(n))
+#define V850E_UART_ASIF_TXBF 0x02 /* transmit buffer flag (data in TXB) */
+#define V850E_UART_ASIF_TXSF 0x01 /* transmit shift flag (sending data) */
+
+/* UART receive buffer register. */
+#define V850E_UART_RXB(n) (*(volatile u8 *)V850E_UART_RXB_ADDR(n))
+
+/* UART transmit buffer register. */
+#define V850E_UART_TXB(n) (*(volatile u8 *)V850E_UART_TXB_ADDR(n))
+
+/* UART baud-rate generator control registers. */
+#define V850E_UART_CKSR(n) (*(volatile u8 *)V850E_UART_CKSR_ADDR(n))
+#define V850E_UART_CKSR_MAX 11
+#define V850E_UART_BRGC(n) (*(volatile u8 *)V850E_UART_BRGC_ADDR(n))
+#define V850E_UART_BRGC_MIN 8
+
+
+#ifndef V850E_UART_CKSR_MAX_FREQ
+#define V850E_UART_CKSR_MAX_FREQ (25*1000*1000)
+#endif
+
+/* Calculate the minimum value for CKSR on this processor. */
+static inline unsigned v850e_uart_cksr_min (void)
+{
+ int min = 0;
+ unsigned freq = V850E_UART_BASE_FREQ;
+ while (freq > V850E_UART_CKSR_MAX_FREQ) {
+ freq >>= 1;
+ min++;
+ }
+ return min;
+}
+
+
+/* Slightly abstract interface used by driver. */
+
+
+/* Interrupts used by the UART. */
+
+/* Received when the most recently transmitted character has been sent. */
+#define V850E_UART_TX_IRQ(chan) IRQ_INTST (chan)
+/* Received when a new character has been received. */
+#define V850E_UART_RX_IRQ(chan) IRQ_INTSR (chan)
+
+
+/* UART clock generator interface. */
+
+/* This type encapsulates a particular uart frequency. */
+typedef struct {
+ unsigned clk_divlog2;
+ unsigned brgen_count;
+} v850e_uart_speed_t;
+
+/* Calculate a uart speed from BAUD for this uart. */
+static inline v850e_uart_speed_t v850e_uart_calc_speed (unsigned baud)
+{
+ v850e_uart_speed_t speed;
+
+ /* Calculate the log2 clock divider and baud-rate counter values
+ (note that the UART divides the resulting clock by 2, so
+ multiply BAUD by 2 here to compensate). */
+ calc_counter_params (V850E_UART_BASE_FREQ, baud * 2,
+ v850e_uart_cksr_min(),
+ V850E_UART_CKSR_MAX, 8/*bits*/,
+ &speed.clk_divlog2, &speed.brgen_count);
+
+ return speed;
+}
+
+/* Return the current speed of uart channel CHAN. */
+static inline v850e_uart_speed_t v850e_uart_speed (unsigned chan)
+{
+ v850e_uart_speed_t speed;
+ speed.clk_divlog2 = V850E_UART_CKSR (chan);
+ speed.brgen_count = V850E_UART_BRGC (chan);
+ return speed;
+}
+
+/* Set the current speed of uart channel CHAN. */
+static inline void v850e_uart_set_speed(unsigned chan,v850e_uart_speed_t speed)
+{
+ V850E_UART_CKSR (chan) = speed.clk_divlog2;
+ V850E_UART_BRGC (chan) = speed.brgen_count;
+}
+
+static inline int
+v850e_uart_speed_eq (v850e_uart_speed_t speed1, v850e_uart_speed_t speed2)
+{
+ return speed1.clk_divlog2 == speed2.clk_divlog2
+ && speed1.brgen_count == speed2.brgen_count;
+}
+
+/* Minimum baud rate possible. */
+#define v850e_uart_min_baud() \
+ ((V850E_UART_BASE_FREQ >> V850E_UART_CKSR_MAX) / (2 * 255) + 1)
+
+/* Maximum baud rate possible. The error is quite high at max, though. */
+#define v850e_uart_max_baud() \
+ ((V850E_UART_BASE_FREQ >> v850e_uart_cksr_min()) / (2 *V850E_UART_BRGC_MIN))
+
+/* The `maximum' clock rate the uart can used, which is wanted (though not
+ really used in any useful way) by the serial framework. */
+#define v850e_uart_max_clock() \
+ ((V850E_UART_BASE_FREQ >> v850e_uart_cksr_min()) / 2)
+
+
+/* UART configuration interface. */
+
+/* Type of the uart config register; must be a scalar. */
+typedef u16 v850e_uart_config_t;
+
+/* The uart hardware config register for channel CHAN. */
+#define V850E_UART_CONFIG(chan) V850E_UART_ASIM (chan)
+
+/* This config bit set if the uart is enabled. */
+#define V850E_UART_CONFIG_ENABLED V850E_UART_ASIM_CAE
+/* If the uart _isn't_ enabled, store this value to it to do so. */
+#define V850E_UART_CONFIG_INIT V850E_UART_ASIM_CAE
+/* Store this config value to disable the uart channel completely. */
+#define V850E_UART_CONFIG_FINI 0
+
+/* Setting/clearing these bits enable/disable TX/RX, respectively (but
+ otherwise generally leave things running). */
+#define V850E_UART_CONFIG_RX_ENABLE V850E_UART_ASIM_RXE
+#define V850E_UART_CONFIG_TX_ENABLE V850E_UART_ASIM_TXE
+
+/* These masks define which config bits affect TX/RX modes, respectively. */
+#define V850E_UART_CONFIG_RX_BITS \
+ (V850E_UART_ASIM_PS_MASK | V850E_UART_ASIM_CL_8 | V850E_UART_ASIM_ISRM)
+#define V850E_UART_CONFIG_TX_BITS \
+ (V850E_UART_ASIM_PS_MASK | V850E_UART_ASIM_CL_8 | V850E_UART_ASIM_SL_2)
+
+static inline v850e_uart_config_t v850e_uart_calc_config (unsigned cflags)
+{
+ v850e_uart_config_t config = 0;
+
+ /* Figure out new configuration of control register. */
+ if (cflags & CSTOPB)
+ /* Number of stop bits, 1 or 2. */
+ config |= V850E_UART_ASIM_SL_2;
+ if ((cflags & CSIZE) == CS8)
+ /* Number of data bits, 7 or 8. */
+ config |= V850E_UART_ASIM_CL_8;
+ if (! (cflags & PARENB))
+ /* No parity check/generation. */
+ config |= V850E_UART_ASIM_PS_NONE;
+ else if (cflags & PARODD)
+ /* Odd parity check/generation. */
+ config |= V850E_UART_ASIM_PS_ODD;
+ else
+ /* Even parity check/generation. */
+ config |= V850E_UART_ASIM_PS_EVEN;
+ if (cflags & CREAD)
+ /* Reading enabled. */
+ config |= V850E_UART_ASIM_RXE;
+
+ config |= V850E_UART_ASIM_CAE;
+ config |= V850E_UART_ASIM_TXE; /* Writing is always enabled. */
+ config |= V850E_UART_ASIM_ISRM; /* Errors generate a read-irq. */
+
+ return config;
+}
+
+/* This should delay as long as necessary for a recently written config
+ setting to settle, before we turn the uart back on. */
+static inline void
+v850e_uart_config_delay (v850e_uart_config_t config, v850e_uart_speed_t speed)
+{
+ /* The UART may not be reset properly unless we wait at least 2
+ `basic-clocks' until turning on the TXE/RXE bits again.
+ A `basic clock' is the clock used by the baud-rate generator,
+ i.e., the cpu clock divided by the 2^new_clk_divlog2.
+ The loop takes 2 insns, so loop CYCLES / 2 times. */
+ register unsigned count = 1 << speed.clk_divlog2;
+ while (--count != 0)
+ /* nothing */;
+}
+
+
+/* RX/TX interface. */
+
+/* Return true if all characters awaiting transmission on uart channel N
+ have been transmitted. */
+#define v850e_uart_xmit_done(n) \
+ (! (V850E_UART_ASIF(n) & V850E_UART_ASIF_TXBF))
+/* Wait for this to be true. */
+#define v850e_uart_wait_for_xmit_done(n) \
+ do { } while (! v850e_uart_xmit_done (n))
+
+/* Return true if uart channel N is ready to transmit a character. */
+#define v850e_uart_xmit_ok(n) \
+ (v850e_uart_xmit_done(n) && v850e_uart_cts(n))
+/* Wait for this to be true. */
+#define v850e_uart_wait_for_xmit_ok(n) \
+ do { } while (! v850e_uart_xmit_ok (n))
+
+/* Write character CH to uart channel CHAN. */
+#define v850e_uart_putc(chan, ch) (V850E_UART_TXB(chan) = (ch))
+
+/* Return latest character read on channel CHAN. */
+#define v850e_uart_getc(chan) V850E_UART_RXB (chan)
+
+/* Return bit-mask of uart error status. */
+#define v850e_uart_err(chan) V850E_UART_ASIS (chan)
+/* Various error bits set in the error result. */
+#define V850E_UART_ERR_OVERRUN V850E_UART_ASIS_OVE
+#define V850E_UART_ERR_FRAME V850E_UART_ASIS_FE
+#define V850E_UART_ERR_PARITY V850E_UART_ASIS_PE
+
+
+#endif /* __V850_V850E_UARTA_H__ */
diff --git a/include/asm-v850/v850e_uartb.h b/include/asm-v850/v850e_uartb.h
new file mode 100644
index 000000000000..6d4767d5a835
--- /dev/null
+++ b/include/asm-v850/v850e_uartb.h
@@ -0,0 +1,262 @@
+/*
+ * include/asm-v850/v850e_uartb.h -- V850E on-chip `UARTB' UART
+ *
+ * Copyright (C) 2001,02,03 NEC Electronics Corporation
+ * Copyright (C) 2001,02,03 Miles Bader <miles@gnu.org>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file COPYING in the main directory of this
+ * archive for more details.
+ *
+ * Written by Miles Bader <miles@gnu.org>
+ */
+
+/* The V850E UARTB is basically a superset of the original V850E UART, but
+ even where it's the same, the names and details have changed a bit.
+ It's similar enough to use the same driver (v850e_uart.c), but the
+ details have been abstracted slightly to do so. */
+
+#ifndef __V850_V850E_UARTB_H__
+#define __V850_V850E_UARTB_H__
+
+
+/* Raw hardware interface. */
+
+#define V850E_UARTB_BASE_ADDR(n) (0xFFFFFA00 + 0x10 * (n))
+
+/* Addresses of specific UART control registers for channel N. */
+#define V850E_UARTB_CTL0_ADDR(n) (V850E_UARTB_BASE_ADDR(n) + 0x0)
+#define V850E_UARTB_CTL2_ADDR(n) (V850E_UARTB_BASE_ADDR(n) + 0x2)
+#define V850E_UARTB_STR_ADDR(n) (V850E_UARTB_BASE_ADDR(n) + 0x4)
+#define V850E_UARTB_RX_ADDR(n) (V850E_UARTB_BASE_ADDR(n) + 0x6)
+#define V850E_UARTB_RXAP_ADDR(n) (V850E_UARTB_BASE_ADDR(n) + 0x6)
+#define V850E_UARTB_TX_ADDR(n) (V850E_UARTB_BASE_ADDR(n) + 0x8)
+#define V850E_UARTB_FIC0_ADDR(n) (V850E_UARTB_BASE_ADDR(n) + 0xA)
+#define V850E_UARTB_FIC1_ADDR(n) (V850E_UARTB_BASE_ADDR(n) + 0xB)
+#define V850E_UARTB_FIC2_ADDR(n) (V850E_UARTB_BASE_ADDR(n) + 0xC)
+#define V850E_UARTB_FIS0_ADDR(n) (V850E_UARTB_BASE_ADDR(n) + 0xE)
+#define V850E_UARTB_FIS1_ADDR(n) (V850E_UARTB_BASE_ADDR(n) + 0xF)
+
+/* UARTB control register 0 (general config). */
+#define V850E_UARTB_CTL0(n) (*(volatile u8 *)V850E_UARTB_CTL0_ADDR(n))
+/* Control bits for config registers. */
+#define V850E_UARTB_CTL0_PWR 0x80 /* clock enable */
+#define V850E_UARTB_CTL0_TXE 0x40 /* transmit enable */
+#define V850E_UARTB_CTL0_RXE 0x20 /* receive enable */
+#define V850E_UARTB_CTL0_DIR 0x10 /* */
+#define V850E_UARTB_CTL0_PS1 0x08 /* parity */
+#define V850E_UARTB_CTL0_PS0 0x04 /* parity */
+#define V850E_UARTB_CTL0_CL 0x02 /* char len 1:8bit, 0:7bit */
+#define V850E_UARTB_CTL0_SL 0x01 /* stop bit 1:2bit, 0:1bit */
+#define V850E_UARTB_CTL0_PS_MASK 0x0C /* mask covering parity bits */
+#define V850E_UARTB_CTL0_PS_NONE 0x00 /* no parity */
+#define V850E_UARTB_CTL0_PS_ZERO 0x04 /* zero parity */
+#define V850E_UARTB_CTL0_PS_ODD 0x08 /* odd parity */
+#define V850E_UARTB_CTL0_PS_EVEN 0x0C /* even parity */
+#define V850E_UARTB_CTL0_CL_8 0x02 /* char len 1:8bit, 0:7bit */
+#define V850E_UARTB_CTL0_SL_2 0x01 /* stop bit 1:2bit, 0:1bit */
+
+/* UARTB control register 2 (clock divider). */
+#define V850E_UARTB_CTL2(n) (*(volatile u16 *)V850E_UARTB_CTL2_ADDR(n))
+#define V850E_UARTB_CTL2_MIN 4
+#define V850E_UARTB_CTL2_MAX 0xFFFF
+
+/* UARTB serial interface status register. */
+#define V850E_UARTB_STR(n) (*(volatile u8 *)V850E_UARTB_STR_ADDR(n))
+/* Control bits for status registers. */
+#define V850E_UARTB_STR_TSF 0x80 /* UBTX or FIFO exist data */
+#define V850E_UARTB_STR_OVF 0x08 /* overflow error */
+#define V850E_UARTB_STR_PE 0x04 /* parity error */
+#define V850E_UARTB_STR_FE 0x02 /* framing error */
+#define V850E_UARTB_STR_OVE 0x01 /* overrun error */
+
+/* UARTB receive data register. */
+#define V850E_UARTB_RX(n) (*(volatile u8 *)V850E_UARTB_RX_ADDR(n))
+#define V850E_UARTB_RXAP(n) (*(volatile u16 *)V850E_UARTB_RXAP_ADDR(n))
+/* Control bits for status registers. */
+#define V850E_UARTB_RXAP_PEF 0x0200 /* parity error */
+#define V850E_UARTB_RXAP_FEF 0x0100 /* framing error */
+
+/* UARTB transmit data register. */
+#define V850E_UARTB_TX(n) (*(volatile u8 *)V850E_UARTB_TX_ADDR(n))
+
+/* UARTB FIFO control register 0. */
+#define V850E_UARTB_FIC0(n) (*(volatile u8 *)V850E_UARTB_FIC0_ADDR(n))
+
+/* UARTB FIFO control register 1. */
+#define V850E_UARTB_FIC1(n) (*(volatile u8 *)V850E_UARTB_FIC1_ADDR(n))
+
+/* UARTB FIFO control register 2. */
+#define V850E_UARTB_FIC2(n) (*(volatile u16 *)V850E_UARTB_FIC2_ADDR(n))
+
+/* UARTB FIFO status register 0. */
+#define V850E_UARTB_FIS0(n) (*(volatile u8 *)V850E_UARTB_FIS0_ADDR(n))
+
+/* UARTB FIFO status register 1. */
+#define V850E_UARTB_FIS1(n) (*(volatile u8 *)V850E_UARTB_FIS1_ADDR(n))
+
+
+/* Slightly abstract interface used by driver. */
+
+
+/* Interrupts used by the UART. */
+
+/* Received when the most recently transmitted character has been sent. */
+#define V850E_UART_TX_IRQ(chan) IRQ_INTUBTIT (chan)
+/* Received when a new character has been received. */
+#define V850E_UART_RX_IRQ(chan) IRQ_INTUBTIR (chan)
+
+/* Use by serial driver for information purposes. */
+#define V850E_UART_BASE_ADDR(chan) V850E_UARTB_BASE_ADDR(chan)
+
+
+/* UART clock generator interface. */
+
+/* This type encapsulates a particular uart frequency. */
+typedef u16 v850e_uart_speed_t;
+
+/* Calculate a uart speed from BAUD for this uart. */
+static inline v850e_uart_speed_t v850e_uart_calc_speed (unsigned baud)
+{
+ v850e_uart_speed_t speed;
+
+ /*
+ * V850E/ME2 UARTB baud rate is determined by the value of UBCTL2
+ * fx = V850E_UARTB_BASE_FREQ = CPU_CLOCK_FREQ/4
+ * baud = fx / 2*speed [ speed >= 4 ]
+ */
+ speed = V850E_UARTB_CTL2_MIN;
+ while (((V850E_UARTB_BASE_FREQ / 2) / speed ) > baud)
+ speed++;
+
+ return speed;
+}
+
+/* Return the current speed of uart channel CHAN. */
+#define v850e_uart_speed(chan) V850E_UARTB_CTL2 (chan)
+
+/* Set the current speed of uart channel CHAN. */
+#define v850e_uart_set_speed(chan, speed) (V850E_UARTB_CTL2 (chan) = (speed))
+
+/* Return true if SPEED1 and SPEED2 are the same. */
+#define v850e_uart_speed_eq(speed1, speed2) ((speed1) == (speed2))
+
+/* Minimum baud rate possible. */
+#define v850e_uart_min_baud() \
+ ((V850E_UARTB_BASE_FREQ / 2) / V850E_UARTB_CTL2_MAX)
+
+/* Maximum baud rate possible. The error is quite high at max, though. */
+#define v850e_uart_max_baud() \
+ ((V850E_UARTB_BASE_FREQ / 2) / V850E_UARTB_CTL2_MIN)
+
+/* The `maximum' clock rate the uart can used, which is wanted (though not
+ really used in any useful way) by the serial framework. */
+#define v850e_uart_max_clock() \
+ (V850E_UARTB_BASE_FREQ / 2)
+
+
+/* UART configuration interface. */
+
+/* Type of the uart config register; must be a scalar. */
+typedef u16 v850e_uart_config_t;
+
+/* The uart hardware config register for channel CHAN. */
+#define V850E_UART_CONFIG(chan) V850E_UARTB_CTL0 (chan)
+
+/* This config bit set if the uart is enabled. */
+#define V850E_UART_CONFIG_ENABLED V850E_UARTB_CTL0_PWR
+/* If the uart _isn't_ enabled, store this value to it to do so. */
+#define V850E_UART_CONFIG_INIT V850E_UARTB_CTL0_PWR
+/* Store this config value to disable the uart channel completely. */
+#define V850E_UART_CONFIG_FINI 0
+
+/* Setting/clearing these bits enable/disable TX/RX, respectively (but
+ otherwise generally leave things running). */
+#define V850E_UART_CONFIG_RX_ENABLE V850E_UARTB_CTL0_RXE
+#define V850E_UART_CONFIG_TX_ENABLE V850E_UARTB_CTL0_TXE
+
+/* These masks define which config bits affect TX/RX modes, respectively. */
+#define V850E_UART_CONFIG_RX_BITS \
+ (V850E_UARTB_CTL0_PS_MASK | V850E_UARTB_CTL0_CL_8)
+#define V850E_UART_CONFIG_TX_BITS \
+ (V850E_UARTB_CTL0_PS_MASK | V850E_UARTB_CTL0_CL_8 | V850E_UARTB_CTL0_SL_2)
+
+static inline v850e_uart_config_t v850e_uart_calc_config (unsigned cflags)
+{
+ v850e_uart_config_t config = 0;
+
+ /* Figure out new configuration of control register. */
+ if (cflags & CSTOPB)
+ /* Number of stop bits, 1 or 2. */
+ config |= V850E_UARTB_CTL0_SL_2;
+ if ((cflags & CSIZE) == CS8)
+ /* Number of data bits, 7 or 8. */
+ config |= V850E_UARTB_CTL0_CL_8;
+ if (! (cflags & PARENB))
+ /* No parity check/generation. */
+ config |= V850E_UARTB_CTL0_PS_NONE;
+ else if (cflags & PARODD)
+ /* Odd parity check/generation. */
+ config |= V850E_UARTB_CTL0_PS_ODD;
+ else
+ /* Even parity check/generation. */
+ config |= V850E_UARTB_CTL0_PS_EVEN;
+ if (cflags & CREAD)
+ /* Reading enabled. */
+ config |= V850E_UARTB_CTL0_RXE;
+
+ config |= V850E_UARTB_CTL0_PWR;
+ config |= V850E_UARTB_CTL0_TXE; /* Writing is always enabled. */
+ config |= V850E_UARTB_CTL0_DIR; /* LSB first. */
+
+ return config;
+}
+
+/* This should delay as long as necessary for a recently written config
+ setting to settle, before we turn the uart back on. */
+static inline void
+v850e_uart_config_delay (v850e_uart_config_t config, v850e_uart_speed_t speed)
+{
+ /* The UART may not be reset properly unless we wait at least 2
+ `basic-clocks' until turning on the TXE/RXE bits again.
+ A `basic clock' is the clock used by the baud-rate generator,
+ i.e., the cpu clock divided by the 2^new_clk_divlog2.
+ The loop takes 2 insns, so loop CYCLES / 2 times. */
+ register unsigned count = 1 << speed;
+ while (--count != 0)
+ /* nothing */;
+}
+
+
+/* RX/TX interface. */
+
+/* Return true if all characters awaiting transmission on uart channel N
+ have been transmitted. */
+#define v850e_uart_xmit_done(n) \
+ (! (V850E_UARTB_STR(n) & V850E_UARTB_STR_TSF))
+/* Wait for this to be true. */
+#define v850e_uart_wait_for_xmit_done(n) \
+ do { } while (! v850e_uart_xmit_done (n))
+
+/* Return true if uart channel N is ready to transmit a character. */
+#define v850e_uart_xmit_ok(n) \
+ (v850e_uart_xmit_done(n) && v850e_uart_cts(n))
+/* Wait for this to be true. */
+#define v850e_uart_wait_for_xmit_ok(n) \
+ do { } while (! v850e_uart_xmit_ok (n))
+
+/* Write character CH to uart channel CHAN. */
+#define v850e_uart_putc(chan, ch) (V850E_UARTB_TX(chan) = (ch))
+
+/* Return latest character read on channel CHAN. */
+#define v850e_uart_getc(chan) V850E_UARTB_RX (chan)
+
+/* Return bit-mask of uart error status. */
+#define v850e_uart_err(chan) V850E_UARTB_STR (chan)
+/* Various error bits set in the error result. */
+#define V850E_UART_ERR_OVERRUN V850E_UARTB_STR_OVE
+#define V850E_UART_ERR_FRAME V850E_UARTB_STR_FE
+#define V850E_UART_ERR_PARITY V850E_UARTB_STR_PE
+
+
+#endif /* __V850_V850E_UARTB_H__ */
diff --git a/include/asm-v850/nb85e_utils.h b/include/asm-v850/v850e_utils.h
index 56314a2e070a..52eb72822d3d 100644
--- a/include/asm-v850/nb85e_utils.h
+++ b/include/asm-v850/v850e_utils.h
@@ -1,9 +1,9 @@
/*
- * include/asm-v850/nb85e_utils.h -- Utility functions associated with
- * the NB85E cpu core
+ * include/asm-v850/v850e_utils.h -- Utility functions associated with
+ * V850E CPUs
*
- * Copyright (C) 2001 NEC Corporation
- * Copyright (C) 2001 Miles Bader <miles@gnu.org>
+ * Copyright (C) 2001,03 NEC Electronics Corporation
+ * Copyright (C) 2001,03 Miles Bader <miles@gnu.org>
*
* This file is subject to the terms and conditions of the GNU General
* Public License. See the file COPYING in the main directory of this
@@ -12,8 +12,8 @@
* Written by Miles Bader <miles@gnu.org>
*/
-#ifndef __V850_NB85E_UTILS_H__
-#define __V850_NB85E_UTILS_H__
+#ifndef __V850_V850E_UTILS_H__
+#define __V850_V850E_UTILS_H__
/* Calculate counter clock-divider and count values to attain the
desired frequency RATE from the base frequency BASE_FREQ. The
@@ -32,4 +32,4 @@ extern int calc_counter_params (unsigned long base_freq,
unsigned counter_size,
unsigned *divlog2, unsigned *count);
-#endif /* __V850_NB85E_UTILS_H__ */
+#endif /* __V850_V850E_UTILS_H__ */
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 2e7f92aa1dc2..d951995038e5 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -44,9 +44,9 @@ struct as_io_context {
unsigned long ttime_samples;
unsigned long ttime_mean;
/* Layout pattern */
- long seek_samples;
+ unsigned int seek_samples;
sector_t last_request_pos;
- sector_t seek_total;
+ u64 seek_total;
sector_t seek_mean;
};
@@ -491,6 +491,7 @@ extern void __blk_attempt_remerge(request_queue_t *, struct request *);
extern struct request *blk_get_request(request_queue_t *, int, int);
extern void blk_put_request(struct request *);
extern void blk_insert_request(request_queue_t *, struct request *, int, void *);
+extern void blk_requeue_request(request_queue_t *, struct request *);
extern void blk_plug_device(request_queue_t *);
extern int blk_remove_plug(request_queue_t *);
extern void blk_recount_segments(request_queue_t *, struct bio *);
diff --git a/include/linux/dm-ioctl-v1.h b/include/linux/dm-ioctl-v1.h
new file mode 100644
index 000000000000..21bef9ec14b0
--- /dev/null
+++ b/include/linux/dm-ioctl-v1.h
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2001 Sistina Software (UK) Limited.
+ *
+ * This file is released under the LGPL.
+ */
+
+#ifndef _LINUX_DM_IOCTL_V1_H
+#define _LINUX_DM_IOCTL_V1_H
+
+#include <linux/types.h>
+
+#define DM_DIR "mapper" /* Slashes not supported */
+#define DM_MAX_TYPE_NAME 16
+#define DM_NAME_LEN 128
+#define DM_UUID_LEN 129
+
+/*
+ * Implements a traditional ioctl interface to the device mapper.
+ */
+
+/*
+ * All ioctl arguments consist of a single chunk of memory, with
+ * this structure at the start. If a uuid is specified any
+ * lookup (eg. for a DM_INFO) will be done on that, *not* the
+ * name.
+ */
+struct dm_ioctl {
+ /*
+ * The version number is made up of three parts:
+ * major - no backward or forward compatibility,
+ * minor - only backwards compatible,
+ * patch - both backwards and forwards compatible.
+ *
+ * All clients of the ioctl interface should fill in the
+ * version number of the interface that they were
+ * compiled with.
+ *
+ * All recognised ioctl commands (ie. those that don't
+ * return -ENOTTY) fill out this field, even if the
+ * command failed.
+ */
+ uint32_t version[3]; /* in/out */
+ uint32_t data_size; /* total size of data passed in
+ * including this struct */
+
+ uint32_t data_start; /* offset to start of data
+ * relative to start of this struct */
+
+ uint32_t target_count; /* in/out */
+ uint32_t open_count; /* out */
+ uint32_t flags; /* in/out */
+
+ __kernel_dev_t dev; /* in/out */
+
+ char name[DM_NAME_LEN]; /* device name */
+ char uuid[DM_UUID_LEN]; /* unique identifier for
+ * the block device */
+};
+
+/*
+ * Used to specify tables. These structures appear after the
+ * dm_ioctl.
+ */
+struct dm_target_spec {
+ int32_t status; /* used when reading from kernel only */
+ uint64_t sector_start;
+ uint32_t length;
+
+ /*
+ * Offset in bytes (from the start of this struct) to
+ * next target_spec.
+ */
+ uint32_t next;
+
+ char target_type[DM_MAX_TYPE_NAME];
+
+ /*
+ * Parameter string starts immediately after this object.
+ * Be careful to add padding after string to ensure correct
+ * alignment of subsequent dm_target_spec.
+ */
+};
+
+/*
+ * Used to retrieve the target dependencies.
+ */
+struct dm_target_deps {
+ uint32_t count;
+
+ __kernel_dev_t dev[0]; /* out */
+};
+
+/*
+ * If you change this make sure you make the corresponding change
+ * to dm-ioctl.c:lookup_ioctl()
+ */
+enum {
+ /* Top level cmds */
+ DM_VERSION_CMD = 0,
+ DM_REMOVE_ALL_CMD,
+
+ /* device level cmds */
+ DM_DEV_CREATE_CMD,
+ DM_DEV_REMOVE_CMD,
+ DM_DEV_RELOAD_CMD,
+ DM_DEV_RENAME_CMD,
+ DM_DEV_SUSPEND_CMD,
+ DM_DEV_DEPS_CMD,
+ DM_DEV_STATUS_CMD,
+
+ /* target level cmds */
+ DM_TARGET_STATUS_CMD,
+ DM_TARGET_WAIT_CMD
+};
+
+#define DM_IOCTL 0xfd
+
+#define DM_VERSION _IOWR(DM_IOCTL, DM_VERSION_CMD, struct dm_ioctl)
+#define DM_REMOVE_ALL _IOWR(DM_IOCTL, DM_REMOVE_ALL_CMD, struct dm_ioctl)
+
+#define DM_DEV_CREATE _IOWR(DM_IOCTL, DM_DEV_CREATE_CMD, struct dm_ioctl)
+#define DM_DEV_REMOVE _IOWR(DM_IOCTL, DM_DEV_REMOVE_CMD, struct dm_ioctl)
+#define DM_DEV_RELOAD _IOWR(DM_IOCTL, DM_DEV_RELOAD_CMD, struct dm_ioctl)
+#define DM_DEV_SUSPEND _IOWR(DM_IOCTL, DM_DEV_SUSPEND_CMD, struct dm_ioctl)
+#define DM_DEV_RENAME _IOWR(DM_IOCTL, DM_DEV_RENAME_CMD, struct dm_ioctl)
+#define DM_DEV_DEPS _IOWR(DM_IOCTL, DM_DEV_DEPS_CMD, struct dm_ioctl)
+#define DM_DEV_STATUS _IOWR(DM_IOCTL, DM_DEV_STATUS_CMD, struct dm_ioctl)
+
+#define DM_TARGET_STATUS _IOWR(DM_IOCTL, DM_TARGET_STATUS_CMD, struct dm_ioctl)
+#define DM_TARGET_WAIT _IOWR(DM_IOCTL, DM_TARGET_WAIT_CMD, struct dm_ioctl)
+
+#define DM_VERSION_MAJOR 1
+#define DM_VERSION_MINOR 0
+#define DM_VERSION_PATCHLEVEL 6
+#define DM_VERSION_EXTRA "-ioctl (2002-10-15)"
+
+/* Status bits */
+#define DM_READONLY_FLAG 0x00000001
+#define DM_SUSPEND_FLAG 0x00000002
+#define DM_EXISTS_FLAG 0x00000004
+#define DM_PERSISTENT_DEV_FLAG 0x00000008
+
+/*
+ * Flag passed into ioctl STATUS command to get table information
+ * rather than current status.
+ */
+#define DM_STATUS_TABLE_FLAG 0x00000010
+
+#endif /* _LINUX_DM_IOCTL_H */
diff --git a/include/linux/dm-ioctl-v4.h b/include/linux/dm-ioctl-v4.h
new file mode 100644
index 000000000000..74a8d14b885d
--- /dev/null
+++ b/include/linux/dm-ioctl-v4.h
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2001 - 2003 Sistina Software (UK) Limited.
+ *
+ * This file is released under the LGPL.
+ */
+
+#ifndef _LINUX_DM_IOCTL_V4_H
+#define _LINUX_DM_IOCTL_V4_H
+
+#include <linux/types.h>
+
+#define DM_DIR "mapper" /* Slashes not supported */
+#define DM_MAX_TYPE_NAME 16
+#define DM_NAME_LEN 128
+#define DM_UUID_LEN 129
+
+/*
+ * A traditional ioctl interface for the device mapper.
+ *
+ * Each device can have two tables associated with it, an
+ * 'active' table which is the one currently used by io passing
+ * through the device, and an 'inactive' one which is a table
+ * that is being prepared as a replacement for the 'active' one.
+ *
+ * DM_VERSION:
+ * Just get the version information for the ioctl interface.
+ *
+ * DM_REMOVE_ALL:
+ * Remove all dm devices, destroy all tables. Only really used
+ * for debug.
+ *
+ * DM_LIST_DEVICES:
+ * Get a list of all the dm device names.
+ *
+ * DM_DEV_CREATE:
+ * Create a new device, neither the 'active' or 'inactive' table
+ * slots will be filled. The device will be in suspended state
+ * after creation, however any io to the device will get errored
+ * since it will be out-of-bounds.
+ *
+ * DM_DEV_REMOVE:
+ * Remove a device, destroy any tables.
+ *
+ * DM_DEV_RENAME:
+ * Rename a device.
+ *
+ * DM_SUSPEND:
+ * This performs both suspend and resume, depending which flag is
+ * passed in.
+ * Suspend: This command will not return until all pending io to
+ * the device has completed. Further io will be deferred until
+ * the device is resumed.
+ * Resume: It is no longer an error to issue this command on an
+ * unsuspended device. If a table is present in the 'inactive'
+ * slot, it will be moved to the active slot, then the old table
+ * from the active slot will be _destroyed_. Finally the device
+ * is resumed.
+ *
+ * DM_DEV_STATUS:
+ * Retrieves the status for the table in the 'active' slot.
+ *
+ * DM_DEV_WAIT:
+ * Wait for a significant event to occur to the device. This
+ * could either be caused by an event triggered by one of the
+ * targets of the table in the 'active' slot, or a table change.
+ *
+ * DM_TABLE_LOAD:
+ * Load a table into the 'inactive' slot for the device. The
+ * device does _not_ need to be suspended prior to this command.
+ *
+ * DM_TABLE_CLEAR:
+ * Destroy any table in the 'inactive' slot (ie. abort).
+ *
+ * DM_TABLE_DEPS:
+ * Return a set of device dependencies for the 'active' table.
+ *
+ * DM_TABLE_STATUS:
+ * Return the targets status for the 'active' table.
+ */
+
+/*
+ * All ioctl arguments consist of a single chunk of memory, with
+ * this structure at the start. If a uuid is specified any
+ * lookup (eg. for a DM_INFO) will be done on that, *not* the
+ * name.
+ */
+struct dm_ioctl {
+ /*
+ * The version number is made up of three parts:
+ * major - no backward or forward compatibility,
+ * minor - only backwards compatible,
+ * patch - both backwards and forwards compatible.
+ *
+ * All clients of the ioctl interface should fill in the
+ * version number of the interface that they were
+ * compiled with.
+ *
+ * All recognised ioctl commands (ie. those that don't
+ * return -ENOTTY) fill out this field, even if the
+ * command failed.
+ */
+ uint32_t version[3]; /* in/out */
+ uint32_t data_size; /* total size of data passed in
+ * including this struct */
+
+ uint32_t data_start; /* offset to start of data
+ * relative to start of this struct */
+
+ uint32_t target_count; /* in/out */
+ int32_t open_count; /* out */
+ uint32_t flags; /* in/out */
+ uint32_t event_nr; /* in/out */
+ uint32_t padding;
+
+ uint64_t dev; /* in/out */
+
+ char name[DM_NAME_LEN]; /* device name */
+ char uuid[DM_UUID_LEN]; /* unique identifier for
+ * the block device */
+};
+
+/*
+ * Used to specify tables. These structures appear after the
+ * dm_ioctl.
+ */
+struct dm_target_spec {
+ uint64_t sector_start;
+ uint64_t length;
+ int32_t status; /* used when reading from kernel only */
+
+ /*
+ * Offset in bytes (from the start of this struct) to
+ * next target_spec.
+ */
+ uint32_t next;
+
+ char target_type[DM_MAX_TYPE_NAME];
+
+ /*
+ * Parameter string starts immediately after this object.
+ * Be careful to add padding after string to ensure correct
+ * alignment of subsequent dm_target_spec.
+ */
+};
+
+/*
+ * Used to retrieve the target dependencies.
+ */
+struct dm_target_deps {
+ uint32_t count; /* Array size */
+ uint32_t padding; /* unused */
+ uint64_t dev[0]; /* out */
+};
+
+/*
+ * Used to get a list of all dm devices.
+ */
+struct dm_name_list {
+ uint64_t dev;
+ uint32_t next; /* offset to the next record from
+ the _start_ of this */
+ char name[0];
+};
+
+/*
+ * If you change this make sure you make the corresponding change
+ * to dm-ioctl.c:lookup_ioctl()
+ */
+enum {
+ /* Top level cmds */
+ DM_VERSION_CMD = 0,
+ DM_REMOVE_ALL_CMD,
+ DM_LIST_DEVICES_CMD,
+
+ /* device level cmds */
+ DM_DEV_CREATE_CMD,
+ DM_DEV_REMOVE_CMD,
+ DM_DEV_RENAME_CMD,
+ DM_DEV_SUSPEND_CMD,
+ DM_DEV_STATUS_CMD,
+ DM_DEV_WAIT_CMD,
+
+ /* Table level cmds */
+ DM_TABLE_LOAD_CMD,
+ DM_TABLE_CLEAR_CMD,
+ DM_TABLE_DEPS_CMD,
+ DM_TABLE_STATUS_CMD,
+};
+
+#define DM_IOCTL 0xfd
+
+#define DM_VERSION _IOWR(DM_IOCTL, DM_VERSION_CMD, struct dm_ioctl)
+#define DM_REMOVE_ALL _IOWR(DM_IOCTL, DM_REMOVE_ALL_CMD, struct dm_ioctl)
+#define DM_LIST_DEVICES _IOWR(DM_IOCTL, DM_LIST_DEVICES_CMD, struct dm_ioctl)
+
+#define DM_DEV_CREATE _IOWR(DM_IOCTL, DM_DEV_CREATE_CMD, struct dm_ioctl)
+#define DM_DEV_REMOVE _IOWR(DM_IOCTL, DM_DEV_REMOVE_CMD, struct dm_ioctl)
+#define DM_DEV_RENAME _IOWR(DM_IOCTL, DM_DEV_RENAME_CMD, struct dm_ioctl)
+#define DM_DEV_SUSPEND _IOWR(DM_IOCTL, DM_DEV_SUSPEND_CMD, struct dm_ioctl)
+#define DM_DEV_STATUS _IOWR(DM_IOCTL, DM_DEV_STATUS_CMD, struct dm_ioctl)
+#define DM_DEV_WAIT _IOWR(DM_IOCTL, DM_DEV_WAIT_CMD, struct dm_ioctl)
+
+#define DM_TABLE_LOAD _IOWR(DM_IOCTL, DM_TABLE_LOAD_CMD, struct dm_ioctl)
+#define DM_TABLE_CLEAR _IOWR(DM_IOCTL, DM_TABLE_CLEAR_CMD, struct dm_ioctl)
+#define DM_TABLE_DEPS _IOWR(DM_IOCTL, DM_TABLE_DEPS_CMD, struct dm_ioctl)
+#define DM_TABLE_STATUS _IOWR(DM_IOCTL, DM_TABLE_STATUS_CMD, struct dm_ioctl)
+
+#define DM_VERSION_MAJOR 4
+#define DM_VERSION_MINOR 0
+#define DM_VERSION_PATCHLEVEL 0
+#define DM_VERSION_EXTRA "-ioctl (2003-06-04)"
+
+/* Status bits */
+#define DM_READONLY_FLAG (1 << 0) /* In/Out */
+#define DM_SUSPEND_FLAG (1 << 1) /* In/Out */
+#define DM_PERSISTENT_DEV_FLAG (1 << 3) /* In */
+
+/*
+ * Flag passed into ioctl STATUS command to get table information
+ * rather than current status.
+ */
+#define DM_STATUS_TABLE_FLAG (1 << 4) /* In */
+
+/*
+ * Flags that indicate whether a table is present in either of
+ * the two table slots that a device has.
+ */
+#define DM_ACTIVE_PRESENT_FLAG (1 << 5) /* Out */
+#define DM_INACTIVE_PRESENT_FLAG (1 << 6) /* Out */
+
+/*
+ * Indicates that the buffer passed in wasn't big enough for the
+ * results.
+ */
+#define DM_BUFFER_FULL_FLAG (1 << 8) /* Out */
+
+#endif /* _LINUX_DM_IOCTL_H */
diff --git a/include/linux/dm-ioctl.h b/include/linux/dm-ioctl.h
index 72edd5e19e62..dddbfd9c3cf7 100644
--- a/include/linux/dm-ioctl.h
+++ b/include/linux/dm-ioctl.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2001 Sistina Software (UK) Limited.
+ * Copyright (C) 2003 Sistina Software (UK) Limited.
*
* This file is released under the LGPL.
*/
@@ -7,143 +7,12 @@
#ifndef _LINUX_DM_IOCTL_H
#define _LINUX_DM_IOCTL_H
-#include <linux/types.h>
+#include <linux/config.h>
-#define DM_DIR "mapper" /* Slashes not supported */
-#define DM_MAX_TYPE_NAME 16
-#define DM_NAME_LEN 128
-#define DM_UUID_LEN 129
+#ifdef CONFIG_DM_IOCTL_V4
+#include "dm-ioctl-v4.h"
+#else
+#include "dm-ioctl-v1.h"
+#endif
-/*
- * Implements a traditional ioctl interface to the device mapper.
- */
-
-/*
- * All ioctl arguments consist of a single chunk of memory, with
- * this structure at the start. If a uuid is specified any
- * lookup (eg. for a DM_INFO) will be done on that, *not* the
- * name.
- */
-struct dm_ioctl {
- /*
- * The version number is made up of three parts:
- * major - no backward or forward compatibility,
- * minor - only backwards compatible,
- * patch - both backwards and forwards compatible.
- *
- * All clients of the ioctl interface should fill in the
- * version number of the interface that they were
- * compiled with.
- *
- * All recognised ioctl commands (ie. those that don't
- * return -ENOTTY) fill out this field, even if the
- * command failed.
- */
- uint32_t version[3]; /* in/out */
- uint32_t data_size; /* total size of data passed in
- * including this struct */
-
- uint32_t data_start; /* offset to start of data
- * relative to start of this struct */
-
- uint32_t target_count; /* in/out */
- uint32_t open_count; /* out */
- uint32_t flags; /* in/out */
-
- __kernel_dev_t dev; /* in/out */
-
- char name[DM_NAME_LEN]; /* device name */
- char uuid[DM_UUID_LEN]; /* unique identifier for
- * the block device */
-};
-
-/*
- * Used to specify tables. These structures appear after the
- * dm_ioctl.
- */
-struct dm_target_spec {
- int32_t status; /* used when reading from kernel only */
- uint64_t sector_start;
- uint32_t length;
-
- /*
- * Offset in bytes (from the start of this struct) to
- * next target_spec.
- */
- uint32_t next;
-
- char target_type[DM_MAX_TYPE_NAME];
-
- /*
- * Parameter string starts immediately after this object.
- * Be careful to add padding after string to ensure correct
- * alignment of subsequent dm_target_spec.
- */
-};
-
-/*
- * Used to retrieve the target dependencies.
- */
-struct dm_target_deps {
- uint32_t count;
-
- __kernel_dev_t dev[0]; /* out */
-};
-
-/*
- * If you change this make sure you make the corresponding change
- * to dm-ioctl.c:lookup_ioctl()
- */
-enum {
- /* Top level cmds */
- DM_VERSION_CMD = 0,
- DM_REMOVE_ALL_CMD,
-
- /* device level cmds */
- DM_DEV_CREATE_CMD,
- DM_DEV_REMOVE_CMD,
- DM_DEV_RELOAD_CMD,
- DM_DEV_RENAME_CMD,
- DM_DEV_SUSPEND_CMD,
- DM_DEV_DEPS_CMD,
- DM_DEV_STATUS_CMD,
-
- /* target level cmds */
- DM_TARGET_STATUS_CMD,
- DM_TARGET_WAIT_CMD
-};
-
-#define DM_IOCTL 0xfd
-
-#define DM_VERSION _IOWR(DM_IOCTL, DM_VERSION_CMD, struct dm_ioctl)
-#define DM_REMOVE_ALL _IOWR(DM_IOCTL, DM_REMOVE_ALL_CMD, struct dm_ioctl)
-
-#define DM_DEV_CREATE _IOWR(DM_IOCTL, DM_DEV_CREATE_CMD, struct dm_ioctl)
-#define DM_DEV_REMOVE _IOWR(DM_IOCTL, DM_DEV_REMOVE_CMD, struct dm_ioctl)
-#define DM_DEV_RELOAD _IOWR(DM_IOCTL, DM_DEV_RELOAD_CMD, struct dm_ioctl)
-#define DM_DEV_SUSPEND _IOWR(DM_IOCTL, DM_DEV_SUSPEND_CMD, struct dm_ioctl)
-#define DM_DEV_RENAME _IOWR(DM_IOCTL, DM_DEV_RENAME_CMD, struct dm_ioctl)
-#define DM_DEV_DEPS _IOWR(DM_IOCTL, DM_DEV_DEPS_CMD, struct dm_ioctl)
-#define DM_DEV_STATUS _IOWR(DM_IOCTL, DM_DEV_STATUS_CMD, struct dm_ioctl)
-
-#define DM_TARGET_STATUS _IOWR(DM_IOCTL, DM_TARGET_STATUS_CMD, struct dm_ioctl)
-#define DM_TARGET_WAIT _IOWR(DM_IOCTL, DM_TARGET_WAIT_CMD, struct dm_ioctl)
-
-#define DM_VERSION_MAJOR 1
-#define DM_VERSION_MINOR 0
-#define DM_VERSION_PATCHLEVEL 6
-#define DM_VERSION_EXTRA "-ioctl (2002-10-15)"
-
-/* Status bits */
-#define DM_READONLY_FLAG 0x00000001
-#define DM_SUSPEND_FLAG 0x00000002
-#define DM_EXISTS_FLAG 0x00000004
-#define DM_PERSISTENT_DEV_FLAG 0x00000008
-
-/*
- * Flag passed into ioctl STATUS command to get table information
- * rather than current status.
- */
-#define DM_STATUS_TABLE_FLAG 0x00000010
-
-#endif /* _LINUX_DM_IOCTL_H */
+#endif
diff --git a/include/linux/elevator.h b/include/linux/elevator.h
index b0e70562be94..3eeb5a2e4591 100644
--- a/include/linux/elevator.h
+++ b/include/linux/elevator.h
@@ -13,6 +13,7 @@ typedef struct request *(elevator_next_req_fn) (request_queue_t *);
typedef void (elevator_add_req_fn) (request_queue_t *, struct request *, struct list_head *);
typedef int (elevator_queue_empty_fn) (request_queue_t *);
typedef void (elevator_remove_req_fn) (request_queue_t *, struct request *);
+typedef void (elevator_requeue_req_fn) (request_queue_t *, struct request *);
typedef struct request *(elevator_request_list_fn) (request_queue_t *, struct request *);
typedef struct list_head *(elevator_get_sort_head_fn) (request_queue_t *, struct request *);
typedef void (elevator_completed_req_fn) (request_queue_t *, struct request *);
@@ -33,6 +34,7 @@ struct elevator_s
elevator_next_req_fn *elevator_next_req_fn;
elevator_add_req_fn *elevator_add_req_fn;
elevator_remove_req_fn *elevator_remove_req_fn;
+ elevator_requeue_req_fn *elevator_requeue_req_fn;
elevator_queue_empty_fn *elevator_queue_empty_fn;
elevator_completed_req_fn *elevator_completed_req_fn;
@@ -64,6 +66,7 @@ extern void elv_merge_requests(request_queue_t *, struct request *,
struct request *);
extern void elv_merged_request(request_queue_t *, struct request *);
extern void elv_remove_request(request_queue_t *, struct request *);
+extern void elv_requeue_request(request_queue_t *, struct request *);
extern int elv_queue_empty(request_queue_t *);
extern struct request *elv_next_request(struct request_queue *q);
extern struct request *elv_former_request(request_queue_t *, struct request *);
diff --git a/include/linux/elfcore.h b/include/linux/elfcore.h
index 089d67225207..dbd7bb4a33b7 100644
--- a/include/linux/elfcore.h
+++ b/include/linux/elfcore.h
@@ -107,12 +107,12 @@ static inline int elf_core_copy_task_regs(struct task_struct *t, elf_gregset_t*
extern int dump_fpu (struct pt_regs *, elf_fpregset_t *);
-static inline int elf_core_copy_task_fpregs(struct task_struct *t, elf_fpregset_t *fpu)
+static inline int elf_core_copy_task_fpregs(struct task_struct *t, struct pt_regs *regs, elf_fpregset_t *fpu)
{
#ifdef ELF_CORE_COPY_FPREGS
return ELF_CORE_COPY_FPREGS(t, fpu);
#else
- return dump_fpu(NULL, fpu);
+ return dump_fpu(regs, fpu);
#endif
}
diff --git a/include/linux/ext3_jbd.h b/include/linux/ext3_jbd.h
index 27b21821ce74..50caf6875ba4 100644
--- a/include/linux/ext3_jbd.h
+++ b/include/linux/ext3_jbd.h
@@ -30,10 +30,11 @@
#define EXT3_SINGLEDATA_TRANS_BLOCKS 8U
-/* Extended attributes may touch two data buffers, two bitmap buffers,
- * and two group and summaries. */
+/* Extended attribute operations touch at most two data buffers,
+ * two bitmap buffers, and two group summaries, in addition to the inode
+ * and the superblock, which are already accounted for. */
-#define EXT3_XATTR_TRANS_BLOCKS 8
+#define EXT3_XATTR_TRANS_BLOCKS 6U
/* Define the minimum size for a transaction which modifies data. This
* needs to take into account the fact that we may end up modifying two
diff --git a/include/linux/hfs_sysdep.h b/include/linux/hfs_sysdep.h
index 1468ef02e8b6..4c4e3eba0963 100644
--- a/include/linux/hfs_sysdep.h
+++ b/include/linux/hfs_sysdep.h
@@ -28,9 +28,6 @@
extern struct timezone sys_tz;
-#undef offsetof
-#define offsetof(TYPE, MEMB) ((size_t) &((TYPE *)0)->MEMB)
-
/* Typedefs for integer types by size and signedness */
typedef __u8 hfs_u8;
typedef __u16 hfs_u16;
diff --git a/include/linux/namespace.h b/include/linux/namespace.h
index b5699538afac..fdd8abb07386 100644
--- a/include/linux/namespace.h
+++ b/include/linux/namespace.h
@@ -14,17 +14,12 @@ struct namespace {
extern void umount_tree(struct vfsmount *);
extern int copy_namespace(int, struct task_struct *);
+void __put_namespace(struct namespace *namespace);
static inline void put_namespace(struct namespace *namespace)
{
- if (atomic_dec_and_test(&namespace->count)) {
- down_write(&namespace->sem);
- spin_lock(&vfsmount_lock);
- umount_tree(namespace->root);
- spin_unlock(&vfsmount_lock);
- up_write(&namespace->sem);
- kfree(namespace);
- }
+ if (atomic_dec_and_test(&namespace->count))
+ __put_namespace(namespace);
}
static inline void exit_namespace(struct task_struct *p)
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 750f2a12cada..bf740af246c0 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -52,6 +52,7 @@ struct exec_domain;
#define CLONE_DETACHED 0x00400000 /* parent wants no child-exit signal */
#define CLONE_UNTRACED 0x00800000 /* set if the tracing process can't force CLONE_PTRACE on this clone */
#define CLONE_CHILD_SETTID 0x01000000 /* set the TID in the child */
+#define CLONE_STOPPED 0x02000000 /* Start in stopped state */
/*
* List of flags we want to share for kernel threads,
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 93ab5714ad94..a7cb796c4deb 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -57,7 +57,7 @@
#define PORT_SUNSAB 39
/* NEC v850. */
-#define PORT_NB85E_UART 40
+#define PORT_V850E_UART 40
/* NEC PC-9800 */
#define PORT_8251_PC98 41
diff --git a/include/linux/tty.h b/include/linux/tty.h
index ea8cd3a2779c..aa10cff1871c 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -57,40 +57,40 @@
*/
struct screen_info {
- unsigned char orig_x; /* 0x00 */
- unsigned char orig_y; /* 0x01 */
- unsigned short dontuse1; /* 0x02 -- EXT_MEM_K sits here */
- unsigned short orig_video_page; /* 0x04 */
- unsigned char orig_video_mode; /* 0x06 */
- unsigned char orig_video_cols; /* 0x07 */
- unsigned short unused2; /* 0x08 */
- unsigned short orig_video_ega_bx; /* 0x0a */
- unsigned short unused3; /* 0x0c */
- unsigned char orig_video_lines; /* 0x0e */
- unsigned char orig_video_isVGA; /* 0x0f */
- unsigned short orig_video_points; /* 0x10 */
+ u8 orig_x; /* 0x00 */
+ u8 orig_y; /* 0x01 */
+ u16 dontuse1; /* 0x02 -- EXT_MEM_K sits here */
+ u16 orig_video_page; /* 0x04 */
+ u8 orig_video_mode; /* 0x06 */
+ u8 orig_video_cols; /* 0x07 */
+ u16 unused2; /* 0x08 */
+ u16 orig_video_ega_bx; /* 0x0a */
+ u16 unused3; /* 0x0c */
+ u8 orig_video_lines; /* 0x0e */
+ u8 orig_video_isVGA; /* 0x0f */
+ u16 orig_video_points; /* 0x10 */
/* VESA graphic mode -- linear frame buffer */
- unsigned short lfb_width; /* 0x12 */
- unsigned short lfb_height; /* 0x14 */
- unsigned short lfb_depth; /* 0x16 */
- unsigned long lfb_base; /* 0x18 */
- unsigned long lfb_size; /* 0x1c */
- unsigned short dontuse2, dontuse3; /* 0x20 -- CL_MAGIC and CL_OFFSET here */
- unsigned short lfb_linelength; /* 0x24 */
- unsigned char red_size; /* 0x26 */
- unsigned char red_pos; /* 0x27 */
- unsigned char green_size; /* 0x28 */
- unsigned char green_pos; /* 0x29 */
- unsigned char blue_size; /* 0x2a */
- unsigned char blue_pos; /* 0x2b */
- unsigned char rsvd_size; /* 0x2c */
- unsigned char rsvd_pos; /* 0x2d */
- unsigned short vesapm_seg; /* 0x2e */
- unsigned short vesapm_off; /* 0x30 */
- unsigned short pages; /* 0x32 */
- unsigned short vesa_attributes; /* 0x34 */
- /* 0x36 -- 0x3f reserved for future expansion */
+ u16 lfb_width; /* 0x12 */
+ u16 lfb_height; /* 0x14 */
+ u16 lfb_depth; /* 0x16 */
+ u32 lfb_base; /* 0x18 */
+ u32 lfb_size; /* 0x1c */
+ u16 dontuse2, dontuse3; /* 0x20 -- CL_MAGIC and CL_OFFSET here */
+ u16 lfb_linelength; /* 0x24 */
+ u8 red_size; /* 0x26 */
+ u8 red_pos; /* 0x27 */
+ u8 green_size; /* 0x28 */
+ u8 green_pos; /* 0x29 */
+ u8 blue_size; /* 0x2a */
+ u8 blue_pos; /* 0x2b */
+ u8 rsvd_size; /* 0x2c */
+ u8 rsvd_pos; /* 0x2d */
+ u16 vesapm_seg; /* 0x2e */
+ u16 vesapm_off; /* 0x30 */
+ u16 pages; /* 0x32 */
+ u16 vesa_attributes; /* 0x34 */
+ /* 0x36 -- 0x3f reserved for future expansion */
};
extern struct screen_info screen_info;
diff --git a/include/pcmcia/ss.h b/include/pcmcia/ss.h
index 24cb380be518..08169885af48 100644
--- a/include/pcmcia/ss.h
+++ b/include/pcmcia/ss.h
@@ -51,6 +51,7 @@
#define SS_3VCARD 0x1000
#define SS_XVCARD 0x2000
#define SS_PENDING 0x4000
+#define SS_ZVCARD 0x8000
/* InquireSocket capabilities */
#define SS_CAP_PAGE_REGS 0x0001
@@ -209,6 +210,10 @@ struct pcmcia_socket {
/* socket operations */
struct pccard_operations * ops;
+ /* Zoom video behaviour is so chip specific its not worth adding
+ this to _ops */
+ void (*zoom_video)(struct pcmcia_socket *, int);
+
/* state thread */
struct semaphore skt_sem; /* protects socket h/w state */
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h
index c49c124fde74..de5ff9fd6c4a 100644
--- a/include/scsi/scsi_device.h
+++ b/include/scsi/scsi_device.h
@@ -11,8 +11,6 @@ struct scsi_mode_data;
struct scsi_device {
- struct class_device sdev_classdev;
-
struct list_head siblings; /* list of all devices on this host */
struct list_head same_target_siblings; /* just the devices sharing same target id */
struct Scsi_Host *host;
@@ -86,10 +84,11 @@ struct scsi_device {
unsigned int max_device_blocked; /* what device_blocked counts down from */
#define SCSI_DEFAULT_DEVICE_BLOCKED 3
- struct device sdev_driverfs_dev;
+ struct device sdev_gendev;
+ struct class_device sdev_classdev;
};
#define to_scsi_device(d) \
- container_of(d, struct scsi_device, sdev_driverfs_dev)
+ container_of(d, struct scsi_device, sdev_gendev)
extern struct scsi_device *scsi_add_device(struct Scsi_Host *,
uint, uint, uint);
diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
index d92dc75d131d..3ef701078fef 100644
--- a/include/scsi/scsi_host.h
+++ b/include/scsi/scsi_host.h
@@ -329,12 +329,12 @@ struct scsi_host_template {
#define SCSI_DEFAULT_HOST_BLOCKED 7
/*
- * Pointer to the sysfs class properties for this host
+ * Pointer to the sysfs class properties for this host, NULL terminated.
*/
struct class_device_attribute **shost_attrs;
/*
- * Pointer to the SCSI device properties for this host
+ * Pointer to the SCSI device properties for this host, NULL terminated.
*/
struct device_attribute **sdev_attrs;
@@ -442,12 +442,6 @@ struct Scsi_Host {
*/
unsigned int max_host_blocked;
- /*
- * Support for sysfs
- */
- struct device host_gendev;
- struct class_device class_dev;
-
/* legacy crap */
unsigned long base;
unsigned long io_port;
@@ -455,6 +449,9 @@ struct Scsi_Host {
unsigned char dma_channel;
unsigned int irq;
+ /* ldm bits */
+ struct device shost_gendev;
+ struct class_device shost_classdev;
/*
* List of hosts per template.
@@ -474,12 +471,13 @@ struct Scsi_Host {
__attribute__ ((aligned (sizeof(unsigned long))));
};
#define dev_to_shost(d) \
- container_of(d, struct Scsi_Host, host_gendev)
+ container_of(d, struct Scsi_Host, shost_gendev)
#define class_to_shost(d) \
- container_of(d, struct Scsi_Host, class_dev)
+ container_of(d, struct Scsi_Host, shost_classdev)
extern struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *, int);
extern int scsi_add_host(struct Scsi_Host *, struct device *);
+extern void scsi_scan_host(struct Scsi_Host *);
extern int scsi_remove_host(struct Scsi_Host *);
extern void scsi_host_get(struct Scsi_Host *);
extern void scsi_host_put(struct Scsi_Host *t);
@@ -495,16 +493,14 @@ static inline void scsi_assign_lock(struct Scsi_Host *shost, spinlock_t *lock)
static inline void scsi_set_device(struct Scsi_Host *shost,
struct device *dev)
{
- shost->host_gendev.parent = dev;
+ shost->shost_gendev.parent = dev;
}
static inline struct device *scsi_get_device(struct Scsi_Host *shost)
{
- return shost->host_gendev.parent;
+ return shost->shost_gendev.parent;
}
-extern void scsi_sysfs_release_attributes(struct scsi_host_template *);
-
extern void scsi_unblock_requests(struct Scsi_Host *);
extern void scsi_block_requests(struct Scsi_Host *);
diff --git a/include/scsi/scsi_request.h b/include/scsi/scsi_request.h
index 90dcdaafe946..d591d365c983 100644
--- a/include/scsi/scsi_request.h
+++ b/include/scsi/scsi_request.h
@@ -56,7 +56,7 @@ extern void scsi_do_req(struct scsi_request *, const void *cmnd,
int timeout, int retries);
struct scsi_mode_data {
- __u16 length;
+ __u32 length;
__u16 block_descriptor_length;
__u8 medium_type;
__u8 device_specific;
diff --git a/kernel/compat.c b/kernel/compat.c
index 868edf9665f1..de5820d09d71 100644
--- a/kernel/compat.c
+++ b/kernel/compat.c
@@ -425,9 +425,11 @@ asmlinkage int compat_sys_sched_getaffinity(compat_pid_t pid, unsigned int len,
&kernel_mask);
set_fs(old_fs);
- if (ret > 0)
+ if (ret > 0) {
+ ret = sizeof(compat_ulong_t);
if (put_user(kernel_mask, user_mask_ptr))
return -EFAULT;
+ }
return ret;
}
diff --git a/kernel/fork.c b/kernel/fork.c
index 2928684629e4..7c4c94b1a968 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -53,13 +53,6 @@ DEFINE_PER_CPU(unsigned long, process_counts) = 0;
rwlock_t tasklist_lock __cacheline_aligned = RW_LOCK_UNLOCKED; /* outer */
-/*
- * A per-CPU task cache - this relies on the fact that
- * the very last portion of sys_exit() is executed with
- * preemption turned off.
- */
-static task_t *task_cache[NR_CPUS] __cacheline_aligned;
-
int nr_processes(void)
{
int cpu;
@@ -80,26 +73,8 @@ static kmem_cache_t *task_struct_cachep;
static void free_task(struct task_struct *tsk)
{
- /*
- * The task cache is effectively disabled right now.
- * Do we want it? The slab cache already has per-cpu
- * stuff, but the thread info (usually a order-1 page
- * allocation) doesn't.
- */
- if (tsk != current) {
- free_thread_info(tsk->thread_info);
- free_task_struct(tsk);
- } else {
- int cpu = get_cpu();
-
- tsk = task_cache[cpu];
- if (tsk) {
- free_thread_info(tsk->thread_info);
- free_task_struct(tsk);
- }
- task_cache[cpu] = current;
- put_cpu();
- }
+ free_thread_info(tsk->thread_info);
+ free_task_struct(tsk);
}
void __put_task_struct(struct task_struct *tsk)
@@ -220,25 +195,18 @@ static struct task_struct *dup_task_struct(struct task_struct *orig)
{
struct task_struct *tsk;
struct thread_info *ti;
- int cpu = get_cpu();
prepare_to_copy(orig);
- tsk = task_cache[cpu];
- task_cache[cpu] = NULL;
- put_cpu();
- if (!tsk) {
- tsk = alloc_task_struct();
- if (!tsk)
- return NULL;
-
- ti = alloc_thread_info(tsk);
- if (!ti) {
- free_task_struct(tsk);
- return NULL;
- }
- } else
- ti = tsk->thread_info;
+ tsk = alloc_task_struct();
+ if (!tsk)
+ return NULL;
+
+ ti = alloc_thread_info(tsk);
+ if (!ti) {
+ free_task_struct(tsk);
+ return NULL;
+ }
*ti = *orig->thread_info;
*tsk = *orig;
@@ -791,8 +759,10 @@ struct task_struct *copy_process(unsigned long clone_flags,
goto fork_out;
retval = -EAGAIN;
- if (atomic_read(&p->user->processes) >= p->rlim[RLIMIT_NPROC].rlim_cur) {
- if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RESOURCE))
+ if (atomic_read(&p->user->processes) >=
+ p->rlim[RLIMIT_NPROC].rlim_cur) {
+ if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RESOURCE) &&
+ p->user != &root_user)
goto bad_fork_free;
}
@@ -1106,7 +1076,7 @@ long do_fork(unsigned long clone_flags,
init_completion(&vfork);
}
- if (p->ptrace & PT_PTRACED) {
+ if ((p->ptrace & PT_PTRACED) || (clone_flags & CLONE_STOPPED)) {
/*
* We'll start up with an immediate SIGSTOP.
*/
@@ -1114,7 +1084,9 @@ long do_fork(unsigned long clone_flags,
set_tsk_thread_flag(p, TIF_SIGPENDING);
}
- wake_up_forked_process(p); /* do this last */
+ p->state = TASK_STOPPED;
+ if (!(clone_flags & CLONE_STOPPED))
+ wake_up_forked_process(p); /* do this last */
++total_forks;
if (unlikely (trace)) {
diff --git a/kernel/sched.c b/kernel/sched.c
index ba4897671015..0bb4f13e95fd 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -2080,7 +2080,7 @@ asmlinkage long sys_sched_get_priority_max(int policy)
}
/**
- * sys_sched_get_priority_mix - return minimum RT priority.
+ * sys_sched_get_priority_min - return minimum RT priority.
* @policy: scheduling class.
*
* this syscall returns the minimum rt_priority that can be used
@@ -2541,7 +2541,7 @@ void __might_sleep(char *file, int line)
if (time_before(jiffies, prev_jiffy + HZ))
return;
prev_jiffy = jiffies;
- printk(KERN_ERR "Debug: sleeping function called from illegal"
+ printk(KERN_ERR "Debug: sleeping function called from invalid"
" context at %s:%d\n", file, line);
dump_stack();
}
diff --git a/kernel/sys.c b/kernel/sys.c
index 4c3f48c93148..0bd0c5a399a6 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -601,6 +601,14 @@ static int set_user(uid_t new_ruid, int dumpclear)
new_user = alloc_uid(new_ruid);
if (!new_user)
return -EAGAIN;
+
+ if (atomic_read(&new_user->processes) >=
+ current->rlim[RLIMIT_NPROC].rlim_cur &&
+ new_user != &root_user) {
+ free_uid(new_user);
+ return -EAGAIN;
+ }
+
switch_uid(new_user);
if(dumpclear)
@@ -1159,6 +1167,7 @@ asmlinkage long sys_newuname(struct new_utsname __user * name)
asmlinkage long sys_sethostname(char __user *name, int len)
{
int errno;
+ char tmp[__NEW_UTS_LEN];
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
@@ -1166,7 +1175,8 @@ asmlinkage long sys_sethostname(char __user *name, int len)
return -EINVAL;
down_write(&uts_sem);
errno = -EFAULT;
- if (!copy_from_user(system_utsname.nodename, name, len)) {
+ if (!copy_from_user(tmp, name, len)) {
+ memcpy(system_utsname.nodename, tmp, len);
system_utsname.nodename[len] = 0;
errno = 0;
}
@@ -1198,6 +1208,7 @@ asmlinkage long sys_gethostname(char __user *name, int len)
asmlinkage long sys_setdomainname(char __user *name, int len)
{
int errno;
+ char tmp[__NEW_UTS_LEN];
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
@@ -1206,9 +1217,10 @@ asmlinkage long sys_setdomainname(char __user *name, int len)
down_write(&uts_sem);
errno = -EFAULT;
- if (!copy_from_user(system_utsname.domainname, name, len)) {
- errno = 0;
+ if (!copy_from_user(tmp, name, len)) {
+ memcpy(system_utsname.domainname, tmp, len);
system_utsname.domainname[len] = 0;
+ errno = 0;
}
up_write(&uts_sem);
return errno;
diff --git a/kernel/time.c b/kernel/time.c
index beb7b007b443..fd23f6774b56 100644
--- a/kernel/time.c
+++ b/kernel/time.c
@@ -66,7 +66,7 @@ asmlinkage long sys_time(int * tloc)
* architectures that need it).
*/
-asmlinkage long sys_stime(int * tptr)
+asmlinkage long sys_stime(time_t *tptr)
{
struct timespec tv;
@@ -160,22 +160,25 @@ int do_sys_settimeofday(struct timespec *tv, struct timezone *tz)
return 0;
}
-asmlinkage long sys_settimeofday(struct timeval __user *tv, struct timezone __user *tz)
+asmlinkage long sys_settimeofday(struct timeval __user *tv,
+ struct timezone __user *tz)
{
- struct timespec new_tv;
+ struct timeval user_tv;
+ struct timespec new_ts;
struct timezone new_tz;
if (tv) {
- if (copy_from_user(&new_tv, tv, sizeof(*tv)))
+ if (copy_from_user(&user_tv, tv, sizeof(*tv)))
return -EFAULT;
- new_tv.tv_nsec *= NSEC_PER_USEC;
+ new_ts.tv_sec = user_tv.tv_sec;
+ new_ts.tv_nsec = user_tv.tv_usec * NSEC_PER_USEC;
}
if (tz) {
if (copy_from_user(&new_tz, tz, sizeof(*tz)))
return -EFAULT;
}
- return do_sys_settimeofday(tv ? &new_tv : NULL, tz ? &new_tz : NULL);
+ return do_sys_settimeofday(tv ? &new_ts : NULL, tz ? &new_tz : NULL);
}
long pps_offset; /* pps time offset (us) */
diff --git a/mm/bootmem.c b/mm/bootmem.c
index 48f286bb780a..c9ee5f70bb5f 100644
--- a/mm/bootmem.c
+++ b/mm/bootmem.c
@@ -183,7 +183,7 @@ restart_scan:
for (i = preferred; i < eidx; i += incr) {
unsigned long j;
i = find_next_zero_bit(bdata->node_bootmem_map, eidx, i);
- i = (i + incr - 1) & -incr;
+ i = ALIGN(i, incr);
if (test_bit(i, bdata->node_bootmem_map))
continue;
for (j = i + 1; j < i + areasize; ++j) {
@@ -195,7 +195,7 @@ restart_scan:
start = i;
goto found;
fail_block:
- ;
+ i = ALIGN(j, incr);
}
if (preferred > offset) {
diff --git a/mm/slab.c b/mm/slab.c
index bee3dfdf8619..f86bb9620c29 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -1628,7 +1628,13 @@ static inline void *cache_free_debugcheck (kmem_cache_t * cachep, void * objp, v
kfree_debugcheck(objp);
page = virt_to_page(objp);
- BUG_ON(GET_PAGE_CACHE(page) != cachep);
+ if (GET_PAGE_CACHE(page) != cachep) {
+ printk(KERN_ERR "mismatch in kmem_cache_free: expected cache %p, got %p\n",
+ GET_PAGE_CACHE(page),cachep);
+ printk(KERN_ERR "%p is %s.\n", cachep, cachep->name);
+ printk(KERN_ERR "%p is %s.\n", GET_PAGE_CACHE(page), GET_PAGE_CACHE(page)->name);
+ WARN_ON(1);
+ }
slabp = GET_PAGE_SLAB(page);
if (cachep->flags & SLAB_STORE_USER) {
@@ -2482,11 +2488,11 @@ static void *s_start(struct seq_file *m, loff_t *pos)
seq_puts(m, "slabinfo - version: 2.0\n");
#endif
seq_puts(m, "# name <active_objs> <num_objs> <objsize> <objperslab> <pagesperslab>");
- seq_puts(m, " : tunables <batchcount> <limit <sharedfactor>");
+ seq_puts(m, " : tunables <batchcount> <limit> <sharedfactor>");
seq_puts(m, " : slabdata <active_slabs> <num_slabs> <sharedavail>");
#if STATS
seq_puts(m, " : globalstat <listallocs> <maxobjs> <grown> <reaped> <error> <maxfreeable> <freelimit>");
- seq_puts(m, " : cpustat <allochit <allocmiss <freehit <freemiss>");
+ seq_puts(m, " : cpustat <allochit> <allocmiss> <freehit <freemiss>");
#endif
seq_putc(m, '\n');
}
diff --git a/scripts/ver_linux b/scripts/ver_linux
index 26f3084e7db3..0bc7fa3e4843 100644
--- a/scripts/ver_linux
+++ b/scripts/ver_linux
@@ -54,11 +54,14 @@ pppd --version 2>&1| grep version | awk \
isdnctrl 2>&1 | grep version | awk \
'NR==1{print "isdn4k-utils ", $NF}'
+showmount --version 2>&1 | grep nfs-utils | awk \
+'NR==1{print "nfs-utils ", $NF}'
+
ls -l `ldd /bin/sh | awk '/libc/{print $3}'` | sed \
-e 's/\.so$//' | awk -F'[.-]' '{print "Linux C Library " \
$(NF-2)"."$(NF-1)"."$NF}'
-ldd -v > /dev/null 2>&1 && ldd -v || ldd --version |head -1 | awk \
+ldd -v > /dev/null 2>&1 && ldd -v || ldd --version |head -n 1 | awk \
'NR==1{print "Dynamic linker (ldd) ", $NF}'
ls -l /usr/lib/lib{g,stdc}++.so 2>/dev/null | awk -F. \
diff --git a/sound/isa/cmi8330.c b/sound/isa/cmi8330.c
index 226ffd299f3c..f3f3d6b12aba 100644
--- a/sound/isa/cmi8330.c
+++ b/sound/isa/cmi8330.c
@@ -293,7 +293,7 @@ static int __devinit snd_cmi8330_pnp(int dev, struct snd_cmi8330 *acard,
const struct pnp_card_device_id *id)
{
struct pnp_dev *pdev;
- struct pnp_resource_table * cfg = kmalloc(GFP_ATOMIC, sizeof(struct pnp_resource_table));
+ struct pnp_resource_table *cfg = kmalloc(sizeof(*cfg), GFP_ATOMIC);
int err;
acard->cap = pnp_request_card_device(card, id->devs[0].id, NULL);
diff --git a/sound/isa/es18xx.c b/sound/isa/es18xx.c
index b52983f47a0c..5b3b49163071 100644
--- a/sound/isa/es18xx.c
+++ b/sound/isa/es18xx.c
@@ -1966,7 +1966,7 @@ static int __devinit snd_audiodrive_pnp(int dev, struct snd_audiodrive *acard,
const struct pnp_card_device_id *id)
{
struct pnp_dev *pdev;
- struct pnp_resource_table * cfg = kmalloc(GFP_ATOMIC, sizeof(struct pnp_resource_table));
+ struct pnp_resource_table *cfg = kmalloc(sizeof(*cfg), GFP_ATOMIC);
int err;
if (!cfg)
diff --git a/sound/oss/Kconfig b/sound/oss/Kconfig
index 1ae2c778a7ae..2fd75db6ea71 100644
--- a/sound/oss/Kconfig
+++ b/sound/oss/Kconfig
@@ -233,6 +233,10 @@ config SOUND_ICH
Support for integral audio in Intel's I/O Controller Hub (ICH)
chipset, as used on the 810/820/840 motherboards.
+config SOUND_HARMONY
+ tristate "PA Harmony audio driver"
+ depends on GSC_LASI && SOUND
+
config SOUND_RME96XX
tristate "RME Hammerfall (RME96XX) support (EXPERIMENTAL)"
depends on SOUND_PRIME!=n && SOUND && PCI && EXPERIMENTAL
@@ -260,6 +264,10 @@ config SOUND_VWSND
<file:Documentation/sound/oss/vwsnd> for more info on this driver's
capabilities.
+config SOUND_HAL2
+ tristate "SGI HAL2 sound (EXPERIMENTAL)"
+ depends on SGI_IP22 && SOUND && EXPERIMENTAL
+
config SOUND_VRC5477
tristate "NEC Vrc5477 AC97 sound"
depends on SOUND_PRIME!=n && DDB5477 && SOUND
@@ -1126,3 +1134,23 @@ config SOUND_TVMIXER
Support for audio mixer facilities on the BT848 TV frame-grabber
card.
+config SOUND_KAHLUA
+ tristate "XpressAudio Sound Blaster emulation"
+ depends on SOUND_SB
+
+config SOUND_ALI5455
+ tristate "ALi5455 audio support"
+ depends on SOUND_PRIME!=n && PCI
+
+config SOUND_FORTE
+ tristate "ForteMedia FM801 driver"
+ depends on SOUND_PRIME!=n && PCI
+
+config SOUND_RME96XX
+ tristate "RME Hammerfall (RME96XX) support"
+ depends on SOUND_PRIME!=n && PCI
+
+config SOUND_AD1980
+ tristate "AD1980 front/back switch plugin"
+ depends on SOUND_PRIME!=n
+
diff --git a/sound/oss/Makefile b/sound/oss/Makefile
index e96098f7e8b4..b6a41ba629e3 100644
--- a/sound/oss/Makefile
+++ b/sound/oss/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_SOUND_CS4232) += cs4232.o ad1848.o
# Please leave it as is, cause the link order is significant !
+obj-$(CONFIG_SOUND_HAL2) += hal2.o
obj-$(CONFIG_SOUND_AEDSP16) += aedsp16.o
obj-$(CONFIG_SOUND_PSS) += pss.o ad1848.o mpu401.o
obj-$(CONFIG_SOUND_TRIX) += trix.o ad1848.o sb_lib.o uart401.o
@@ -21,6 +22,7 @@ obj-$(CONFIG_SOUND_MSS) += ad1848.o
obj-$(CONFIG_SOUND_OPL3SA2) += opl3sa2.o ad1848.o mpu401.o
obj-$(CONFIG_SOUND_PAS) += pas2.o sb.o sb_lib.o uart401.o
obj-$(CONFIG_SOUND_SB) += sb.o sb_lib.o uart401.o
+obj-$(CONFIG_SOUND_KAHLUA) += kahlua.o
obj-$(CONFIG_SOUND_WAVEFRONT) += wavefront.o
obj-$(CONFIG_SOUND_MAUI) += maui.o mpu401.o
obj-$(CONFIG_SOUND_MPU401) += mpu401.o
@@ -60,10 +62,16 @@ obj-$(CONFIG_SOUND_FUSION) += cs46xx.o ac97_codec.o
obj-$(CONFIG_SOUND_MAESTRO) += maestro.o
obj-$(CONFIG_SOUND_MAESTRO3) += maestro3.o ac97_codec.o
obj-$(CONFIG_SOUND_TRIDENT) += trident.o ac97_codec.o
+obj-$(CONFIG_SOUND_HARMONY) += harmony.o
obj-$(CONFIG_SOUND_EMU10K1) += ac97_codec.o
obj-$(CONFIG_SOUND_RME96XX) += rme96xx.o
obj-$(CONFIG_SOUND_BT878) += btaudio.o
+obj-$(CONFIG_SOUND_ALI5455) += ali5455.o ac97_codec.o
obj-$(CONFIG_SOUND_IT8172) += ite8172.o ac97_codec.o
+obj-$(CONFIG_SOUND_FORTE) += forte.o
+
+obj-$(CONFIG_SOUND_AD1980) += ac97_plugin_ad1980.o
+obj-$(CONFIG_SOUND_WM97XX) += ac97_plugin_wm97xx.o
ifeq ($(CONFIG_MIDI_EMU10K1),y)
obj-$(CONFIG_SOUND_EMU10K1) += sound.o
diff --git a/sound/oss/ac97_plugin_ad1980.c b/sound/oss/ac97_plugin_ad1980.c
index 0ed2bf178c30..2c0738a86ef2 100644
--- a/sound/oss/ac97_plugin_ad1980.c
+++ b/sound/oss/ac97_plugin_ad1980.c
@@ -17,7 +17,7 @@
the provisions above, a recipient may use your version of this
file under either the OSL or the GPL.
- Authors: Arjan van de Ven <arjanv@redhat.com>
+ Authors: Alan Cox <alan@redhat.com>
This is an example codec plugin. This one switches the connections
around to match the setups some vendors use with audio switched to
diff --git a/sound/oss/ad1889.c b/sound/oss/ad1889.c
index 08aa241cd41d..2f9f6db25efc 100644
--- a/sound/oss/ad1889.c
+++ b/sound/oss/ad1889.c
@@ -245,7 +245,6 @@ static ad1889_dev_t *ad1889_alloc_dev(struct pci_dev *pci)
dmabuf->ready = 0;
dmabuf->rate = 44100;
}
-out:
return dev;
err_free_dmabuf:
diff --git a/sound/oss/btaudio.c b/sound/oss/btaudio.c
index 587924cbc06d..22e3b6cfd817 100644
--- a/sound/oss/btaudio.c
+++ b/sound/oss/btaudio.c
@@ -328,8 +328,8 @@ static int btaudio_mixer_ioctl(struct inode *inode, struct file *file,
if (cmd == SOUND_MIXER_INFO) {
mixer_info info;
memset(&info,0,sizeof(info));
- strncpy(info.id,"bt878",sizeof(info.id));
- strncpy(info.name,"Brooktree Bt878 audio",sizeof(info.name));
+ strlcpy(info.id,"bt878",sizeof(info.id));
+ strlcpy(info.name,"Brooktree Bt878 audio",sizeof(info.name));
info.modify_counter = bta->mixcount;
if (copy_to_user((void *)arg, &info, sizeof(info)))
return -EFAULT;
@@ -338,8 +338,8 @@ static int btaudio_mixer_ioctl(struct inode *inode, struct file *file,
if (cmd == SOUND_OLD_MIXER_INFO) {
_old_mixer_info info;
memset(&info,0,sizeof(info));
- strncpy(info.id,"bt878",sizeof(info.id)-1);
- strncpy(info.name,"Brooktree Bt878 audio",sizeof(info.name));
+ strlcpy(info.id,"bt878",sizeof(info.id)-1);
+ strlcpy(info.name,"Brooktree Bt878 audio",sizeof(info.name));
if (copy_to_user((void *)arg, &info, sizeof(info)))
return -EFAULT;
return 0;
diff --git a/sound/oss/dmasound/dmasound_core.c b/sound/oss/dmasound/dmasound_core.c
index c60b2dceaa79..f8b10a89d56c 100644
--- a/sound/oss/dmasound/dmasound_core.c
+++ b/sound/oss/dmasound/dmasound_core.c
@@ -1660,13 +1660,13 @@ static int __init dmasound_setup(char *str)
#ifdef HAS_RECORD
case 5:
if ((ints[5] < 0) || (ints[5] > MAX_CATCH_RADIUS))
- printk("dmasound_setup: illegal catch radius, using default = %d\n", catchRadius);
+ printk("dmasound_setup: invalid catch radius, using default = %d\n", catchRadius);
else
catchRadius = ints[5];
/* fall through */
case 4:
if (ints[4] < MIN_BUFFERS)
- printk("dmasound_setup: illegal number of read buffers, using default = %d\n",
+ printk("dmasound_setup: invalid number of read buffers, using default = %d\n",
numReadBufs);
else
numReadBufs = ints[4];
@@ -1675,21 +1675,21 @@ static int __init dmasound_setup(char *str)
if ((size = ints[3]) < 256) /* check for small buffer specs */
size <<= 10 ;
if (size < MIN_BUFSIZE || size > MAX_BUFSIZE)
- printk("dmasound_setup: illegal read buffer size, using default = %d\n", readBufSize);
+ printk("dmasound_setup: invalid read buffer size, using default = %d\n", readBufSize);
else
readBufSize = size;
/* fall through */
#else
case 3:
if ((ints[3] < 0) || (ints[3] > MAX_CATCH_RADIUS))
- printk("dmasound_setup: illegal catch radius, using default = %d\n", catchRadius);
+ printk("dmasound_setup: invalid catch radius, using default = %d\n", catchRadius);
else
catchRadius = ints[3];
/* fall through */
#endif
case 2:
if (ints[1] < MIN_BUFFERS)
- printk("dmasound_setup: illegal number of buffers, using default = %d\n", numWriteBufs);
+ printk("dmasound_setup: invalid number of buffers, using default = %d\n", numWriteBufs);
else
numWriteBufs = ints[1];
/* fall through */
@@ -1697,13 +1697,13 @@ static int __init dmasound_setup(char *str)
if ((size = ints[2]) < 256) /* check for small buffer specs */
size <<= 10 ;
if (size < MIN_BUFSIZE || size > MAX_BUFSIZE)
- printk("dmasound_setup: illegal write buffer size, using default = %d\n", writeBufSize);
+ printk("dmasound_setup: invalid write buffer size, using default = %d\n", writeBufSize);
else
writeBufSize = size;
case 0:
break;
default:
- printk("dmasound_setup: illegal number of arguments\n");
+ printk("dmasound_setup: invalid number of arguments\n");
return 0;
}
return 1;
diff --git a/sound/oss/emu10k1/8010.h b/sound/oss/emu10k1/8010.h
index 404df2af120c..61c6c42bbc36 100644
--- a/sound/oss/emu10k1/8010.h
+++ b/sound/oss/emu10k1/8010.h
@@ -1,7 +1,7 @@
/*
**********************************************************************
* 8010.h
- * Copyright 1999, 2000 Creative Labs, Inc.
+ * Copyright 1999-2001 Creative Labs, Inc.
*
**********************************************************************
*
@@ -11,6 +11,8 @@
* November 2, 1999 Alan Cox Cleaned of 8bit chars, DOS
* line endings
* December 8, 1999 Jon Taylor Added lots of new register info
+ * May 16, 2001 Daniel Bertrand Added unofficial DBG register info
+ * Oct-Nov 2001 D.B. Added unofficial Audigy registers
*
**********************************************************************
*
@@ -39,6 +41,14 @@
#include <linux/types.h>
+// Driver version:
+#define MAJOR_VER 0
+#define MINOR_VER 20
+#define DRIVER_VERSION "0.20a"
+
+
+// Audigy specify registers are prefixed with 'A_'
+
/************************************************************************************************/
/* PCI function 0 registers, address = <val> + PCIBASE0 */
/************************************************************************************************/
@@ -57,6 +67,11 @@
#define IPR 0x08 /* Global interrupt pending register */
/* Clear pending interrupts by writing a 1 to */
/* the relevant bits and zero to the other bits */
+
+/* The next two interrupts are for the midi port on the Audigy Drive (A_MPU1) */
+#define A_IPR_MIDITRANSBUFEMPTY2 0x10000000 /* MIDI UART transmit buffer empty */
+#define A_IPR_MIDIRECVBUFEMPTY2 0x08000000 /* MIDI UART receive buffer empty */
+
#define IPR_SAMPLERATETRACKER 0x01000000 /* Sample rate tracker lock status change */
#define IPR_FXDSP 0x00800000 /* Enable FX DSP interrupts */
#define IPR_FORCEINT 0x00400000 /* Force Sound Blaster interrupt */
@@ -81,6 +96,10 @@
/* IP is written with CL set, the bit in CLIPL */
/* or CLIPH corresponding to the CIN value */
/* written will be cleared. */
+#define A_IPR_MIDITRANSBUFEMPTY1 IPR_MIDITRANSBUFEMPTY /* MIDI UART transmit buffer empty */
+#define A_IPR_MIDIRECVBUFEMPTY1 IPR_MIDIRECVBUFEMPTY /* MIDI UART receive buffer empty */
+
+
#define INTE 0x0c /* Interrupt enable register */
#define INTE_VIRTUALSB_MASK 0xc0000000 /* Virtual Soundblaster I/O port capture */
@@ -108,6 +127,11 @@
/* behavior and possibly random segfaults and */
/* lockups if enabled. */
+/* The next two interrupts are for the midi port on the Audigy Drive (A_MPU1) */
+#define A_INTE_MIDITXENABLE2 0x00020000 /* Enable MIDI transmit-buffer-empty interrupts */
+#define A_INTE_MIDIRXENABLE2 0x00010000 /* Enable MIDI receive-buffer-empty interrupts */
+
+
#define INTE_SAMPLERATETRACKER 0x00002000 /* Enable sample rate tracker interrupts */
/* NOTE: This bit must always be enabled */
#define INTE_FXDSPENABLE 0x00001000 /* Enable FX DSP interrupts */
@@ -124,6 +148,10 @@
#define INTE_MIDITXENABLE 0x00000002 /* Enable MIDI transmit-buffer-empty interrupts */
#define INTE_MIDIRXENABLE 0x00000001 /* Enable MIDI receive-buffer-empty interrupts */
+/* The next two interrupts are for the midi port on the Audigy (A_MPU2) */
+#define A_INTE_MIDITXENABLE1 INTE_MIDITXENABLE
+#define A_INTE_MIDIRXENABLE1 INTE_MIDIRXENABLE
+
#define WC 0x10 /* Wall Clock register */
#define WC_SAMPLECOUNTER_MASK 0x03FFFFC0 /* Sample periods elapsed since reset */
#define WC_SAMPLECOUNTER 0x14060010
@@ -186,6 +214,8 @@
/* Should be set to 1 when the EMU10K1 is */
/* completely initialized. */
+//For Audigy, MPU port move to 0x70-0x74 ptr register
+
#define MUDATA 0x18 /* MPU401 data register (8 bits) */
#define MUCMD 0x19 /* MPU401 command register (8 bits) */
@@ -197,13 +227,16 @@
#define MUSTAT_IRDYN 0x80 /* 0 = MIDI data or command ACK */
#define MUSTAT_ORDYN 0x40 /* 0 = MUDATA can accept a command or data */
-#define TIMER 0x1a /* Timer terminal count register */
+#define A_IOCFG 0x18 /* GPIO on Audigy card (16bits) */
+#define A_GPINPUT_MASK 0xff00
+#define A_GPOUTPUT_MASK 0x00ff
+
+#define TIMER 0x1a /* Timer terminal count register (16-bit) */
/* NOTE: After the rate is changed, a maximum */
/* of 1024 sample periods should be allowed */
/* before the new rate is guaranteed accurate. */
-#define TIMER_RATE_MASK 0x000003ff /* Timer interrupt rate in sample periods */
+#define TIMER_RATE_MASK 0x03ff /* Timer interrupt rate in sample periods */
/* 0 == 1024 periods, [1..4] are not useful */
-#define TIMER_RATE 0x0a00001a
#define AC97DATA 0x1c /* AC97 register set data register (16 bit) */
@@ -386,6 +419,8 @@
#define TREMFRQ 0x1c /* Tremolo amount and modulation LFO frequency register */
#define TREMFRQ_DEPTH 0x0000ff00 /* Tremolo depth */
/* Signed 2's complement, with +/- 12dB extremes */
+#define TREMFRQ_FREQUENCY 0x000000ff /* Tremolo LFO frequency */
+ /* ??Hz steps, maximum of ?? Hz. */
#define FM2FRQ2 0x1d /* Vibrato amount and vibrato LFO frequency register */
#define FM2FRQ2_DEPTH 0x0000ff00 /* Vibrato LFO vibrato depth */
@@ -426,7 +461,12 @@
#define ADCCR_LCHANENABLE 0x00000008 /* Enables left channel for writing to the host */
/* NOTE: To guarantee phase coherency, both channels */
/* must be disabled prior to enabling both channels. */
+#define A_ADCCR_RCHANENABLE 0x00000020
+#define A_ADCCR_LCHANENABLE 0x00000010
+
+#define A_ADCCR_SAMPLERATE_MASK 0x0000000F /* Audigy sample rate convertor output rate */
#define ADCCR_SAMPLERATE_MASK 0x00000007 /* Sample rate convertor output rate */
+
#define ADCCR_SAMPLERATE_48 0x00000000 /* 48kHz sample rate */
#define ADCCR_SAMPLERATE_44 0x00000001 /* 44.1kHz sample rate */
#define ADCCR_SAMPLERATE_32 0x00000002 /* 32kHz sample rate */
@@ -436,10 +476,16 @@
#define ADCCR_SAMPLERATE_11 0x00000006 /* 11.025kHz sample rate */
#define ADCCR_SAMPLERATE_8 0x00000007 /* 8kHz sample rate */
+#define A_ADCCR_SAMPLERATE_12 0x00000006 /* 12kHz sample rate */
+#define A_ADCCR_SAMPLERATE_11 0x00000007 /* 11.025kHz sample rate */
+#define A_ADCCR_SAMPLERATE_8 0x00000008 /* 8kHz sample rate */
+
#define FXWC 0x43 /* FX output write channels register */
/* When set, each bit enables the writing of the */
- /* corresponding FX output channel into host memory */
-
+ /* corresponding FX output channel (internal registers */
+ /* 0x20-0x3f) into host memory. This mode of recording */
+ /* is 16bit, 48KHz only. All 32 channels can be enabled */
+ /* simultaneously. */
#define TCBS 0x44 /* Tank cache buffer size register */
#define TCBS_MASK 0x00000007 /* Tank cache buffer size field */
#define TCBS_BUFFSIZE_16K 0x00000000
@@ -519,6 +565,13 @@
#define REG53 0x53 /* DO NOT PROGRAM THIS REGISTER!!! MAY DESTROY CHIP */
+#define A_DBG 0x53
+#define A_DBG_SINGLE_STEP 0x00020000 /* Set to zero to start dsp */
+#define A_DBG_ZC 0x40000000 /* zero tram counter */
+#define A_DBG_STEP_ADDR 0x000003ff
+#define A_DBG_SATURATION_OCCURED 0x20000000
+#define A_DBG_SATURATION_ADDR 0x0ffc0000
+
#define SPCS0 0x54 /* SPDIF output Channel Status 0 register */
#define SPCS1 0x55 /* SPDIF output Channel Status 1 register */
@@ -582,10 +635,19 @@
#define SRCS_RATELOCKED 0x01000000 /* Sample rate locked */
#define SRCS_ESTSAMPLERATE 0x0007ffff /* Do not modify this field. */
+
+/* Note that these values can vary +/- by a small amount */
+#define SRCS_SPDIFRATE_44 0x0003acd9
+#define SRCS_SPDIFRATE_48 0x00040000
+#define SRCS_SPDIFRATE_96 0x00080000
+
#define MICIDX 0x63 /* Microphone recording buffer index register */
#define MICIDX_MASK 0x0000ffff /* 16-bit value */
#define MICIDX_IDX 0x10000063
+#define A_ADCIDX 0x63
+#define A_ADCIDX_IDX 0x10000063
+
#define ADCIDX 0x64 /* ADC recording buffer index register */
#define ADCIDX_MASK 0x0000ffff /* 16 bit index field */
#define ADCIDX_IDX 0x10000064
@@ -594,9 +656,50 @@
#define FXIDX_MASK 0x0000ffff /* 16-bit value */
#define FXIDX_IDX 0x10000065
+/* This is the MPU port on the card (via the game port) */
+#define A_MUDATA1 0x70
+#define A_MUCMD1 0x71
+#define A_MUSTAT1 A_MUCMD1
+
+/* This is the MPU port on the Audigy Drive */
+#define A_MUDATA2 0x72
+#define A_MUCMD2 0x73
+#define A_MUSTAT2 A_MUCMD2
+
+/* The next two are the Audigy equivalent of FXWC */
+/* the Audigy can record any output (16bit, 48kHz, up to 64 channel simultaneously) */
+/* Each bit selects a channel for recording */
+#define A_FXWC1 0x74 /* Selects 0x7f-0x60 for FX recording */
+#define A_FXWC2 0x75 /* Selects 0x9f-0x80 for FX recording */
+
+#define A_SPDIF_SAMPLERATE 0x76 /* Set the sample rate of SPDIF output */
+#define A_SPDIF_48000 0x00000080
+#define A_SPDIF_44100 0x00000000
+#define A_SPDIF_96000 0x00000040
+
+#define A_FXRT2 0x7c
+#define A_FXRT_CHANNELE 0x0000003f /* Effects send bus number for channel's effects send E */
+#define A_FXRT_CHANNELF 0x00003f00 /* Effects send bus number for channel's effects send F */
+#define A_FXRT_CHANNELG 0x003f0000 /* Effects send bus number for channel's effects send G */
+#define A_FXRT_CHANNELH 0x3f000000 /* Effects send bus number for channel's effects send H */
+
+#define A_SENDAMOUNTS 0x7d
+#define A_FXSENDAMOUNT_E_MASK 0xff000000
+#define A_FXSENDAMOUNT_F_MASK 0x00ff0000
+#define A_FXSENDAMOUNT_G_MASK 0x0000ff00
+#define A_FXSENDAMOUNT_H_MASK 0x000000ff
+
+/* The send amounts for this one are the same as used with the emu10k1 */
+#define A_FXRT1 0x7e
+#define A_FXRT_CHANNELA 0x0000003f
+#define A_FXRT_CHANNELB 0x00003f00
+#define A_FXRT_CHANNELC 0x003f0000
+#define A_FXRT_CHANNELD 0x3f000000
+
+
/* Each FX general purpose register is 32 bits in length, all bits are used */
#define FXGPREGBASE 0x100 /* FX general purpose registers base */
-
+#define A_FXGPREGBASE 0x400 /* Audigy GPRs, 0x400 to 0x5ff */
/* Tank audio data is logarithmically compressed down to 16 bits before writing to TRAM and is */
/* decompressed back to 20 bits on a read. There are a total of 160 locations, the last 32 */
/* locations are for external TRAM. */
@@ -621,4 +724,14 @@
#define HIWORD_RESULT_MASK 0x000ffc00 /* Instruction result */
#define HIWORD_OPA_MASK 0x000003ff /* Instruction operand A */
+
+/* Audigy Soundcard have a different instruction format */
+#define AUDIGY_CODEBASE 0x600
+#define A_LOWORD_OPY_MASK 0x000007ff
+#define A_LOWORD_OPX_MASK 0x007ff000
+#define A_HIWORD_OPCODE_MASK 0x0f000000
+#define A_HIWORD_RESULT_MASK 0x007ff000
+#define A_HIWORD_OPA_MASK 0x000007ff
+
+
#endif /* _8010_H */
diff --git a/sound/oss/emu10k1/audio.c b/sound/oss/emu10k1/audio.c
index 6d383b866a2f..0c94b8fd6420 100644
--- a/sound/oss/emu10k1/audio.c
+++ b/sound/oss/emu10k1/audio.c
@@ -158,8 +158,8 @@ static ssize_t emu10k1_audio_write(struct file *file, const char *buffer, size_t
spin_unlock_irqrestore(&woinst->lock, flags);
return -ENXIO;
}
-
- if (woinst->format.passthrough) {
+ // This is for emu10k1 revs less than 7, we need to go through tram
+ if (woinst->format.passthrough == 1) {
int r;
woinst->buffer.ossfragshift = PT_BLOCKSIZE_LOG2;
@@ -350,8 +350,9 @@ static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned
case SNDCTL_DSP_GETCAPS:
DPF(2, "SNDCTL_DSP_GETCAPS:\n");
- return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP | DSP_CAP_COPROC, (int *) arg);
-
+ return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME |
+ DSP_CAP_TRIGGER | DSP_CAP_MMAP |
+ DSP_CAP_COPROC| DSP_CAP_MULTI, (int *) arg);
case SNDCTL_DSP_SPEED:
DPF(2, "SNDCTL_DSP_SPEED:\n");
@@ -528,8 +529,8 @@ static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned
else if (file->f_mode & FMODE_WRITE) {
val = AFMT_S16_LE | AFMT_U8;
if (emu10k1_find_control_gpr(&wave_dev->card->mgr,
- wave_dev->card->pt.patch_name,
- wave_dev->card->pt.enable_gpr_name) >= 0)
+ wave_dev->card->pt.patch_name,
+ wave_dev->card->pt.enable_gpr_name) >= 0)
val |= AFMT_AC3;
}
return put_user(val, (int *) arg);
@@ -789,7 +790,7 @@ static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned
cinfo.blocks = 0;
}
- if(wiinst->mmapped)
+ if (wiinst->mmapped)
wiinst->buffer.bytestocopy %= wiinst->buffer.fragment_size;
spin_unlock_irqrestore(&wiinst->lock, flags);
@@ -811,15 +812,17 @@ static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned
spin_lock_irqsave(&woinst->lock, flags);
if (woinst->state & WAVE_STATE_OPEN ||
- (woinst->format.passthrough && wave_dev->card->pt.state)) {
+ ((woinst->format.passthrough == 1) && wave_dev->card->pt.state)) {
int num_fragments;
- if (woinst->format.passthrough) {
+
+ if (woinst->format.passthrough == 1) {
emu10k1_pt_waveout_update(wave_dev);
cinfo.bytes = woinst->total_played;
} else {
emu10k1_waveout_update(woinst);
cinfo.bytes = woinst->total_played;
}
+
cinfo.ptr = woinst->buffer.hw_pos;
num_fragments = cinfo.bytes / woinst->buffer.fragment_size;
cinfo.blocks = num_fragments - woinst->blocks;
@@ -899,7 +902,7 @@ static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned
if (file->f_mode & FMODE_WRITE) {
/* digital pass-through fragment count and size are fixed values */
- if (woinst->state & WAVE_STATE_OPEN || woinst->format.passthrough)
+ if (woinst->state & WAVE_STATE_OPEN || (woinst->format.passthrough == 1))
return -EINVAL; /* too late to change */
woinst->buffer.ossfragshift = val & 0xffff;
@@ -936,19 +939,35 @@ static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned
kfree (buf);
return -EINVAL;
}
+
+ if (buf->command == CMD_WRITE) {
+
#ifdef DBGEMU
- if ( (buf->offs < 0) || (buf->offs + buf->len > 0x800) || (buf->len > 1000)) {
+ if ((buf->offs < 0) || (buf->offs + buf->len > 0xe00) || (buf->len > 1000)) {
#else
- if ( ((buf->offs < 0x100 ) || (buf->offs + buf->len > 0x800) || (buf->len > 1000))
- && !( ( buf->offs == DBG) && (buf->len ==1) )){
-#endif
- kfree(buf);
- return -EINVAL;
- }
+ if (((buf->offs < 0x100) || (buf->offs + buf->len > (wave_dev->card->is_audigy ? 0xe00 : 0x800)) || (buf->len > 1000)
+ ) && !(
+ //any register allowed raw access to users goes here:
+ (buf->offs == DBG ||
+ buf->offs == A_DBG)
+ && (buf->len == 1))) {
+#endif
+ kfree(buf);
+ return -EINVAL;
+ }
+ } else {
+ if ((buf->offs < 0) || (buf->offs + buf->len > 0xe00) || (buf->len > 1000)) {
+ kfree(buf);
+ return -EINVAL;
+ }
+ }
+
+ if (((unsigned)buf->flags) > 0x3f)
+ buf->flags = 0;
if (buf->command == CMD_READ) {
for (i = 0; i < buf->len; i++)
- ((u32 *) buf->data)[i] = sblive_readptr(wave_dev->card, buf->offs + i, 0);
+ ((u32 *) buf->data)[i] = sblive_readptr(wave_dev->card, buf->offs + i, buf->flags);
if (copy_to_user((copr_buffer *) arg, buf, sizeof(copr_buffer))) {
kfree(buf);
@@ -956,7 +975,7 @@ static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned
}
} else {
for (i = 0; i < buf->len; i++)
- sblive_writeptr(wave_dev->card, buf->offs + i, 0, ((u32 *) buf->data)[i]);
+ sblive_writeptr(wave_dev->card, buf->offs + i, buf->flags, ((u32 *) buf->data)[i]);
}
kfree (buf);
@@ -1244,8 +1263,9 @@ static int emu10k1_audio_release(struct inode *inode, struct file *file)
struct woinst *woinst = wave_dev->woinst;
spin_lock_irqsave(&woinst->lock, flags);
-
- if (woinst->format.passthrough && card->pt.state != PT_STATE_INACTIVE) {
+ if(woinst->format.passthrough==2)
+ card->pt.state=PT_STATE_PLAYING;
+ if (woinst->format.passthrough && card->pt.state != PT_STATE_INACTIVE){
spin_lock(&card->pt.lock);
emu10k1_pt_stop(card);
spin_unlock(&card->pt.lock);
diff --git a/sound/oss/emu10k1/cardmi.c b/sound/oss/emu10k1/cardmi.c
index a6140b00f884..7a6439457a11 100644
--- a/sound/oss/emu10k1/cardmi.c
+++ b/sound/oss/emu10k1/cardmi.c
@@ -113,7 +113,7 @@ int emu10k1_mpuin_close(struct emu10k1_card *card)
}
/* Disable RX interrupt */
- emu10k1_irq_disable(card, INTE_MIDIRXENABLE);
+ emu10k1_irq_disable(card, card->is_audigy ? A_INTE_MIDIRXENABLE : INTE_MIDIRXENABLE);
emu10k1_mpu_release(card);
@@ -189,7 +189,7 @@ int emu10k1_mpuin_start(struct emu10k1_card *card)
card_mpuin->qhead = 0;
card_mpuin->qtail = 0;
- emu10k1_irq_enable(card, INTE_MIDIRXENABLE);
+ emu10k1_irq_enable(card, card->is_audigy ? A_INTE_MIDIRXENABLE : INTE_MIDIRXENABLE);
}
return 0;
@@ -207,7 +207,7 @@ int emu10k1_mpuin_stop(struct emu10k1_card *card)
DPF(2, "emu10k1_mpuin_stop()\n");
- emu10k1_irq_disable(card, INTE_MIDIRXENABLE);
+ emu10k1_irq_disable(card, card->is_audigy ? A_INTE_MIDIRXENABLE : INTE_MIDIRXENABLE);
card_mpuin->status &= ~FLAGS_MIDM_STARTED; /* clear */
@@ -246,7 +246,7 @@ int emu10k1_mpuin_reset(struct emu10k1_card *card)
DPF(2, "emu10k1_mpuin_reset()\n");
- emu10k1_irq_disable(card, INTE_MIDIRXENABLE);
+ emu10k1_irq_disable(card, card->is_audigy ? A_INTE_MIDIRXENABLE : INTE_MIDIRXENABLE);
while (card_mpuin->firstmidiq) {
midiq = card_mpuin->firstmidiq;
diff --git a/sound/oss/emu10k1/cardmo.c b/sound/oss/emu10k1/cardmo.c
index d11349d26345..5938d31f9e21 100644
--- a/sound/oss/emu10k1/cardmo.c
+++ b/sound/oss/emu10k1/cardmo.c
@@ -72,7 +72,7 @@ int emu10k1_mpuout_close(struct emu10k1_card *card)
DPF(2, "emu10k1_mpuout_close()\n");
- emu10k1_irq_disable(card, INTE_MIDITXENABLE);
+ emu10k1_irq_disable(card, card->is_audigy ? A_INTE_MIDITXENABLE : INTE_MIDITXENABLE);
spin_lock_irqsave(&card_mpuout->lock, flags);
@@ -142,7 +142,7 @@ int emu10k1_mpuout_add_buffer(struct emu10k1_card *card, struct midi_hdr *midihd
card_mpuout->intr = 0;
- emu10k1_irq_enable(card, INTE_MIDITXENABLE);
+ emu10k1_irq_enable(card, card->is_audigy ? A_INTE_MIDITXENABLE : INTE_MIDITXENABLE);
spin_unlock_irqrestore(&card_mpuout->lock, flags);
@@ -206,7 +206,7 @@ void emu10k1_mpuout_bh(unsigned long refdata)
if ((card_mpuout->firstmidiq != NULL) || cByteSent) {
card_mpuout->intr = 0;
- emu10k1_irq_enable(card, INTE_MIDITXENABLE);
+ emu10k1_irq_enable(card, card->is_audigy ? A_INTE_MIDITXENABLE : INTE_MIDITXENABLE);
}
spin_unlock_irqrestore(&card_mpuout->lock, flags);
@@ -221,7 +221,7 @@ int emu10k1_mpuout_irqhandler(struct emu10k1_card *card)
DPF(4, "emu10k1_mpuout_irqhandler\n");
card_mpuout->intr = 1;
- emu10k1_irq_disable(card, INTE_MIDITXENABLE);
+ emu10k1_irq_disable(card, card->is_audigy ? A_INTE_MIDITXENABLE : INTE_MIDITXENABLE);
tasklet_hi_schedule(&card_mpuout->tasklet);
diff --git a/sound/oss/emu10k1/cardwo.c b/sound/oss/emu10k1/cardwo.c
index 57e151a97e62..5cc3afa431ef 100644
--- a/sound/oss/emu10k1/cardwo.c
+++ b/sound/oss/emu10k1/cardwo.c
@@ -85,25 +85,36 @@ static void query_format(struct emu10k1_wavedevice *wave_dev, struct wave_format
break;
}
if (do_passthrough) {
- i = emu10k1_find_control_gpr(&card->mgr, card->pt.patch_name, card->pt.intr_gpr_name);
- j = emu10k1_find_control_gpr(&card->mgr, card->pt.patch_name, card->pt.enable_gpr_name);
/* currently only one waveout instance may use pass-through */
- if (i < 0 || j < 0 || woinst->state != WAVE_STATE_CLOSED ||
+ if (woinst->state != WAVE_STATE_CLOSED ||
card->pt.state != PT_STATE_INACTIVE ||
- (wave_fmt->samplingrate != 48000 && !is_ac3) ||
(wave_fmt->samplingrate != 48000 && !is_ac3)) {
DPF(2, "unable to set pass-through mode\n");
- } else {
- wave_fmt->samplingrate = 48000;
- wave_fmt->channels = 2;
- wave_fmt->passthrough = 1;
- card->pt.intr_gpr = i;
- card->pt.enable_gpr = j;
- card->pt.state = PT_STATE_INACTIVE;
- card->pt.pos_gpr = emu10k1_find_control_gpr(&card->mgr, card->pt.patch_name, card->pt.pos_gpr_name);
- DPD(2, "is_ac3 is %d\n", is_ac3);
- card->pt.ac3data = is_ac3;
- wave_fmt->bitsperchannel = 16;
+ } else if (USE_PT_METHOD1) {
+ i = emu10k1_find_control_gpr(&card->mgr, card->pt.patch_name, card->pt.intr_gpr_name);
+ j = emu10k1_find_control_gpr(&card->mgr, card->pt.patch_name, card->pt.enable_gpr_name);
+ if (i < 0 || j < 0)
+ DPF(2, "unable to set pass-through mode\n");
+ else {
+ wave_fmt->samplingrate = 48000;
+ wave_fmt->channels = 2;
+ card->pt.pos_gpr = emu10k1_find_control_gpr(&card->mgr, card->pt.patch_name,
+ card->pt.pos_gpr_name);
+ wave_fmt->passthrough = 1;
+ card->pt.intr_gpr = i;
+ card->pt.enable_gpr = j;
+ card->pt.state = PT_STATE_INACTIVE;
+
+ DPD(2, "is_ac3 is %d\n", is_ac3);
+ card->pt.ac3data = is_ac3;
+ wave_fmt->bitsperchannel = 16;
+ }
+ }else{
+ DPF(2, "Using Passthrough Method 2\n");
+ card->pt.enable_gpr = emu10k1_find_control_gpr(&card->mgr, card->pt.patch_name,
+ card->pt.enable_gpr_name);
+ wave_fmt->passthrough = 2;
+ wave_fmt->bitsperchannel = 16;
}
}
@@ -149,33 +160,37 @@ static int get_voice(struct emu10k1_card *card, struct woinst *woinst, unsigned
voice->endloop = voice->startloop + woinst->buffer.size / woinst->format.bytespervoicesample;
voice->start = voice->startloop;
- if (voice->flags & VOICE_FLAGS_STEREO) {
- voice->params[0].send_a = card->waveout.send_a[1];
- voice->params[0].send_b = card->waveout.send_b[1];
- voice->params[0].send_c = card->waveout.send_c[1];
- voice->params[0].send_d = card->waveout.send_d[1];
-
- if (woinst->device)
- voice->params[0].send_routing = 0x7654;
- else
- voice->params[0].send_routing = card->waveout.send_routing[1];
-
- voice->params[0].volume_target = 0xffff;
- voice->params[0].initial_fc = 0xff;
- voice->params[0].initial_attn = 0x00;
- voice->params[0].byampl_env_sustain = 0x7f;
- voice->params[0].byampl_env_decay = 0x7f;
-
- voice->params[1].send_a = card->waveout.send_a[2];
- voice->params[1].send_b = card->waveout.send_b[2];
- voice->params[1].send_c = card->waveout.send_c[2];
- voice->params[1].send_d = card->waveout.send_d[2];
-
- if (woinst->device)
- voice->params[1].send_routing = 0x7654;
- else
- voice->params[1].send_routing = card->waveout.send_routing[2];
+
+ voice->params[0].volume_target = 0xffff;
+ voice->params[0].initial_fc = 0xff;
+ voice->params[0].initial_attn = 0x00;
+ voice->params[0].byampl_env_sustain = 0x7f;
+ voice->params[0].byampl_env_decay = 0x7f;
+
+ if (voice->flags & VOICE_FLAGS_STEREO) {
+ if (woinst->format.passthrough == 2) {
+ voice->params[0].send_routing = voice->params[1].send_routing = card->waveout.send_routing[ROUTE_PT];
+ voice->params[0].send_routing2 = voice->params[1].send_routing2 = card->waveout.send_routing2[ROUTE_PT];
+ voice->params[0].send_dcba = 0xff;
+ voice->params[1].send_dcba = 0xff00;
+ voice->params[0].send_hgfe = voice->params[1].send_hgfe=0;
+ } else {
+ voice->params[0].send_dcba = card->waveout.send_dcba[SEND_LEFT];
+ voice->params[0].send_hgfe = card->waveout.send_hgfe[SEND_LEFT];
+ voice->params[1].send_dcba = card->waveout.send_dcba[SEND_RIGHT];
+ voice->params[1].send_hgfe = card->waveout.send_hgfe[SEND_RIGHT];
+
+ if (woinst->device) {
+ // /dev/dps1
+ voice->params[0].send_routing = voice->params[1].send_routing = card->waveout.send_routing[ROUTE_PCM1];
+ voice->params[0].send_routing2 = voice->params[1].send_routing2 = card->waveout.send_routing2[ROUTE_PCM1];
+ } else {
+ voice->params[0].send_routing = voice->params[1].send_routing = card->waveout.send_routing[ROUTE_PCM];
+ voice->params[0].send_routing2 = voice->params[1].send_routing2 = card->waveout.send_routing2[ROUTE_PCM];
+ }
+ }
+
voice->params[1].volume_target = 0xffff;
voice->params[1].initial_fc = 0xff;
voice->params[1].initial_attn = 0x00;
@@ -183,30 +198,28 @@ static int get_voice(struct emu10k1_card *card, struct woinst *woinst, unsigned
voice->params[1].byampl_env_decay = 0x7f;
} else {
if (woinst->num_voices > 1) {
- voice->params[0].send_a = 0xff;
- voice->params[0].send_b = 0;
- voice->params[0].send_c = 0;
- voice->params[0].send_d = 0;
-
- voice->params[0].send_routing =
- 0xfff0 + card->mchannel_fx + voicenum;
+ // Multichannel pcm
+ voice->params[0].send_dcba=0xff;
+ voice->params[0].send_hgfe=0;
+ if (card->is_audigy) {
+ voice->params[0].send_routing = 0x3f3f3f00 + card->mchannel_fx + voicenum;
+ voice->params[0].send_routing2 = 0x3f3f3f3f;
+ } else {
+ voice->params[0].send_routing = 0xfff0 + card->mchannel_fx + voicenum;
+ }
+
} else {
- voice->params[0].send_a = card->waveout.send_a[0];
- voice->params[0].send_b = card->waveout.send_b[0];
- voice->params[0].send_c = card->waveout.send_c[0];
- voice->params[0].send_d = card->waveout.send_d[0];
-
- if (woinst->device)
- voice->params[0].send_routing = 0x7654;
- else
- voice->params[0].send_routing = card->waveout.send_routing[0];
- }
-
- voice->params[0].volume_target = 0xffff;
- voice->params[0].initial_fc = 0xff;
- voice->params[0].initial_attn = 0x00;
- voice->params[0].byampl_env_sustain = 0x7f;
- voice->params[0].byampl_env_decay = 0x7f;
+ voice->params[0].send_dcba = card->waveout.send_dcba[SEND_MONO];
+ voice->params[0].send_hgfe = card->waveout.send_hgfe[SEND_MONO];
+
+ if (woinst->device) {
+ voice->params[0].send_routing = card->waveout.send_routing[ROUTE_PCM1];
+ voice->params[0].send_routing2 = card->waveout.send_routing2[ROUTE_PCM1];
+ } else {
+ voice->params[0].send_routing = card->waveout.send_routing[ROUTE_PCM];
+ voice->params[0].send_routing2 = card->waveout.send_routing2[ROUTE_PCM];
+ }
+ }
}
DPD(2, "voice: startloop=%#x, endloop=%#x\n", voice->startloop, voice->endloop);
@@ -280,9 +293,16 @@ void emu10k1_waveout_start(struct emu10k1_wavedevice *wave_dev)
{
struct emu10k1_card *card = wave_dev->card;
struct woinst *woinst = wave_dev->woinst;
+ struct pt_data *pt = &card->pt;
DPF(2, "emu10k1_waveout_start()\n");
+ if (woinst->format.passthrough == 2) {
+ emu10k1_pt_setup(wave_dev);
+ sblive_writeptr(card, (card->is_audigy ? A_GPR_BASE : GPR_BASE) + pt->enable_gpr, 0, 1);
+ pt->state = PT_STATE_PLAYING;
+ }
+
/* Actual start */
emu10k1_voices_start(woinst->voice, woinst->num_voices, woinst->total_played);
diff --git a/sound/oss/emu10k1/efxmgr.c b/sound/oss/emu10k1/efxmgr.c
index dba905499ffa..74e27b711f6f 100644
--- a/sound/oss/emu10k1/efxmgr.c
+++ b/sound/oss/emu10k1/efxmgr.c
@@ -80,15 +80,20 @@ void emu10k1_set_control_gpr(struct emu10k1_card *card, int addr, s32 val, int f
if (addr < 0 || addr >= NUM_GPRS)
return;
- if (flag)
- val += sblive_readptr(card, GPR_BASE + addr, 0);
-
- if (val > mgr->gpr[addr].max)
- val = mgr->gpr[addr].max;
- else if (val < mgr->gpr[addr].min)
- val = mgr->gpr[addr].min;
-
- sblive_writeptr(card, GPR_BASE + addr, 0, val);
+ //fixme: once patch manager is up, remember to fix this for the audigy
+ if (card->is_audigy) {
+ sblive_writeptr(card, A_GPR_BASE + addr, 0, val);
+ } else {
+ if (flag)
+ val += sblive_readptr(card, GPR_BASE + addr, 0);
+ if (val > mgr->gpr[addr].max)
+ val = mgr->gpr[addr].max;
+ else if (val < mgr->gpr[addr].min)
+ val = mgr->gpr[addr].min;
+ sblive_writeptr(card, GPR_BASE + addr, 0, val);
+ }
+
+
}
//TODO: make this configurable:
diff --git a/sound/oss/emu10k1/efxmgr.h b/sound/oss/emu10k1/efxmgr.h
index 59abc8af7754..ef48e5c70d1f 100644
--- a/sound/oss/emu10k1/efxmgr.h
+++ b/sound/oss/emu10k1/efxmgr.h
@@ -32,16 +32,30 @@
#ifndef _EFXMGR_H
#define _EFXMGR_H
-#define WRITE_EFX(a, b, c) sblive_writeptr((a), MICROCODEBASE + (b), 0, (c))
+struct emu_efx_info_t{
+ int opcode_shift;
+ int high_operand_shift;
+ int instruction_start;
+ int gpr_base;
+ int output_base;
+};
+
+
+#define WRITE_EFX(a, b, c) sblive_writeptr((a), emu_efx_info[card->is_audigy].instruction_start + (b), 0, (c))
#define OP(op, z, w, x, y) \
- do { WRITE_EFX(card, (pc) * 2, ((x) << 10) | (y)); \
- WRITE_EFX(card, (pc) * 2 + 1, ((op) << 20) | ((z) << 10) | (w)); \
+ do { WRITE_EFX(card, (pc) * 2, ((x) << emu_efx_info[card->is_audigy].high_operand_shift) | (y)); \
+ WRITE_EFX(card, (pc) * 2 + 1, ((op) << emu_efx_info[card->is_audigy].opcode_shift ) | ((z) << emu_efx_info[card->is_audigy].high_operand_shift) | (w)); \
++pc; } while (0)
#define NUM_INPUTS 0x20
#define NUM_OUTPUTS 0x20
#define NUM_GPRS 0x100
+
+#define A_NUM_INPUTS 0x60
+#define A_NUM_OUTPUTS 0x60 //fixme: this may or may not be true
+#define A_NUM_GPRS 0x200
+
#define GPR_NAME_SIZE 32
#define PATCH_NAME_SIZE 32
@@ -98,6 +112,9 @@ enum {
#define GPR_BASE 0x100
#define OUTPUT_BASE 0x20
+#define A_GPR_BASE 0x400
+#define A_OUTPUT_BASE 0x60
+
#define MAX_PATCHES_PAGES 32
struct patch_manager {
diff --git a/sound/oss/emu10k1/hwaccess.c b/sound/oss/emu10k1/hwaccess.c
index 04f6a9a43cf1..698c35414ecb 100644
--- a/sound/oss/emu10k1/hwaccess.c
+++ b/sound/oss/emu10k1/hwaccess.c
@@ -160,6 +160,24 @@ void emu10k1_writefn0(struct emu10k1_card *card, u32 reg, u32 data)
return;
}
+void emu10k1_writefn0_2(struct emu10k1_card *card, u32 reg, u32 data, int size)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&card->lock, flags);
+
+ if (size == 32)
+ outl(data, card->iobase + (reg & 0x1F));
+ else if (size == 16)
+ outw(data, card->iobase + (reg & 0x1F));
+ else
+ outb(data, card->iobase + (reg & 0x1F));
+
+ spin_unlock_irqrestore(&card->lock, flags);
+
+ return;
+}
+
u32 emu10k1_readfn0(struct emu10k1_card * card, u32 reg)
{
u32 val;
@@ -200,12 +218,13 @@ void emu10k1_timer_set(struct emu10k1_card * card, u16 data)
* write/read Emu10k1 pointer-offset register set, accessed through *
* the PTR and DATA registers *
*************************************************************************/
+#define A_PTR_ADDRESS_MASK 0x0fff0000
void sblive_writeptr(struct emu10k1_card *card, u32 reg, u32 channel, u32 data)
{
u32 regptr;
unsigned long flags;
- regptr = ((reg << 16) & PTR_ADDRESS_MASK) | (channel & PTR_CHANNELNUM_MASK);
+ regptr = ((reg << 16) & A_PTR_ADDRESS_MASK) | (channel & PTR_CHANNELNUM_MASK);
if (reg & 0xff000000) {
u32 mask;
@@ -242,7 +261,7 @@ void sblive_writeptr_tag(struct emu10k1_card *card, u32 channel, ...)
spin_lock_irqsave(&card->lock, flags);
while ((reg = va_arg(args, u32)) != TAGLIST_END) {
u32 data = va_arg(args, u32);
- u32 regptr = (((reg << 16) & PTR_ADDRESS_MASK)
+ u32 regptr = (((reg << 16) & A_PTR_ADDRESS_MASK)
| (channel & PTR_CHANNELNUM_MASK));
outl(regptr, card->iobase + PTR);
if (reg & 0xff000000) {
@@ -267,7 +286,7 @@ u32 sblive_readptr(struct emu10k1_card * card, u32 reg, u32 channel)
u32 regptr, val;
unsigned long flags;
- regptr = ((reg << 16) & PTR_ADDRESS_MASK) | (channel & PTR_CHANNELNUM_MASK);
+ regptr = ((reg << 16) & A_PTR_ADDRESS_MASK) | (channel & PTR_CHANNELNUM_MASK);
if (reg & 0xff000000) {
u32 mask;
@@ -389,7 +408,7 @@ void emu10k1_ac97_write(struct ac97_codec *codec, u8 reg, u16 value)
outb(reg, card->iobase + AC97ADDRESS);
outw(value, card->iobase + AC97DATA);
-
+ outb( AC97_EXTENDED_ID, card->iobase + AC97ADDRESS);
spin_unlock_irqrestore(&card->lock, flags);
}
@@ -402,15 +421,23 @@ int emu10k1_mpu_write_data(struct emu10k1_card *card, u8 data)
unsigned long flags;
int ret;
- spin_lock_irqsave(&card->lock, flags);
+ if (card->is_audigy) {
+ if ((sblive_readptr(card, A_MUSTAT,0) & MUSTAT_ORDYN) == 0) {
+ sblive_writeptr(card, A_MUDATA, 0, data);
+ ret = 0;
+ } else
+ ret = -1;
+ } else {
+ spin_lock_irqsave(&card->lock, flags);
- if ((inb(card->iobase + MUSTAT) & MUSTAT_ORDYN) == 0) {
- outb(data, card->iobase + MUDATA);
- ret = 0;
- } else
- ret = -1;
+ if ((inb(card->iobase + MUSTAT) & MUSTAT_ORDYN) == 0) {
+ outb(data, card->iobase + MUDATA);
+ ret = 0;
+ } else
+ ret = -1;
- spin_unlock_irqrestore(&card->lock, flags);
+ spin_unlock_irqrestore(&card->lock, flags);
+ }
return ret;
}
@@ -420,15 +447,23 @@ int emu10k1_mpu_read_data(struct emu10k1_card *card, u8 * data)
unsigned long flags;
int ret;
- spin_lock_irqsave(&card->lock, flags);
+ if (card->is_audigy) {
+ if ((sblive_readptr(card, A_MUSTAT,0) & MUSTAT_IRDYN) == 0) {
+ *data = sblive_readptr(card, A_MUDATA,0);
+ ret = 0;
+ } else
+ ret = -1;
+ } else {
+ spin_lock_irqsave(&card->lock, flags);
- if ((inb(card->iobase + MUSTAT) & MUSTAT_IRDYN) == 0) {
- *data = inb(card->iobase + MUDATA);
- ret = 0;
- } else
- ret = -1;
+ if ((inb(card->iobase + MUSTAT) & MUSTAT_IRDYN) == 0) {
+ *data = inb(card->iobase + MUDATA);
+ ret = 0;
+ } else
+ ret = -1;
- spin_unlock_irqrestore(&card->lock, flags);
+ spin_unlock_irqrestore(&card->lock, flags);
+ }
return ret;
}
@@ -439,37 +474,54 @@ int emu10k1_mpu_reset(struct emu10k1_card *card)
unsigned long flags;
DPF(2, "emu10k1_mpu_reset()\n");
+ if (card->is_audigy) {
+ if (card->mpuacqcount == 0) {
+ sblive_writeptr(card, A_MUCMD, 0, MUCMD_RESET);
+ sblive_wcwait(card, 8);
+ sblive_writeptr(card, A_MUCMD, 0, MUCMD_RESET);
+ sblive_wcwait(card, 8);
+ sblive_writeptr(card, A_MUCMD, 0, MUCMD_ENTERUARTMODE);
+ sblive_wcwait(card, 8);
+ status = sblive_readptr(card, A_MUDATA, 0);
+ if (status == 0xfe)
+ return 0;
+ else
+ return -1;
+ }
- if (card->mpuacqcount == 0) {
- spin_lock_irqsave(&card->lock, flags);
- outb(MUCMD_RESET, card->iobase + MUCMD);
- spin_unlock_irqrestore(&card->lock, flags);
+ return 0;
+ } else {
+ if (card->mpuacqcount == 0) {
+ spin_lock_irqsave(&card->lock, flags);
+ outb(MUCMD_RESET, card->iobase + MUCMD);
+ spin_unlock_irqrestore(&card->lock, flags);
- sblive_wcwait(card, 8);
+ sblive_wcwait(card, 8);
- spin_lock_irqsave(&card->lock, flags);
- outb(MUCMD_RESET, card->iobase + MUCMD);
- spin_unlock_irqrestore(&card->lock, flags);
+ spin_lock_irqsave(&card->lock, flags);
+ outb(MUCMD_RESET, card->iobase + MUCMD);
+ spin_unlock_irqrestore(&card->lock, flags);
- sblive_wcwait(card, 8);
+ sblive_wcwait(card, 8);
- spin_lock_irqsave(&card->lock, flags);
- outb(MUCMD_ENTERUARTMODE, card->iobase + MUCMD);
- spin_unlock_irqrestore(&card->lock, flags);
+ spin_lock_irqsave(&card->lock, flags);
+ outb(MUCMD_ENTERUARTMODE, card->iobase + MUCMD);
+ spin_unlock_irqrestore(&card->lock, flags);
- sblive_wcwait(card, 8);
+ sblive_wcwait(card, 8);
- spin_lock_irqsave(&card->lock, flags);
- status = inb(card->iobase + MUDATA);
- spin_unlock_irqrestore(&card->lock, flags);
+ spin_lock_irqsave(&card->lock, flags);
+ status = inb(card->iobase + MUDATA);
+ spin_unlock_irqrestore(&card->lock, flags);
- if (status == 0xfe)
- return 0;
- else
- return -1;
- }
+ if (status == 0xfe)
+ return 0;
+ else
+ return -1;
+ }
- return 0;
+ return 0;
+ }
}
int emu10k1_mpu_acquire(struct emu10k1_card *card)
diff --git a/sound/oss/emu10k1/hwaccess.h b/sound/oss/emu10k1/hwaccess.h
index c3215b87c7d5..eca206e6626a 100644
--- a/sound/oss/emu10k1/hwaccess.h
+++ b/sound/oss/emu10k1/hwaccess.h
@@ -79,13 +79,21 @@ struct memhandle
struct emu10k1_waveout
{
- u16 send_routing[3];
+ u32 send_routing[3];
+ // audigy only:
+ u32 send_routing2[3];
- u8 send_a[3];
- u8 send_b[3];
- u8 send_c[3];
- u8 send_d[3];
+ u32 send_dcba[3];
+ // audigy only:
+ u32 send_hgfe[3];
};
+#define ROUTE_PCM 0
+#define ROUTE_PT 1
+#define ROUTE_PCM1 2
+
+#define SEND_MONO 0
+#define SEND_LEFT 1
+#define SEND_RIGHT 2
struct emu10k1_wavein
{
@@ -129,7 +137,7 @@ struct mixer_private_ioctl {
#define CMD_AC97_BOOST _IOW('D', 20, struct mixer_private_ioctl)
//up this number when breaking compatibility
-#define PRIVATE3_VERSION 1
+#define PRIVATE3_VERSION 2
struct emu10k1_card
{
@@ -181,7 +189,7 @@ struct emu10k1_card
u32 has_toslink; // TOSLink detection
u8 chiprev; /* Chip revision */
-
+ u8 is_audigy;
u8 is_aps;
struct patch_manager mgr;
@@ -211,6 +219,7 @@ extern struct list_head emu10k1_devs;
/* Hardware Abstraction Layer access functions */
void emu10k1_writefn0(struct emu10k1_card *, u32, u32);
+void emu10k1_writefn0_2(struct emu10k1_card *, u32, u32, int);
u32 emu10k1_readfn0(struct emu10k1_card *, u32);
void emu10k1_timer_set(struct emu10k1_card *, u16);
diff --git a/sound/oss/emu10k1/irqmgr.h b/sound/oss/emu10k1/irqmgr.h
index 8f1d2476ae52..7e7c9ca1098c 100644
--- a/sound/oss/emu10k1/irqmgr.h
+++ b/sound/oss/emu10k1/irqmgr.h
@@ -33,15 +33,15 @@
#define _IRQ_H
/* EMU Irq Types */
-#define IRQTYPE_PCIBUSERROR IPR_PCIERROR
-#define IRQTYPE_MIXERBUTTON (IPR_VOLINCR | IPR_VOLDECR | IPR_MUTE)
-#define IRQTYPE_VOICE (IPR_CHANNELLOOP | IPR_CHANNELNUMBERMASK)
-#define IRQTYPE_RECORD (IPR_ADCBUFFULL | IPR_ADCBUFHALFFULL | IPR_MICBUFFULL | IPR_MICBUFHALFFULL | IPR_EFXBUFFULL | IPR_EFXBUFHALFFULL)
-#define IRQTYPE_MPUOUT IPR_MIDITRANSBUFEMPTY
-#define IRQTYPE_MPUIN IPR_MIDIRECVBUFEMPTY
-#define IRQTYPE_TIMER IPR_INTERVALTIMER
-#define IRQTYPE_SPDIF (IPR_GPSPDIFSTATUSCHANGE | IPR_CDROMSTATUSCHANGE)
-#define IRQTYPE_DSP IPR_FXDSP
+#define IRQTYPE_PCIBUSERROR IPR_PCIERROR
+#define IRQTYPE_MIXERBUTTON (IPR_VOLINCR | IPR_VOLDECR | IPR_MUTE)
+#define IRQTYPE_VOICE (IPR_CHANNELLOOP | IPR_CHANNELNUMBERMASK)
+#define IRQTYPE_RECORD (IPR_ADCBUFFULL | IPR_ADCBUFHALFFULL | IPR_MICBUFFULL | IPR_MICBUFHALFFULL | IPR_EFXBUFFULL | IPR_EFXBUFHALFFULL)
+#define IRQTYPE_MPUOUT (IPR_MIDITRANSBUFEMPTY | A_IPR_MIDITRANSBUFEMPTY2)
+#define IRQTYPE_MPUIN (IPR_MIDIRECVBUFEMPTY | A_IPR_MIDIRECVBUFEMPTY2)
+#define IRQTYPE_TIMER IPR_INTERVALTIMER
+#define IRQTYPE_SPDIF (IPR_GPSPDIFSTATUSCHANGE | IPR_CDROMSTATUSCHANGE)
+#define IRQTYPE_DSP IPR_FXDSP
void emu10k1_timer_irqhandler(struct emu10k1_card *);
void emu10k1_dsp_irqhandler(struct emu10k1_card *);
diff --git a/sound/oss/emu10k1/main.c b/sound/oss/emu10k1/main.c
index 707dbe428a85..f6520b8e9d4a 100644
--- a/sound/oss/emu10k1/main.c
+++ b/sound/oss/emu10k1/main.c
@@ -78,10 +78,11 @@
* Cleaned up poll() functions (audio and midi). Don't start input.
* Restrict DMA pages used to 512Mib range.
* New AC97_BOOST mixer ioctl.
- * 0.19 Real fix for kernel with highmem support (cast dma_handle to u32).
+ * 0.19a Added Support for Audigy Cards
+ * Real fix for kernel with highmem support (cast dma_handle to u32).
* Fix recording buffering parameters calculation.
* Use unsigned long for variables in bit ops.
- * 0.20 Fixed recording startup
+ * 0.20a Fixed recording startup
* Fixed timer rate setting (it's a 16-bit register)
*********************************************************************/
@@ -114,7 +115,6 @@
#define SNDCARD_EMU10K1 46
#endif
-#define DRIVER_VERSION "0.20"
/* the emu10k1 _seems_ to only supports 29 bit (512MiB) bit bus master */
#define EMU10K1_DMA_MASK 0x1fffffff /* DMA buffer mask for pci_alloc_consist */
@@ -126,20 +126,27 @@
#ifndef PCI_DEVICE_ID_CREATIVE_EMU10K1
#define PCI_DEVICE_ID_CREATIVE_EMU10K1 0x0002
#endif
+#ifndef PCI_DEVICE_ID_CREATIVE_AUDIGY
+#define PCI_DEVICE_ID_CREATIVE_AUDIGY 0x0004
+#endif
#define EMU_APS_SUBID 0x40011102
enum {
EMU10K1 = 0,
+ AUDIGY,
};
static char *card_names[] __devinitdata = {
"EMU10K1",
+ "Audigy",
};
static struct pci_device_id emu10k1_pci_tbl[] = {
{PCI_VENDOR_ID_CREATIVE, PCI_DEVICE_ID_CREATIVE_EMU10K1,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, EMU10K1},
+ {PCI_VENDOR_ID_CREATIVE, PCI_DEVICE_ID_CREATIVE_AUDIGY,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, AUDIGY},
{0,}
};
@@ -161,6 +168,67 @@ extern irqreturn_t emu10k1_interrupt(int, void *, struct pt_regs *s);
static int __devinit emu10k1_audio_init(struct emu10k1_card *card)
{
+ /* Assign default playback voice parameters */
+ if (card->is_audigy)
+ card->mchannel_fx = 0;
+ else
+ card->mchannel_fx = 8;
+
+
+ if (card->is_audigy) {
+ /* mono voice */
+ card->waveout.send_dcba[SEND_MONO] = 0xffffffff;
+ card->waveout.send_hgfe[SEND_MONO] = 0x0000ffff;
+
+ /* stereo voice */
+ /* left */
+ card->waveout.send_dcba[SEND_LEFT] = 0x00ff00ff;
+ card->waveout.send_hgfe[SEND_LEFT] = 0x00007f7f;
+ /* right */
+ card->waveout.send_dcba[SEND_RIGHT] = 0xff00ff00;
+ card->waveout.send_hgfe[SEND_RIGHT] = 0x00007f7f;
+
+ card->waveout.send_routing[ROUTE_PCM] = 0x03020100; // Regular pcm
+ card->waveout.send_routing2[ROUTE_PCM] = 0x07060504;
+
+ card->waveout.send_routing[ROUTE_PT] = 0x3f3f3d3c; // Passthrough
+ card->waveout.send_routing2[ROUTE_PT] = 0x3f3f3f3f;
+
+ card->waveout.send_routing[ROUTE_PCM1] = 0x03020100; // Spare
+ card->waveout.send_routing2[ROUTE_PCM1] = 0x07060404;
+
+ } else {
+ /* mono voice */
+ card->waveout.send_dcba[SEND_MONO] = 0x0000ffff;
+
+ /* stereo voice */
+ /* left */
+ card->waveout.send_dcba[SEND_LEFT] = 0x000000ff;
+ /* right */
+ card->waveout.send_dcba[SEND_RIGHT] = 0x0000ff00;
+
+ card->waveout.send_routing[ROUTE_PCM] = 0x3210; // pcm
+ card->waveout.send_routing[ROUTE_PT] = 0x3210; // passthrough
+ card->waveout.send_routing[ROUTE_PCM1] = 0x7654; // /dev/dsp1
+ }
+
+ /* Assign default recording parameters */
+ /* FIXME */
+ if (card->is_aps)
+ card->wavein.recsrc = WAVERECORD_FX;
+ else
+ card->wavein.recsrc = WAVERECORD_AC97;
+
+ card->wavein.fxwc = 0x0003;
+ return 0;
+}
+
+static void emu10k1_audio_cleanup(struct emu10k1_card *card)
+{
+}
+
+static int __devinit emu10k1_register_devices(struct emu10k1_card *card)
+{
card->audio_dev = register_sound_dsp(&emu10k1_audio_fops, -1);
if (card->audio_dev < 0) {
printk(KERN_ERR "emu10k1: cannot register first audio device!\n");
@@ -173,56 +241,167 @@ static int __devinit emu10k1_audio_init(struct emu10k1_card *card)
goto err_dev1;
}
- /* Assign default playback voice parameters */
- card->mchannel_fx = 8;
- /* mono voice */
- card->waveout.send_a[0] = 0xff;
- card->waveout.send_b[0] = 0xff;
- card->waveout.send_c[0] = 0x00;
- card->waveout.send_d[0] = 0x00;
- card->waveout.send_routing[0] = 0x3210;
-
- /* stereo voice */
- /* left */
- card->waveout.send_a[1] = 0xff;
- card->waveout.send_b[1] = 0x00;
- card->waveout.send_c[1] = 0x00;
- card->waveout.send_d[1] = 0x00;
- card->waveout.send_routing[1] = 0x3210;
-
- /* right */
- card->waveout.send_a[2] = 0x00;
- card->waveout.send_b[2] = 0xff;
- card->waveout.send_c[2] = 0x00;
- card->waveout.send_d[2] = 0x00;
- card->waveout.send_routing[2] = 0x3210;
+ card->ac97->dev_mixer = register_sound_mixer(&emu10k1_mixer_fops, -1);
+ if (card->ac97->dev_mixer < 0) {
+ printk(KERN_ERR "emu10k1: cannot register mixer device\n");
+ goto err_mixer;
+ }
- /* Assign default recording parameters */
- /* FIXME */
- if (card->is_aps)
- card->wavein.recsrc = WAVERECORD_FX;
- else
- card->wavein.recsrc = WAVERECORD_AC97;
+ card->midi_dev = register_sound_midi(&emu10k1_midi_fops, -1);
+ if (card->midi_dev < 0) {
+ printk(KERN_ERR "emu10k1: cannot register midi device!\n");
+ goto err_midi;
+ }
- card->wavein.fxwc = 0x0003;
+#ifdef EMU10K1_SEQUENCER
+ card->seq_dev = sound_alloc_mididev();
+ if (card->seq_dev == -1)
+ printk(KERN_WARNING "emu10k1: unable to register sequencer device!");
+ else {
+ std_midi_synth.midi_dev = card->seq_dev;
+ midi_devs[card->seq_dev] =
+ (struct midi_operations *)
+ kmalloc(sizeof(struct midi_operations), GFP_KERNEL);
+
+ if (midi_devs[card->seq_dev] == NULL) {
+ printk(KERN_ERR "emu10k1: unable to allocate memory!");
+ sound_unload_mididev(card->seq_dev);
+ card->seq_dev = -1;
+ /* return without error */
+ } else {
+ memcpy((char *)midi_devs[card->seq_dev],
+ (char *)&emu10k1_midi_operations,
+ sizeof(struct midi_operations));
+ midi_devs[card->seq_dev]->devc = card;
+ sequencer_init();
+ card->seq_mididev = NULL;
+ }
+ }
+#endif
return 0;
+err_midi:
+ unregister_sound_mixer(card->ac97->dev_mixer);
+err_mixer:
+ unregister_sound_dsp(card->audio_dev);
err_dev1:
unregister_sound_dsp(card->audio_dev);
err_dev:
return -ENODEV;
}
-static void emu10k1_audio_cleanup(struct emu10k1_card *card)
+static void emu10k1_unregister_devices(struct emu10k1_card *card)
{
+#ifdef EMU10K1_SEQUENCER
+ if (card->seq_dev > -1) {
+ kfree(midi_devs[card->seq_dev]);
+ midi_devs[card->seq_dev] = NULL;
+ sound_unload_mididev(card->seq_dev);
+ card->seq_dev = -1;
+ }
+#endif
+
+ unregister_sound_midi(card->midi_dev);
+ unregister_sound_mixer(card->ac97->dev_mixer);
unregister_sound_dsp(card->audio_dev1);
unregister_sound_dsp(card->audio_dev);
}
-static int __devinit emu10k1_mixer_init(struct emu10k1_card *card)
+int emu10k1_info_proc (char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ struct emu10k1_card *card = data;
+ int len = 0;
+
+ if (card == NULL)
+ return -ENODEV;
+
+ len += sprintf (page + len, "Driver Version : %s\n", DRIVER_VERSION);
+ len += sprintf (page + len, "Card type : %s\n", card->is_aps ? "Aps" : (card->is_audigy ? "Audigy" : "Emu10k1"));
+ len += sprintf (page + len, "Revision : %d\n", card->chiprev);
+ len += sprintf (page + len, "Model : %#06x\n", card->model);
+ len += sprintf (page + len, "IO : %#06lx-%#06lx\n", card->iobase, card->iobase + card->length - 1);
+ len += sprintf (page + len, "IRQ : %d\n\n", card->irq);
+
+ len += sprintf (page + len, "Registered /dev Entries:\n");
+ len += sprintf (page + len, "/dev/dsp%d\n", card->audio_dev / 16);
+ len += sprintf (page + len, "/dev/dsp%d\n", card->audio_dev1 / 16);
+ len += sprintf (page + len, "/dev/mixer%d\n", card->ac97->dev_mixer / 16);
+ len += sprintf (page + len, "/dev/midi%d\n", card->midi_dev / 16);
+
+#ifdef EMU10K1_SEQUENCER
+ len += sprintf (page + len, "/dev/sequencer\n");
+#endif
+
+ return len;
+}
+
+static int __devinit emu10k1_proc_init(struct emu10k1_card *card)
{
- char s[32];
+ char s[48];
+
+ if (!proc_mkdir ("driver/emu10k1", 0)) {
+ printk(KERN_ERR "emu10k1: unable to create proc directory driver/emu10k1\n");
+ goto err_out;
+ }
+
+ sprintf(s, "driver/emu10k1/%s", card->pci_dev->slot_name);
+ if (!proc_mkdir (s, 0)) {
+ printk(KERN_ERR "emu10k1: unable to create proc directory %s\n", s);
+ goto err_emu10k1_proc;
+ }
+
+ sprintf(s, "driver/emu10k1/%s/info", card->pci_dev->slot_name);
+ if (!create_proc_read_entry (s, 0, 0, emu10k1_info_proc, card)) {
+ printk(KERN_ERR "emu10k1: unable to create proc entry %s\n", s);
+ goto err_dev_proc;
+ }
+
+ if (!card->is_aps) {
+ sprintf(s, "driver/emu10k1/%s/ac97", card->pci_dev->slot_name);
+ if (!create_proc_read_entry (s, 0, 0, ac97_read_proc, card->ac97)) {
+ printk(KERN_ERR "emu10k1: unable to create proc entry %s\n", s);
+ goto err_proc_ac97;
+ }
+ }
+
+ return 0;
+
+err_proc_ac97:
+ sprintf(s, "driver/emu10k1/%s/info", card->pci_dev->slot_name);
+ remove_proc_entry(s, NULL);
+
+err_dev_proc:
+ sprintf(s, "driver/emu10k1/%s", card->pci_dev->slot_name);
+ remove_proc_entry(s, NULL);
+
+err_emu10k1_proc:
+ remove_proc_entry("driver/emu10k1", NULL);
+
+err_out:
+ return -EIO;
+}
+
+static void emu10k1_proc_cleanup(struct emu10k1_card *card)
+{
+ char s[48];
+
+ if (!card->is_aps) {
+ sprintf(s, "driver/emu10k1/%s/ac97", card->pci_dev->slot_name);
+ remove_proc_entry(s, NULL);
+ }
+
+ sprintf(s, "driver/emu10k1/%s/info", card->pci_dev->slot_name);
+ remove_proc_entry(s, NULL);
+
+ sprintf(s, "driver/emu10k1/%s", card->pci_dev->slot_name);
+ remove_proc_entry(s, NULL);
+
+ remove_proc_entry("driver/emu10k1", NULL);
+}
+static int __devinit emu10k1_mixer_init(struct emu10k1_card *card)
+{
struct ac97_codec *codec = ac97_alloc_codec();
if(codec == NULL)
@@ -231,15 +410,6 @@ static int __devinit emu10k1_mixer_init(struct emu10k1_card *card)
return -EIO;
}
card->ac97 = codec;
-
-#warning "Initialisation order race. Must register after usable"
-
- card->ac97->dev_mixer = register_sound_mixer(&emu10k1_mixer_fops, -1);
- if (card->ac97->dev_mixer < 0) {
- printk(KERN_ERR "emu10k1: cannot register mixer device\n");
- goto err_codec;
- }
-
card->ac97->private_data = card;
if (!card->is_aps) {
@@ -261,23 +431,6 @@ static int __devinit emu10k1_mixer_init(struct emu10k1_card *card)
// Force 5bit:
//card->ac97->bit_resolution=5;
- if (!proc_mkdir ("driver/emu10k1", 0)) {
- printk(KERN_ERR "emu10k1: unable to create proc directory driver/emu10k1\n");
- goto err_out;
- }
-
- sprintf(s, "driver/emu10k1/%s", card->pci_dev->slot_name);
- if (!proc_mkdir (s, 0)) {
- printk(KERN_ERR "emu10k1: unable to create proc directory %s\n", s);
- goto err_emu10k1_proc;
- }
-
- sprintf(s, "driver/emu10k1/%s/ac97", card->pci_dev->slot_name);
- if (!create_proc_read_entry (s, 0, 0, ac97_read_proc, card->ac97)) {
- printk(KERN_ERR "emu10k1: unable to create proc entry %s\n", s);
- goto err_ac97_proc;
- }
-
/* these will store the original values and never be modified */
card->ac97_supported_mixers = card->ac97->supported_mixers;
card->ac97_stereo_mixers = card->ac97->stereo_mixers;
@@ -285,34 +438,13 @@ static int __devinit emu10k1_mixer_init(struct emu10k1_card *card)
return 0;
- err_ac97_proc:
- sprintf(s, "driver/emu10k1/%s", card->pci_dev->slot_name);
- remove_proc_entry(s, NULL);
-
- err_emu10k1_proc:
- remove_proc_entry("driver/emu10k1", NULL);
err_out:
- unregister_sound_mixer (card->ac97->dev_mixer);
- err_codec:
ac97_release_codec(card->ac97);
return -EIO;
}
static void emu10k1_mixer_cleanup(struct emu10k1_card *card)
{
- char s[32];
-
- if (!card->is_aps) {
- sprintf(s, "driver/emu10k1/%s/ac97", card->pci_dev->slot_name);
- remove_proc_entry(s, NULL);
-
- sprintf(s, "driver/emu10k1/%s", card->pci_dev->slot_name);
- remove_proc_entry(s, NULL);
-
- remove_proc_entry("driver/emu10k1", NULL);
- }
-
- unregister_sound_mixer (card->ac97->dev_mixer);
ac97_release_codec(card->ac97);
}
@@ -320,13 +452,6 @@ static int __devinit emu10k1_midi_init(struct emu10k1_card *card)
{
int ret;
- card->midi_dev = register_sound_midi(&emu10k1_midi_fops, -1);
- if (card->midi_dev < 0) {
- printk(KERN_ERR "emu10k1: cannot register midi device!\n");
- return -ENODEV;
- }
-
-
card->mpuout = kmalloc(sizeof(struct emu10k1_mpuout), GFP_KERNEL);
if (card->mpuout == NULL) {
printk(KERN_WARNING "emu10k1: Unable to allocate emu10k1_mpuout: out of memory\n");
@@ -366,31 +491,6 @@ static int __devinit emu10k1_midi_init(struct emu10k1_card *card)
goto err_out3;
}
-#ifdef EMU10K1_SEQUENCER
- card->seq_dev = sound_alloc_mididev();
- if (card->seq_dev == -1)
- printk(KERN_WARNING "emu10k1: unable to register sequencer device!");
- else {
- std_midi_synth.midi_dev = card->seq_dev;
- midi_devs[card->seq_dev] =
- (struct midi_operations *)
- kmalloc(sizeof(struct midi_operations), GFP_KERNEL);
-
- if (midi_devs[card->seq_dev] == NULL) {
- printk(KERN_ERR "emu10k1: unable to allocate memory!");
- sound_unload_mididev(card->seq_dev);
- card->seq_dev = -1;
- return 0;
- } else {
- memcpy((char *)midi_devs[card->seq_dev],
- (char *)&emu10k1_midi_operations,
- sizeof(struct midi_operations));
- midi_devs[card->seq_dev]->devc = card;
- sequencer_init();
- }
- }
- card->seq_mididev = 0;
-#endif
return 0;
err_out3:
@@ -398,7 +498,6 @@ err_out3:
err_out2:
kfree(card->mpuout);
err_out1:
- unregister_sound_midi(card->midi_dev);
return ret;
}
@@ -409,17 +508,6 @@ static void emu10k1_midi_cleanup(struct emu10k1_card *card)
tasklet_kill(&card->mpuin->tasklet);
kfree(card->mpuin);
-
-#ifdef EMU10K1_SEQUENCER
- if (card->seq_dev > -1) {
- kfree(midi_devs[card->seq_dev]);
- midi_devs[card->seq_dev] = NULL;
- sound_unload_mididev(card->seq_dev);
- card->seq_dev = -1;
- }
-#endif
-
- unregister_sound_midi(card->midi_dev);
}
static void __devinit voice_init(struct emu10k1_card *card)
@@ -465,24 +553,25 @@ static int __devinit fx_init(struct emu10k1_card *card)
s32 left, right;
int i;
u32 pc = 0;
- u32 patch_n;
+ u32 patch_n=0;
+ struct emu_efx_info_t emu_efx_info[2]=
+ {{ 20, 10, 0x400, 0x100, 0x20 },
+ { 24, 12, 0x600, 0x400, 0x60 },
+ };
+
for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
mgr->ctrl_gpr[i][0] = -1;
mgr->ctrl_gpr[i][1] = -1;
}
- for (i = 0; i < 512; i++)
- OP(6, 0x40, 0x40, 0x40, 0x40);
- for (i = 0; i < 256; i++)
- sblive_writeptr_tag(card, 0,
- FXGPREGBASE + i, 0,
- TANKMEMADDRREGBASE + i, 0,
- TAGLIST_END);
-
- /* !! The number bellow must equal the number of patches, currently 11 !! */
- mgr->current_pages = (11 + PATCHES_PER_PAGE - 1) / PATCHES_PER_PAGE;
+ if (card->is_audigy)
+ mgr->current_pages = (2 + PATCHES_PER_PAGE - 1) / PATCHES_PER_PAGE;
+ else
+ /* !! The number below must equal the number of patches, currently 11 !! */
+ mgr->current_pages = (11 + PATCHES_PER_PAGE - 1) / PATCHES_PER_PAGE;
+
for (i = 0; i < mgr->current_pages; i++) {
mgr->patch[i] = (void *)__get_free_page(GFP_KERNEL);
if (mgr->patch[i] == NULL) {
@@ -493,215 +582,298 @@ static int __devinit fx_init(struct emu10k1_card *card)
memset(mgr->patch[i], 0, PAGE_SIZE);
}
- pc = 0;
- patch_n = 0;
- //first free GPR = 0x11b
-
- /* FX volume correction and Volume control*/
- INPUT_PATCH_START(patch, "Pcm L vol", 0x0, 0);
- GET_OUTPUT_GPR(patch, 0x100, 0x0);
- GET_CONTROL_GPR(patch, 0x106, "Vol", 0, 0x7fffffff);
- GET_DYNAMIC_GPR(patch, 0x112);
-
- OP(4, 0x112, 0x40, PCM_IN_L, 0x44); //*4
- OP(0, 0x100, 0x040, 0x112, 0x106); //*vol
- INPUT_PATCH_END(patch);
-
+ if (card->is_audigy) {
+ for (i = 0; i < 1024; i++)
+ OP(0xf, 0x0c0, 0x0c0, 0x0cf, 0x0c0);
- INPUT_PATCH_START(patch, "Pcm R vol", 0x1, 0);
- GET_OUTPUT_GPR(patch, 0x101, 0x1);
- GET_CONTROL_GPR(patch, 0x107, "Vol", 0, 0x7fffffff);
- GET_DYNAMIC_GPR(patch, 0x112);
+ for (i = 0; i < 512 ; i++)
+ sblive_writeptr(card, A_GPR_BASE+i,0,0);
- OP(4, 0x112, 0x40, PCM_IN_R, 0x44);
- OP(0, 0x101, 0x040, 0x112, 0x107);
+ pc=0;
- INPUT_PATCH_END(patch);
+ //Pcm input volume
+ OP(0, 0x402, 0x0c0, 0x406, 0x000);
+ OP(0, 0x403, 0x0c0, 0x407, 0x001);
+ //CD-Digital input Volume
+ OP(0, 0x404, 0x0c0, 0x40d, 0x42);
+ OP(0, 0x405, 0x0c0, 0x40f, 0x43);
- // CD-Digital In Volume control
- INPUT_PATCH_START(patch, "CD-Digital Vol L", 0x12, 0);
- GET_OUTPUT_GPR(patch, 0x10c, 0x12);
- GET_CONTROL_GPR(patch, 0x10d, "Vol", 0, 0x7fffffff);
+ // CD + PCM
+ OP(6, 0x400, 0x0c0, 0x402, 0x404);
+ OP(6, 0x401, 0x0c0, 0x403, 0x405);
+
+ // Front Output + Master Volume
+ OP(0, 0x68, 0x0c0, 0x408, 0x400);
+ OP(0, 0x69, 0x0c0, 0x409, 0x401);
- OP(0, 0x10c, 0x040, SPDIF_CD_L, 0x10d);
- INPUT_PATCH_END(patch);
+ // Add-in analog inputs for other speakers
+ OP(6, 0x400, 0x40, 0x400, 0xc0);
+ OP(6, 0x401, 0x41, 0x401, 0xc0);
- INPUT_PATCH_START(patch, "CD-Digital Vol R", 0x13, 0);
- GET_OUTPUT_GPR(patch, 0x10e, 0x13);
- GET_CONTROL_GPR(patch, 0x10f, "Vol", 0, 0x7fffffff);
+ // Digital Front + Master Volume
+ OP(0, 0x60, 0x0c0, 0x408, 0x400);
+ OP(0, 0x61, 0x0c0, 0x409, 0x401);
- OP(0, 0x10e, 0x040, SPDIF_CD_R, 0x10f);
- INPUT_PATCH_END(patch);
+ // Rear Output + Rear Volume
+ OP(0, 0x06e, 0x0c0, 0x419, 0x400);
+ OP(0, 0x06f, 0x0c0, 0x41a, 0x401);
- //Volume Correction for Multi-channel Inputs
- INPUT_PATCH_START(patch, "Multi-Channel Gain", 0x08, 0);
- patch->input=patch->output=0x3F00;
+ // Digital Rear Output + Rear Volume
+ OP(0, 0x066, 0x0c0, 0x419, 0x400);
+ OP(0, 0x067, 0x0c0, 0x41a, 0x401);
- GET_OUTPUT_GPR(patch, 0x113, MULTI_FRONT_L);
- GET_OUTPUT_GPR(patch, 0x114, MULTI_FRONT_R);
- GET_OUTPUT_GPR(patch, 0x115, MULTI_REAR_L);
- GET_OUTPUT_GPR(patch, 0x116, MULTI_REAR_R);
- GET_OUTPUT_GPR(patch, 0x117, MULTI_CENTER);
- GET_OUTPUT_GPR(patch, 0x118, MULTI_LFE);
+ // Audigy Drive, Headphone out
+ OP(6, 0x64, 0x0c0, 0x0c0, 0x400);
+ OP(6, 0x65, 0x0c0, 0x0c0, 0x401);
- OP(4, 0x113, 0x40, MULTI_FRONT_L, 0x44);
- OP(4, 0x114, 0x40, MULTI_FRONT_R, 0x44);
- OP(4, 0x115, 0x40, MULTI_REAR_L, 0x44);
- OP(4, 0x116, 0x40, MULTI_REAR_R, 0x44);
- OP(4, 0x117, 0x40, MULTI_CENTER, 0x44);
- OP(4, 0x118, 0x40, MULTI_LFE, 0x44);
-
- INPUT_PATCH_END(patch);
-
-
- //Routing patch start
- ROUTING_PATCH_START(rpatch, "Routing");
- GET_INPUT_GPR(rpatch, 0x100, 0x0);
- GET_INPUT_GPR(rpatch, 0x101, 0x1);
- GET_INPUT_GPR(rpatch, 0x10c, 0x12);
- GET_INPUT_GPR(rpatch, 0x10e, 0x13);
- GET_INPUT_GPR(rpatch, 0x113, MULTI_FRONT_L);
- GET_INPUT_GPR(rpatch, 0x114, MULTI_FRONT_R);
- GET_INPUT_GPR(rpatch, 0x115, MULTI_REAR_L);
- GET_INPUT_GPR(rpatch, 0x116, MULTI_REAR_R);
- GET_INPUT_GPR(rpatch, 0x117, MULTI_CENTER);
- GET_INPUT_GPR(rpatch, 0x118, MULTI_LFE);
-
- GET_DYNAMIC_GPR(rpatch, 0x102);
- GET_DYNAMIC_GPR(rpatch, 0x103);
+ // ac97 Recording
+ OP(6, 0x76, 0x0c0, 0x0c0, 0x40);
+ OP(6, 0x77, 0x0c0, 0x0c0, 0x41);
+
+ // Center = sub = Left/2 + Right/2
+ OP(0xe, 0x400, 0x401, 0xcd, 0x400);
- GET_OUTPUT_GPR(rpatch, 0x104, 0x8);
- GET_OUTPUT_GPR(rpatch, 0x105, 0x9);
- GET_OUTPUT_GPR(rpatch, 0x10a, 0x2);
- GET_OUTPUT_GPR(rpatch, 0x10b, 0x3);
+ // center/sub Volume (master)
+ OP(0, 0x06a, 0x0c0, 0x408, 0x400);
+ OP(0, 0x06b, 0x0c0, 0x409, 0x400);
+ // Digital center/sub Volume (master)
+ OP(0, 0x062, 0x0c0, 0x408, 0x400);
+ OP(0, 0x063, 0x0c0, 0x409, 0x400);
- /* input buffer */
- OP(6, 0x102, AC97_IN_L, 0x40, 0x40);
- OP(6, 0x103, AC97_IN_R, 0x40, 0x40);
+ ROUTING_PATCH_START(rpatch, "Routing");
+ ROUTING_PATCH_END(rpatch);
+ /* delimiter patch */
+ patch = PATCH(mgr, patch_n);
+ patch->code_size = 0;
- /* Digital In + PCM + MULTI_FRONT-> AC97 out (front speakers)*/
- OP(6, AC97_FRONT_L, 0x100, 0x10c, 0x113);
-
- CONNECT(MULTI_FRONT_L, AC97_FRONT_L);
- CONNECT(PCM_IN_L, AC97_FRONT_L);
- CONNECT(SPDIF_CD_L, AC97_FRONT_L);
-
- OP(6, AC97_FRONT_R, 0x101, 0x10e, 0x114);
+
+ sblive_writeptr(card, 0x53, 0, 0);
+ } else {
+ for (i = 0; i < 512 ; i++)
+ OP(6, 0x40, 0x40, 0x40, 0x40);
- CONNECT(MULTI_FRONT_R, AC97_FRONT_R);
- CONNECT(PCM_IN_R, AC97_FRONT_R);
- CONNECT(SPDIF_CD_R, AC97_FRONT_R);
+ for (i = 0; i < 256; i++)
+ sblive_writeptr_tag(card, 0,
+ FXGPREGBASE + i, 0,
+ TANKMEMADDRREGBASE + i, 0,
+ TAGLIST_END);
- /* Digital In + PCM + AC97 In + PCM1 + MULTI_REAR --> Rear Channel */
- OP(6, 0x104, PCM1_IN_L, 0x100, 0x115);
- OP(6, 0x104, 0x104, 0x10c, 0x102);
+
+ pc = 0;
- CONNECT(MULTI_REAR_L, ANALOG_REAR_L);
- CONNECT(AC97_IN_L, ANALOG_REAR_L);
- CONNECT(PCM_IN_L, ANALOG_REAR_L);
- CONNECT(SPDIF_CD_L, ANALOG_REAR_L);
- CONNECT(PCM1_IN_L, ANALOG_REAR_L);
+ //first free GPR = 0x11b
+
+
+ /* FX volume correction and Volume control*/
+ INPUT_PATCH_START(patch, "Pcm L vol", 0x0, 0);
+ GET_OUTPUT_GPR(patch, 0x100, 0x0);
+ GET_CONTROL_GPR(patch, 0x106, "Vol", 0, 0x7fffffff);
+ GET_DYNAMIC_GPR(patch, 0x112);
- OP(6, 0x105, PCM1_IN_R, 0x101, 0x116);
- OP(6, 0x105, 0x105, 0x10e, 0x103);
+ OP(4, 0x112, 0x40, PCM_IN_L, 0x44); //*4
+ OP(0, 0x100, 0x040, 0x112, 0x106); //*vol
+ INPUT_PATCH_END(patch);
- CONNECT(MULTI_REAR_R, ANALOG_REAR_R);
- CONNECT(AC97_IN_R, ANALOG_REAR_R);
- CONNECT(PCM_IN_R, ANALOG_REAR_R);
- CONNECT(SPDIF_CD_R, ANALOG_REAR_R);
- CONNECT(PCM1_IN_R, ANALOG_REAR_R);
- /* Digital In + PCM + AC97 In + MULTI_FRONT --> Digital out */
- OP(6, 0x10a, 0x100, 0x102, 0x10c);
- OP(6, 0x10a, 0x10a, 0x113, 0x40);
+ INPUT_PATCH_START(patch, "Pcm R vol", 0x1, 0);
+ GET_OUTPUT_GPR(patch, 0x101, 0x1);
+ GET_CONTROL_GPR(patch, 0x107, "Vol", 0, 0x7fffffff);
+ GET_DYNAMIC_GPR(patch, 0x112);
- CONNECT(MULTI_FRONT_L, DIGITAL_OUT_L);
- CONNECT(PCM_IN_L, DIGITAL_OUT_L);
- CONNECT(AC97_IN_L, DIGITAL_OUT_L);
- CONNECT(SPDIF_CD_L, DIGITAL_OUT_L);
+ OP(4, 0x112, 0x40, PCM_IN_R, 0x44);
+ OP(0, 0x101, 0x040, 0x112, 0x107);
- OP(6, 0x10b, 0x101, 0x103, 0x10e);
- OP(6, 0x10b, 0x10b, 0x114, 0x40);
+ INPUT_PATCH_END(patch);
- CONNECT(MULTI_FRONT_R, DIGITAL_OUT_R);
- CONNECT(PCM_IN_R, DIGITAL_OUT_R);
- CONNECT(AC97_IN_R, DIGITAL_OUT_R);
- CONNECT(SPDIF_CD_R, DIGITAL_OUT_R);
- /* AC97 In --> ADC Recording Buffer */
- OP(6, ADC_REC_L, 0x102, 0x40, 0x40);
+ // CD-Digital In Volume control
+ INPUT_PATCH_START(patch, "CD-Digital Vol L", 0x12, 0);
+ GET_OUTPUT_GPR(patch, 0x10c, 0x12);
+ GET_CONTROL_GPR(patch, 0x10d, "Vol", 0, 0x7fffffff);
- CONNECT(AC97_IN_L, ADC_REC_L);
+ OP(0, 0x10c, 0x040, SPDIF_CD_L, 0x10d);
+ INPUT_PATCH_END(patch);
- OP(6, ADC_REC_R, 0x103, 0x40, 0x40);
+ INPUT_PATCH_START(patch, "CD-Digital Vol R", 0x13, 0);
+ GET_OUTPUT_GPR(patch, 0x10e, 0x13);
+ GET_CONTROL_GPR(patch, 0x10f, "Vol", 0, 0x7fffffff);
- CONNECT(AC97_IN_R, ADC_REC_R);
+ OP(0, 0x10e, 0x040, SPDIF_CD_R, 0x10f);
+ INPUT_PATCH_END(patch);
+ //Volume Correction for Multi-channel Inputs
+ INPUT_PATCH_START(patch, "Multi-Channel Gain", 0x08, 0);
+ patch->input=patch->output=0x3F00;
- /* fx12:Analog-Center */
- OP(6, ANALOG_CENTER, 0x117, 0x40, 0x40);
- CONNECT(MULTI_CENTER, ANALOG_CENTER);
+ GET_OUTPUT_GPR(patch, 0x113, MULTI_FRONT_L);
+ GET_OUTPUT_GPR(patch, 0x114, MULTI_FRONT_R);
+ GET_OUTPUT_GPR(patch, 0x115, MULTI_REAR_L);
+ GET_OUTPUT_GPR(patch, 0x116, MULTI_REAR_R);
+ GET_OUTPUT_GPR(patch, 0x117, MULTI_CENTER);
+ GET_OUTPUT_GPR(patch, 0x118, MULTI_LFE);
- /* fx11:Analog-LFE */
- OP(6, ANALOG_LFE, 0x118, 0x40, 0x40);
- CONNECT(MULTI_LFE, ANALOG_LFE);
+ OP(4, 0x113, 0x40, MULTI_FRONT_L, 0x44);
+ OP(4, 0x114, 0x40, MULTI_FRONT_R, 0x44);
+ OP(4, 0x115, 0x40, MULTI_REAR_L, 0x44);
+ OP(4, 0x116, 0x40, MULTI_REAR_R, 0x44);
+ OP(4, 0x117, 0x40, MULTI_CENTER, 0x44);
+ OP(4, 0x118, 0x40, MULTI_LFE, 0x44);
+
+ INPUT_PATCH_END(patch);
- /* fx12:Digital-Center */
- OP(6, DIGITAL_CENTER, 0x117, 0x40, 0x40);
- CONNECT(MULTI_CENTER, DIGITAL_CENTER);
- /* fx11:Analog-LFE */
- OP(6, DIGITAL_LFE, 0x118, 0x40, 0x40);
- CONNECT(MULTI_LFE, DIGITAL_LFE);
+ //Routing patch start
+ ROUTING_PATCH_START(rpatch, "Routing");
+ GET_INPUT_GPR(rpatch, 0x100, 0x0);
+ GET_INPUT_GPR(rpatch, 0x101, 0x1);
+ GET_INPUT_GPR(rpatch, 0x10c, 0x12);
+ GET_INPUT_GPR(rpatch, 0x10e, 0x13);
+ GET_INPUT_GPR(rpatch, 0x113, MULTI_FRONT_L);
+ GET_INPUT_GPR(rpatch, 0x114, MULTI_FRONT_R);
+ GET_INPUT_GPR(rpatch, 0x115, MULTI_REAR_L);
+ GET_INPUT_GPR(rpatch, 0x116, MULTI_REAR_R);
+ GET_INPUT_GPR(rpatch, 0x117, MULTI_CENTER);
+ GET_INPUT_GPR(rpatch, 0x118, MULTI_LFE);
+
+ GET_DYNAMIC_GPR(rpatch, 0x102);
+ GET_DYNAMIC_GPR(rpatch, 0x103);
+
+ GET_OUTPUT_GPR(rpatch, 0x104, 0x8);
+ GET_OUTPUT_GPR(rpatch, 0x105, 0x9);
+ GET_OUTPUT_GPR(rpatch, 0x10a, 0x2);
+ GET_OUTPUT_GPR(rpatch, 0x10b, 0x3);
+
+
+ /* input buffer */
+ OP(6, 0x102, AC97_IN_L, 0x40, 0x40);
+ OP(6, 0x103, AC97_IN_R, 0x40, 0x40);
+
+
+ /* Digital In + PCM + MULTI_FRONT-> AC97 out (front speakers)*/
+ OP(6, AC97_FRONT_L, 0x100, 0x10c, 0x113);
+
+ CONNECT(MULTI_FRONT_L, AC97_FRONT_L);
+ CONNECT(PCM_IN_L, AC97_FRONT_L);
+ CONNECT(SPDIF_CD_L, AC97_FRONT_L);
+
+ OP(6, AC97_FRONT_R, 0x101, 0x10e, 0x114);
+
+ CONNECT(MULTI_FRONT_R, AC97_FRONT_R);
+ CONNECT(PCM_IN_R, AC97_FRONT_R);
+ CONNECT(SPDIF_CD_R, AC97_FRONT_R);
+
+ /* Digital In + PCM + AC97 In + PCM1 + MULTI_REAR --> Rear Channel */
+ OP(6, 0x104, PCM1_IN_L, 0x100, 0x115);
+ OP(6, 0x104, 0x104, 0x10c, 0x102);
+
+ CONNECT(MULTI_REAR_L, ANALOG_REAR_L);
+ CONNECT(AC97_IN_L, ANALOG_REAR_L);
+ CONNECT(PCM_IN_L, ANALOG_REAR_L);
+ CONNECT(SPDIF_CD_L, ANALOG_REAR_L);
+ CONNECT(PCM1_IN_L, ANALOG_REAR_L);
+
+ OP(6, 0x105, PCM1_IN_R, 0x101, 0x116);
+ OP(6, 0x105, 0x105, 0x10e, 0x103);
+
+ CONNECT(MULTI_REAR_R, ANALOG_REAR_R);
+ CONNECT(AC97_IN_R, ANALOG_REAR_R);
+ CONNECT(PCM_IN_R, ANALOG_REAR_R);
+ CONNECT(SPDIF_CD_R, ANALOG_REAR_R);
+ CONNECT(PCM1_IN_R, ANALOG_REAR_R);
+
+ /* Digital In + PCM + AC97 In + MULTI_FRONT --> Digital out */
+ OP(6, 0x10b, 0x100, 0x102, 0x10c);
+ OP(6, 0x10b, 0x10b, 0x113, 0x40);
+
+ CONNECT(MULTI_FRONT_L, DIGITAL_OUT_L);
+ CONNECT(PCM_IN_L, DIGITAL_OUT_L);
+ CONNECT(AC97_IN_L, DIGITAL_OUT_L);
+ CONNECT(SPDIF_CD_L, DIGITAL_OUT_L);
+
+ OP(6, 0x10a, 0x101, 0x103, 0x10e);
+ OP(6, 0x10b, 0x10b, 0x114, 0x40);
+
+ CONNECT(MULTI_FRONT_R, DIGITAL_OUT_R);
+ CONNECT(PCM_IN_R, DIGITAL_OUT_R);
+ CONNECT(AC97_IN_R, DIGITAL_OUT_R);
+ CONNECT(SPDIF_CD_R, DIGITAL_OUT_R);
+
+ /* AC97 In --> ADC Recording Buffer */
+ OP(6, ADC_REC_L, 0x102, 0x40, 0x40);
+
+ CONNECT(AC97_IN_L, ADC_REC_L);
+
+ OP(6, ADC_REC_R, 0x103, 0x40, 0x40);
+
+ CONNECT(AC97_IN_R, ADC_REC_R);
+
+
+ /* fx12:Analog-Center */
+ OP(6, ANALOG_CENTER, 0x117, 0x40, 0x40);
+ CONNECT(MULTI_CENTER, ANALOG_CENTER);
+
+ /* fx11:Analog-LFE */
+ OP(6, ANALOG_LFE, 0x118, 0x40, 0x40);
+ CONNECT(MULTI_LFE, ANALOG_LFE);
+
+ /* fx12:Digital-Center */
+ OP(6, DIGITAL_CENTER, 0x117, 0x40, 0x40);
+ CONNECT(MULTI_CENTER, DIGITAL_CENTER);
+
+ /* fx11:Analog-LFE */
+ OP(6, DIGITAL_LFE, 0x118, 0x40, 0x40);
+ CONNECT(MULTI_LFE, DIGITAL_LFE);
- ROUTING_PATCH_END(rpatch);
+ ROUTING_PATCH_END(rpatch);
- // Rear volume control
- OUTPUT_PATCH_START(patch, "Vol Rear L", 0x8, 0);
- GET_INPUT_GPR(patch, 0x104, 0x8);
- GET_CONTROL_GPR(patch, 0x119, "Vol", 0, 0x7fffffff);
+ // Rear volume control
+ OUTPUT_PATCH_START(patch, "Vol Rear L", 0x8, 0);
+ GET_INPUT_GPR(patch, 0x104, 0x8);
+ GET_CONTROL_GPR(patch, 0x119, "Vol", 0, 0x7fffffff);
- OP(0, ANALOG_REAR_L, 0x040, 0x104, 0x119);
- OUTPUT_PATCH_END(patch);
+ OP(0, ANALOG_REAR_L, 0x040, 0x104, 0x119);
+ OUTPUT_PATCH_END(patch);
+ OUTPUT_PATCH_START(patch, "Vol Rear R", 0x9, 0);
+ GET_INPUT_GPR(patch, 0x105, 0x9);
+ GET_CONTROL_GPR(patch, 0x11a, "Vol", 0, 0x7fffffff);
- OUTPUT_PATCH_START(patch, "Vol Rear R", 0x9, 0);
- GET_INPUT_GPR(patch, 0x105, 0x9);
- GET_CONTROL_GPR(patch, 0x11a, "Vol", 0, 0x7fffffff);
+ OP(0, ANALOG_REAR_R, 0x040, 0x105, 0x11a);
+ OUTPUT_PATCH_END(patch);
- OP(0, ANALOG_REAR_R, 0x040, 0x105, 0x11a);
- OUTPUT_PATCH_END(patch);
+ //Master volume control on front-digital
+ OUTPUT_PATCH_START(patch, "Vol Master L", 0x2, 1);
+ GET_INPUT_GPR(patch, 0x10a, 0x2);
+ GET_CONTROL_GPR(patch, 0x108, "Vol", 0, 0x7fffffff);
- //Master volume control on front-digital
- OUTPUT_PATCH_START(patch, "Vol Master L", 0x2, 1);
- GET_INPUT_GPR(patch, 0x10a, 0x2);
- GET_CONTROL_GPR(patch, 0x108, "Vol", 0, 0x7fffffff);
+ OP(0, DIGITAL_OUT_L, 0x040, 0x10a, 0x108);
+ OUTPUT_PATCH_END(patch);
- OP(0, DIGITAL_OUT_L, 0x040, 0x10a, 0x108);
- OUTPUT_PATCH_END(patch);
+ OUTPUT_PATCH_START(patch, "Vol Master R", 0x3, 1);
+ GET_INPUT_GPR(patch, 0x10b, 0x3);
+ GET_CONTROL_GPR(patch, 0x109, "Vol", 0, 0x7fffffff);
- OUTPUT_PATCH_START(patch, "Vol Master R", 0x3, 1);
- GET_INPUT_GPR(patch, 0x10b, 0x3);
- GET_CONTROL_GPR(patch, 0x109, "Vol", 0, 0x7fffffff);
+ OP(0, DIGITAL_OUT_R, 0x040, 0x10b, 0x109);
+ OUTPUT_PATCH_END(patch);
- OP(0, DIGITAL_OUT_R, 0x040, 0x10b, 0x109);
- OUTPUT_PATCH_END(patch);
+ /* delimiter patch */
+ patch = PATCH(mgr, patch_n);
+ patch->code_size = 0;
- /* delimiter patch */
- patch = PATCH(mgr, patch_n);
- patch->code_size = 0;
-
- sblive_writeptr(card, DBG, 0, 0);
+
+ sblive_writeptr(card, DBG, 0, 0);
+ }
mgr->lock = SPIN_LOCK_UNLOCKED;
+ // Set up Volume controls, try to keep this the same for both Audigy and Live
//Master volume
mgr->ctrl_gpr[SOUND_MIXER_VOLUME][0] = 8;
@@ -749,8 +921,16 @@ static int __devinit fx_init(struct emu10k1_card *card)
emu10k1_set_volume_gpr(card, 0xd, left, VOL_5BIT);
emu10k1_set_volume_gpr(card, 0xf, right, VOL_5BIT);
- //hard wire the ac97's pcm, we'll do that in dsp code instead.
- emu10k1_ac97_write(card->ac97, 0x18, 0x0);
+
+ //hard wire the ac97's pcm, pcm volume is done above using dsp code.
+ if (card->is_audigy)
+ //for Audigy, we mute it and use the philips 6 channel DAC instead
+ emu10k1_ac97_write(card->ac97, 0x18, 0x8000);
+ else
+ //For the Live we hardwire it to full volume
+ emu10k1_ac97_write(card->ac97, 0x18, 0x0);
+
+ //remove it from the ac97_codec's control
card->ac97_supported_mixers &= ~SOUND_MASK_PCM;
card->ac97_stereo_mixers &= ~SOUND_MASK_PCM;
@@ -789,6 +969,13 @@ static int __devinit hw_init(struct emu10k1_card *card)
SOLEH, 0,
TAGLIST_END);
+ if (card->is_audigy) {
+ sblive_writeptr_tag(card,0,
+ 0x5e,0xf00,
+ 0x5f,0x3,
+ TAGLIST_END);
+ }
+
/* Init envelope engine */
for (nCh = 0; nCh < NUM_G; nCh++) {
sblive_writeptr_tag(card, nCh,
@@ -824,6 +1011,21 @@ static int __devinit hw_init(struct emu10k1_card *card)
ENVVAL, 0,
TAGLIST_END);
sblive_writeptr(card, CPF, nCh, 0);
+ /*
+ Audigy FXRT initialization
+ reversed eng'd, may not be accurate.
+ */
+ if (card->is_audigy) {
+ sblive_writeptr_tag(card,nCh,
+ 0x4c,0x0,
+ 0x4d,0x0,
+ 0x4e,0x0,
+ 0x4f,0x0,
+ A_FXRT1, 0x3f3f3f3f,
+ A_FXRT2, 0x3f3f3f3f,
+ A_SENDAMOUNTS, 0,
+ TAGLIST_END);
+ }
}
@@ -858,6 +1060,25 @@ static int __devinit hw_init(struct emu10k1_card *card)
TAGLIST_END);
+ if (card->is_audigy && (card->chiprev == 4)) {
+ /* Hacks for Alice3 to work independent of haP16V driver */
+ u32 tmp;
+
+ //Setup SRCMulti_I2S SamplingRate
+ tmp = sblive_readptr(card, A_SPDIF_SAMPLERATE, 0);
+ tmp &= 0xfffff1ff;
+ tmp |= (0x2<<9);
+ sblive_writeptr(card, A_SPDIF_SAMPLERATE, 0, tmp);
+
+ /* Setup SRCSel (Enable Spdif,I2S SRCMulti) */
+ emu10k1_writefn0(card, 0x20, 0x600000);
+ emu10k1_writefn0(card, 0x24, 0x14);
+
+ /* Setup SRCMulti Input Audio Enable */
+ emu10k1_writefn0(card, 0x20, 0x6E0000);
+ emu10k1_writefn0(card, 0x24, 0xFF00FF00);
+ }
+
ret = fx_init(card); /* initialize effects engine */
if (ret < 0)
return ret;
@@ -905,16 +1126,30 @@ static int __devinit hw_init(struct emu10k1_card *card)
/* Lock Tank Memory = 1 */
/* Lock Sound Memory = 0 */
/* Auto Mute = 1 */
-
- if (card->model == 0x20 || card->model == 0xc400 ||
- (card->model == 0x21 && card->chiprev < 6))
- emu10k1_writefn0(card, HCFG, HCFG_AUDIOENABLE | HCFG_LOCKTANKCACHE_MASK | HCFG_AUTOMUTE);
- else
- emu10k1_writefn0(card, HCFG, HCFG_AUDIOENABLE | HCFG_LOCKTANKCACHE_MASK | HCFG_AUTOMUTE | HCFG_JOYENABLE);
-
+ if (card->is_audigy) {
+ if (card->chiprev == 4)
+ emu10k1_writefn0(card, HCFG, HCFG_AUDIOENABLE | HCFG_AC3ENABLE_CDSPDIF | HCFG_AC3ENABLE_GPSPDIF | HCFG_AUTOMUTE | HCFG_JOYENABLE);
+ else
+ emu10k1_writefn0(card, HCFG, HCFG_AUDIOENABLE | HCFG_AUTOMUTE | HCFG_JOYENABLE);
+ } else {
+ if (card->model == 0x20 || card->model == 0xc400 ||
+ (card->model == 0x21 && card->chiprev < 6))
+ emu10k1_writefn0(card, HCFG, HCFG_AUDIOENABLE | HCFG_LOCKTANKCACHE_MASK | HCFG_AUTOMUTE);
+ else
+ emu10k1_writefn0(card, HCFG, HCFG_AUDIOENABLE | HCFG_LOCKTANKCACHE_MASK | HCFG_AUTOMUTE | HCFG_JOYENABLE);
+ }
/* Enable Vol_Ctrl irqs */
emu10k1_irq_enable(card, INTE_VOLINCRENABLE | INTE_VOLDECRENABLE | INTE_MUTEENABLE | INTE_FXDSPENABLE);
+ if (card->is_audigy && (card->chiprev == 4)) {
+ /* Unmute Analog now. Set GPO6 to 1 for Apollo.
+ * This has to be done after init ALice3 I2SOut beyond 48KHz.
+ * So, sequence is important. */
+ u32 tmp = emu10k1_readfn0(card, A_IOCFG);
+ tmp |= 0x0040;
+ emu10k1_writefn0(card, A_IOCFG, tmp);
+ }
+
/* FIXME: TOSLink detection */
card->has_toslink = 0;
@@ -1012,6 +1247,8 @@ static void emu10k1_cleanup(struct emu10k1_card *card)
SOLEH, 0,
TAGLIST_END);
+ if (card->is_audigy)
+ sblive_writeptr(card, 0, A_DBG, A_DBG_SINGLE_STEP);
pci_free_consistent(card->pci_dev, card->virtualpagetable.size, card->virtualpagetable.addr, card->virtualpagetable.dma_handle);
pci_free_consistent(card->pci_dev, card->silentpage.size, card->silentpage.addr, card->silentpage.dma_handle);
@@ -1074,6 +1311,9 @@ static int __devinit emu10k1_probe(struct pci_dev *pci_dev, const struct pci_dev
card_names[pci_id->driver_data], card->chiprev, card->model, card->iobase,
card->iobase + card->length - 1, card->irq);
+ if (pci_id->device == PCI_DEVICE_ID_CREATIVE_AUDIGY)
+ card->is_audigy = 1;
+
pci_read_config_dword(pci_dev, PCI_SUBSYSTEM_VENDOR_ID, &subsysvid);
card->is_aps = (subsysvid == EMU_APS_SUBID);
@@ -1083,13 +1323,13 @@ static int __devinit emu10k1_probe(struct pci_dev *pci_dev, const struct pci_dev
init_waitqueue_head(&card->open_wait);
ret = emu10k1_audio_init(card);
- if(ret < 0) {
+ if (ret < 0) {
printk(KERN_ERR "emu10k1: cannot initialize audio devices\n");
goto err_audio;
}
ret = emu10k1_mixer_init(card);
- if(ret < 0) {
+ if (ret < 0) {
printk(KERN_ERR "emu10k1: cannot initialize AC97 codec\n");
goto err_mixer;
}
@@ -1109,10 +1349,28 @@ static int __devinit emu10k1_probe(struct pci_dev *pci_dev, const struct pci_dev
if (card->is_aps)
emu10k1_ecard_init(card);
+ ret = emu10k1_register_devices(card);
+ if (ret < 0)
+ goto err_register;
+
+ /* proc entries must be created after registering devices, as
+ * emu10k1_info_proc prints card->audio_dev &co. */
+ ret = emu10k1_proc_init(card);
+ if (ret < 0) {
+ printk(KERN_ERR "emu10k1: cannot initialize proc directory\n");
+ goto err_proc;
+ }
+
list_add(&card->list, &emu10k1_devs);
return 0;
+err_proc:
+ emu10k1_unregister_devices(card);
+
+err_register:
+ emu10k1_cleanup(card);
+
err_emu10k1_init:
emu10k1_midi_cleanup(card);
@@ -1141,9 +1399,11 @@ static void __devexit emu10k1_remove(struct pci_dev *pci_dev)
list_del(&card->list);
+ emu10k1_unregister_devices(card);
emu10k1_cleanup(card);
emu10k1_midi_cleanup(card);
emu10k1_mixer_cleanup(card);
+ emu10k1_proc_cleanup(card);
emu10k1_audio_cleanup(card);
free_irq(card->irq, card);
release_region(card->iobase, card->length);
diff --git a/sound/oss/emu10k1/midi.h b/sound/oss/emu10k1/midi.h
index 360ca978f415..2459ec929e8d 100644
--- a/sound/oss/emu10k1/midi.h
+++ b/sound/oss/emu10k1/midi.h
@@ -52,4 +52,27 @@ struct emu10k1_mididevice
struct list_head mid_hdrs;
};
+/* uncomment next line to use midi port on Audigy drive */
+//#define USE_AUDIGY_DRIVE_MIDI
+
+#ifdef USE_AUDIGY_DRIVE_MIDI
+#define A_MUDATA A_MUDATA2
+#define A_MUCMD A_MUCMD2
+#define A_MUSTAT A_MUCMD2
+#define A_IPR_MIDITRANSBUFEMPTY A_IPR_MIDITRANSBUFEMPTY2
+#define A_IPR_MIDIRECVBUFEMPTY A_IPR_MIDIRECVBUFEMPTY2
+#define A_INTE_MIDITXENABLE A_INTE_MIDITXENABLE2
+#define A_INTE_MIDIRXENABLE A_INTE_MIDIRXENABLE2
+#else
+#define A_MUDATA A_MUDATA1
+#define A_MUCMD A_MUCMD1
+#define A_MUSTAT A_MUCMD1
+#define A_IPR_MIDITRANSBUFEMPTY A_IPR_MIDITRANSBUFEMPTY1
+#define A_IPR_MIDIRECVBUFEMPTY A_IPR_MIDIRECVBUFEMPTY1
+#define A_INTE_MIDITXENABLE A_INTE_MIDITXENABLE1
+#define A_INTE_MIDIRXENABLE A_INTE_MIDIRXENABLE1
+#endif
+
+
#endif /* _MIDI_H */
+
diff --git a/sound/oss/emu10k1/mixer.c b/sound/oss/emu10k1/mixer.c
index dbade3ca49b1..f26e6b5025ec 100644
--- a/sound/oss/emu10k1/mixer.c
+++ b/sound/oss/emu10k1/mixer.c
@@ -136,7 +136,7 @@ static void set_bass(struct emu10k1_card *card, int l, int r)
r = (r * 40 + 50) / 100;
for (i = 0; i < 5; i++)
- sblive_writeptr(card, GPR_BASE + card->mgr.ctrl_gpr[SOUND_MIXER_BASS][0] + i, 0, bass_table[l][i]);
+ sblive_writeptr(card, (card->is_audigy ? A_GPR_BASE : GPR_BASE) + card->mgr.ctrl_gpr[SOUND_MIXER_BASS][0] + i, 0, bass_table[l][i]);
}
static void set_treble(struct emu10k1_card *card, int l, int r)
@@ -147,7 +147,7 @@ static void set_treble(struct emu10k1_card *card, int l, int r)
r = (r * 40 + 50) / 100;
for (i = 0; i < 5; i++)
- sblive_writeptr(card, GPR_BASE + card->mgr.ctrl_gpr[SOUND_MIXER_TREBLE][0] + i , 0, treble_table[l][i]);
+ sblive_writeptr(card, (card->is_audigy ? A_GPR_BASE : GPR_BASE) + card->mgr.ctrl_gpr[SOUND_MIXER_TREBLE][0] + i , 0, treble_table[l][i]);
}
const char volume_params[SOUND_MIXER_NRDEVICES]= {
@@ -206,22 +206,25 @@ static int emu10k1_private_mixer(struct emu10k1_card *card, unsigned int cmd, un
switch (ctl->cmd) {
#ifdef DBGEMU
case CMD_WRITEFN0:
- emu10k1_writefn0(card, ctl->val[0], ctl->val[1]);
+ emu10k1_writefn0_2(card, ctl->val[0], ctl->val[1], ctl->val[2]);
break;
-
+#endif
case CMD_WRITEPTR:
- if (ctl->val[1] >= 0x40 || ctl->val[0] > 0xff) {
+#ifdef DBGEMU
+ if (ctl->val[1] >= 0x40 || ctl->val[0] >= 0x1000) {
+#else
+ if (ctl->val[1] >= 0x40 || ctl->val[0] >= 0x1000 || ((ctl->val[0] < 0x100 ) &&
+ //Any register allowed raw access goes here:
+ (ctl->val[0] != A_SPDIF_SAMPLERATE) && (ctl->val[0] != A_DBG)
+ )
+ ) {
+#endif
ret = -EINVAL;
break;
}
-
- if ((ctl->val[0] & 0x7ff) > 0x3f)
- ctl->val[1] = 0x00;
-
sblive_writeptr(card, ctl->val[0], ctl->val[1], ctl->val[2]);
-
break;
-#endif
+
case CMD_READFN0:
ctl->val[2] = emu10k1_readfn0(card, ctl->val[0]);
@@ -286,16 +289,13 @@ static int emu10k1_private_mixer(struct emu10k1_card *card, unsigned int cmd, un
case CMD_GETVOICEPARAM:
ctl->val[0] = card->waveout.send_routing[0];
- ctl->val[1] = card->waveout.send_a[0] | card->waveout.send_b[0] << 8 |
- card->waveout.send_c[0] << 16 | card->waveout.send_d[0] << 24;
+ ctl->val[1] = card->waveout.send_dcba[0];
ctl->val[2] = card->waveout.send_routing[1];
- ctl->val[3] = card->waveout.send_a[1] | card->waveout.send_b[1] << 8 |
- card->waveout.send_c[1] << 16 | card->waveout.send_d[1] << 24;
+ ctl->val[3] = card->waveout.send_dcba[1];
ctl->val[4] = card->waveout.send_routing[2];
- ctl->val[5] = card->waveout.send_a[2] | card->waveout.send_b[2] << 8 |
- card->waveout.send_c[2] << 16 | card->waveout.send_d[2] << 24;
+ ctl->val[5] = card->waveout.send_dcba[2];
if (copy_to_user((void *) arg, ctl, sizeof(struct mixer_private_ioctl)))
ret = -EFAULT;
@@ -303,23 +303,14 @@ static int emu10k1_private_mixer(struct emu10k1_card *card, unsigned int cmd, un
break;
case CMD_SETVOICEPARAM:
- card->waveout.send_routing[0] = ctl->val[0] & 0xffff;
- card->waveout.send_a[0] = ctl->val[1] & 0xff;
- card->waveout.send_b[0] = (ctl->val[1] >> 8) & 0xff;
- card->waveout.send_c[0] = (ctl->val[1] >> 16) & 0xff;
- card->waveout.send_d[0] = (ctl->val[1] >> 24) & 0xff;
-
- card->waveout.send_routing[1] = ctl->val[2] & 0xffff;
- card->waveout.send_a[1] = ctl->val[3] & 0xff;
- card->waveout.send_b[1] = (ctl->val[3] >> 8) & 0xff;
- card->waveout.send_c[1] = (ctl->val[3] >> 16) & 0xff;
- card->waveout.send_d[1] = (ctl->val[3] >> 24) & 0xff;
-
- card->waveout.send_routing[2] = ctl->val[4] & 0xffff;
- card->waveout.send_a[2] = ctl->val[5] & 0xff;
- card->waveout.send_b[2] = (ctl->val[5] >> 8) & 0xff;
- card->waveout.send_c[2] = (ctl->val[5] >> 16) & 0xff;
- card->waveout.send_d[2] = (ctl->val[5] >> 24) & 0xff;
+ card->waveout.send_routing[0] = ctl->val[0];
+ card->waveout.send_dcba[0] = ctl->val[1];
+
+ card->waveout.send_routing[1] = ctl->val[2];
+ card->waveout.send_dcba[1] = ctl->val[3];
+
+ card->waveout.send_routing[2] = ctl->val[4];
+ card->waveout.send_dcba[2] = ctl->val[5];
break;
@@ -416,12 +407,16 @@ static int emu10k1_private_mixer(struct emu10k1_card *card, unsigned int cmd, un
break;
case CMD_SETGPOUT:
- if (ctl->val[0] > 2 || ctl->val[1] > 1) {
+ if ( ((ctl->val[0] > 2) && (!card->is_audigy))
+ || (ctl->val[0] > 15) || ctl->val[1] > 1) {
ret= -EINVAL;
break;
}
- emu10k1_writefn0(card, (1 << 24) | (((ctl->val[0]) + 10) << 16) | HCFG, ctl->val[1]);
+ if (card->is_audigy)
+ emu10k1_writefn0(card, (1 << 24) | ((ctl->val[0]) << 16) | A_IOCFG, ctl->val[1]);
+ else
+ emu10k1_writefn0(card, (1 << 24) | (((ctl->val[0]) + 10) << 16) | HCFG, ctl->val[1]);
break;
case CMD_GETGPR2OSS:
@@ -493,13 +488,20 @@ static int emu10k1_private_mixer(struct emu10k1_card *card, unsigned int cmd, un
break;
case CMD_PRIVATE3_VERSION:
- ctl->val[0]=PRIVATE3_VERSION;
+ ctl->val[0] = PRIVATE3_VERSION; //private3 version
+ ctl->val[1] = MAJOR_VER; //major driver version
+ ctl->val[2] = MINOR_VER; //minor driver version
+ ctl->val[3] = card->is_audigy; //1=card is audigy
+
+ if (card->is_audigy)
+ ctl->val[4]=emu10k1_readfn0(card, 0x18);
+
if (copy_to_user((void *) arg, ctl, sizeof(struct mixer_private_ioctl)))
ret = -EFAULT;
break;
case CMD_AC97_BOOST:
- if(ctl->val[0])
+ if (ctl->val[0])
emu10k1_ac97_write(card->ac97, 0x18, 0x0);
else
emu10k1_ac97_write(card->ac97, 0x18, 0x0808);
@@ -556,7 +558,7 @@ static int emu10k1_private_mixer(struct emu10k1_card *card, unsigned int cmd, un
card->tankmem.size = size;
- sblive_writeptr_tag(card, 0, TCB, (u32) card->tankmem.dma_handle, TCBS, size_reg, TAGLIST_END);
+ sblive_writeptr_tag(card, 0, TCB, (u32) card->tankmem.dma_handle, TCBS,(u32) size_reg, TAGLIST_END);
emu10k1_writefn0(card, HCFG_LOCKTANKCACHE, 0);
}
@@ -623,8 +625,13 @@ static int emu10k1_mixer_ioctl(struct inode *inode, struct file *file, unsigned
if (cmd == SOUND_MIXER_INFO) {
mixer_info info;
- strncpy(info.id, card->ac97->name, sizeof(info.id));
- strncpy(info.name, "Creative SBLive - Emu10k1", sizeof(info.name));
+ strlcpy(info.id, card->ac97->name, sizeof(info.id));
+
+ if (card->is_audigy)
+ strlcpy(info.name, "Audigy - Emu10k1", sizeof(info.name));
+ else
+ strlcpy(info.name, "Creative SBLive - Emu10k1", sizeof(info.name));
+
info.modify_counter = card->ac97->modcnt;
if (copy_to_user((void *)arg, &info, sizeof(info)))
diff --git a/sound/oss/emu10k1/passthrough.c b/sound/oss/emu10k1/passthrough.c
index 700e95f1c372..805840eb1360 100644
--- a/sound/oss/emu10k1/passthrough.c
+++ b/sound/oss/emu10k1/passthrough.c
@@ -109,7 +109,7 @@ static int pt_putblock(struct emu10k1_wavedevice *wave_dev, u16 *block, int nonb
return 0;
}
-static int pt_setup(struct emu10k1_wavedevice *wave_dev)
+int emu10k1_pt_setup(struct emu10k1_wavedevice *wave_dev)
{
u32 bits;
struct emu10k1_card *card = wave_dev->card;
@@ -155,7 +155,7 @@ ssize_t emu10k1_pt_write(struct file *file, const char *buffer, size_t count)
pt->prepend_size = 0;
if (pt->buf == NULL)
return -ENOMEM;
- pt_setup(wave_dev);
+ emu10k1_pt_setup(wave_dev);
}
if (pt->prepend_size) {
int needed = PT_BLOCKSIZE - pt->prepend_size;
@@ -208,13 +208,14 @@ void emu10k1_pt_stop(struct emu10k1_card *card)
if (pt->state != PT_STATE_INACTIVE) {
DPF(2, "digital pass-through stopped\n");
- sblive_writeptr(card, GPR_BASE + pt->enable_gpr, 0, 0);
+ sblive_writeptr(card, (card->is_audigy ? A_GPR_BASE : GPR_BASE) + pt->enable_gpr, 0, 0);
for (i = 0; i < 3; i++) {
if (pt->spcs_to_use & (1 << i))
sblive_writeptr(card, SPCS0 + i, 0, pt->old_spcs[i]);
}
pt->state = PT_STATE_INACTIVE;
- kfree(pt->buf);
+ if(pt->buf)
+ kfree(pt->buf);
}
}
diff --git a/sound/oss/emu10k1/passthrough.h b/sound/oss/emu10k1/passthrough.h
index ed7a57439c18..3c7855320b70 100644
--- a/sound/oss/emu10k1/passthrough.h
+++ b/sound/oss/emu10k1/passthrough.h
@@ -63,7 +63,36 @@ struct pt_data
spinlock_t lock;
};
+/*
+ Passthrough can be done in two methods:
+
+ Method 1 : tram
+ In original emu10k1, we couldn't bypass the sample rate converters. Even at 48kHz
+ (the internal sample rate of the emu10k1) the samples would get messed up.
+ To over come this, samples are copied into the tram and a special dsp patch copies
+ the samples out and generates interrupts when a block has finnished playing.
+
+ Method 2 : Interpolator bypass
+
+ Creative fixed the sample rate convert problem in emu10k1 rev 7 and higher
+ (including the emu10k2 (audigy)). This allows us to use the regular, and much simpler
+ playback method.
+
+
+ In both methods, dsp code is used to mux audio and passthrough. This ensures that the spdif
+ doesn't receive audio and pasthrough data at the same time. The spdif flag SPCS_NOTAUDIODATA
+ is set to tell
+
+ */
+
+// emu10k1 revs greater than or equal to 7 can use method2
+
+#define USE_PT_METHOD2 (card->is_audigy)
+#define USE_PT_METHOD1 !USE_PT_METHOD2
+
ssize_t emu10k1_pt_write(struct file *file, const char *buf, size_t count);
+
+int emu10k1_pt_setup(struct emu10k1_wavedevice *wave_dev);
void emu10k1_pt_stop(struct emu10k1_card *card);
void emu10k1_pt_waveout_update(struct emu10k1_wavedevice *wave_dev);
diff --git a/sound/oss/emu10k1/recmgr.c b/sound/oss/emu10k1/recmgr.c
index 2f6265fd00dc..67c3fd04cfdd 100644
--- a/sound/oss/emu10k1/recmgr.c
+++ b/sound/oss/emu10k1/recmgr.c
@@ -74,7 +74,7 @@ void emu10k1_set_record_src(struct emu10k1_card *card, struct wiinst *wiinst)
DPF(2, "recording source: AC97\n");
buffer->sizereg = ADCBS;
buffer->addrreg = ADCBA;
- buffer->idxreg = ADCIDX_IDX;
+ buffer->idxreg = card->is_audigy ? A_ADCIDX_IDX : ADCIDX_IDX;
switch (wiinst->format.samplingrate) {
case 0xBB80:
@@ -95,21 +95,27 @@ void emu10k1_set_record_src(struct emu10k1_card *card, struct wiinst *wiinst)
case 0x3E80:
buffer->adcctl = ADCCR_SAMPLERATE_16;
break;
+ // FIXME: audigy supports 12kHz recording
+ /*
+ case ????:
+ buffer->adcctl = A_ADCCR_SAMPLERATE_12;
+ break;
+ */
case 0x2B11:
- buffer->adcctl = ADCCR_SAMPLERATE_11;
+ buffer->adcctl = card->is_audigy ? A_ADCCR_SAMPLERATE_11 : ADCCR_SAMPLERATE_11;
break;
case 0x1F40:
- buffer->adcctl = ADCCR_SAMPLERATE_8;
+ buffer->adcctl = card->is_audigy ? A_ADCCR_SAMPLERATE_8 : ADCCR_SAMPLERATE_8;
break;
default:
BUG();
break;
}
- buffer->adcctl |= ADCCR_LCHANENABLE;
+ buffer->adcctl |= card->is_audigy ? A_ADCCR_LCHANENABLE : ADCCR_LCHANENABLE;
if (wiinst->format.channels == 2)
- buffer->adcctl |= ADCCR_RCHANENABLE;
+ buffer->adcctl |= card->is_audigy ? A_ADCCR_RCHANENABLE : ADCCR_RCHANENABLE;
break;
diff --git a/sound/oss/emu10k1/voicemgr.c b/sound/oss/emu10k1/voicemgr.c
index 1ed8b087c5c9..c27f4a5f7e59 100644
--- a/sound/oss/emu10k1/voicemgr.c
+++ b/sound/oss/emu10k1/voicemgr.c
@@ -32,6 +32,34 @@
#include "voicemgr.h"
#include "8010.h"
+#define PITCH_48000 0x00004000
+#define PITCH_96000 0x00008000
+#define PITCH_85000 0x00007155
+#define PITCH_80726 0x00006ba2
+#define PITCH_67882 0x00005a82
+#define PITCH_57081 0x00004c1c
+
+u32 emu10k1_select_interprom(struct emu10k1_card *card, struct emu_voice *voice)
+{
+ if(voice->pitch_target==PITCH_48000)
+ return CCCA_INTERPROM_0;
+ else if(voice->pitch_target<PITCH_48000)
+ return CCCA_INTERPROM_1;
+ else if(voice->pitch_target>=PITCH_96000)
+ return CCCA_INTERPROM_0;
+ else if(voice->pitch_target>=PITCH_85000)
+ return CCCA_INTERPROM_6;
+ else if(voice->pitch_target>=PITCH_80726)
+ return CCCA_INTERPROM_5;
+ else if(voice->pitch_target>=PITCH_67882)
+ return CCCA_INTERPROM_4;
+ else if(voice->pitch_target>=PITCH_57081)
+ return CCCA_INTERPROM_3;
+ else
+ return CCCA_INTERPROM_2;
+}
+
+
/**
* emu10k1_voice_alloc_buffer -
*
@@ -216,17 +244,25 @@ void emu10k1_voice_playback_setup(struct emu_voice *voice)
voice->start += start;
for (i = 0; i < (voice->flags & VOICE_FLAGS_STEREO ? 2 : 1); i++) {
- sblive_writeptr(card, FXRT, voice->num + i, voice->params[i].send_routing << 16);
+ if (card->is_audigy) {
+ sblive_writeptr(card, A_FXRT1, voice->num + i, voice->params[i].send_routing);
+ sblive_writeptr(card, A_FXRT2, voice->num + i, voice->params[i].send_routing2);
+ sblive_writeptr(card, A_SENDAMOUNTS, voice->num + i, voice->params[i].send_hgfe);
+ } else {
+ sblive_writeptr(card, FXRT, voice->num + i, voice->params[i].send_routing << 16);
+ }
/* Stop CA */
/* Assumption that PT is already 0 so no harm overwriting */
- sblive_writeptr(card, PTRX, voice->num + i, (voice->params[i].send_a << 8) | voice->params[i].send_b);
+ sblive_writeptr(card, PTRX, voice->num + i, ((voice->params[i].send_dcba & 0xff) << 8)
+ | ((voice->params[i].send_dcba & 0xff00) >> 8));
sblive_writeptr_tag(card, voice->num + i,
/* CSL, ST, CA */
- DSL, voice->endloop | (voice->params[i].send_d << 24),
- PSST, voice->startloop | (voice->params[i].send_c << 24),
- CCCA, (voice->start) | CCCA_INTERPROM_0 | ((voice->flags & VOICE_FLAGS_16BIT) ? 0 : CCCA_8BITSELECT),
+ DSL, voice->endloop | (voice->params[i].send_dcba & 0xff000000),
+ PSST, voice->startloop | ((voice->params[i].send_dcba & 0x00ff0000) << 8),
+ CCCA, (voice->start) | emu10k1_select_interprom(card,voice) |
+ ((voice->flags & VOICE_FLAGS_16BIT) ? 0 : CCCA_8BITSELECT),
/* Clear filter delay memory */
Z1, 0,
Z2, 0,
diff --git a/sound/oss/emu10k1/voicemgr.h b/sound/oss/emu10k1/voicemgr.h
index 0c60a6de45b4..099a8cb7f2c5 100644
--- a/sound/oss/emu10k1/voicemgr.h
+++ b/sound/oss/emu10k1/voicemgr.h
@@ -48,11 +48,13 @@ struct voice_param
/* FX bus amount send */
u32 send_routing;
+ // audigy only:
+ u32 send_routing2;
+
+ u32 send_dcba;
+ // audigy only:
+ u32 send_hgfe;
- u32 send_a;
- u32 send_b;
- u32 send_c;
- u32 send_d;
u32 initial_fc;
u32 fc_target;
diff --git a/sound/oss/hal2.c b/sound/oss/hal2.c
new file mode 100644
index 000000000000..36cfd22650af
--- /dev/null
+++ b/sound/oss/hal2.c
@@ -0,0 +1,1498 @@
+/*
+ * Driver for HAL2 sound processors
+ * Copyright (c) 2001, 2002 Ladislav Michl <ladis@psi.cz>
+ *
+ * Based on Ulf Carlsson's code.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Supported devices:
+ * /dev/dsp standard dsp device, (mostly) OSS compatible
+ * /dev/mixer standard mixer device, (mostly) OSS compatible
+ *
+ * BUGS:
+ * + Driver currently supports indigo mode only.
+ * + Recording doesn't work. I guess that it is caused by PBUS channel
+ * misconfiguration, but until I get relevant info I'm unable to fix it.
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/sound.h>
+#include <linux/soundcard.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/sgi/sgint23.h>
+
+#include "hal2.h"
+
+#if 0
+#define DEBUG(args...) printk(args)
+#else
+#define DEBUG(args...)
+#endif
+
+#if 0
+#define DEBUG_MIX(args...) printk(args)
+#else
+#define DEBUG_MIX(args...)
+#endif
+
+#define H2_INDIRECT_WAIT(regs) while (regs->isr & H2_ISR_TSTATUS);
+
+#define H2_READ_ADDR(addr) (addr | (1<<7))
+#define H2_WRITE_ADDR(addr) (addr)
+
+static char *hal2str = "HAL2 audio";
+static int ibuffers = 32;
+static int obuffers = 32;
+
+/* I doubt anyone has a machine with two HAL2 cards. It's possible to
+ * have two HPC's, so it is probably possible to have two HAL2 cards.
+ * Try to deal with it, but note that it is not tested.
+ */
+#define MAXCARDS 2
+static hal2_card_t* hal2_card[MAXCARDS];
+
+static const struct {
+ unsigned char idx:4, avail:1;
+} mixtable[SOUND_MIXER_NRDEVICES] = {
+ [SOUND_MIXER_PCM] = { H2_MIX_OUTPUT_ATT, 1 }, /* voice */
+ [SOUND_MIXER_MIC] = { H2_MIX_INPUT_GAIN, 1 }, /* mic */
+};
+
+#define H2_SUPPORTED_FORMATS (AFMT_S16_LE | AFMT_S16_BE)
+
+static inline void hal2_isr_write(hal2_card_t *hal2, u32 val)
+{
+ hal2->ctl_regs->isr = val;
+}
+
+static inline u32 hal2_isr_look(hal2_card_t *hal2)
+{
+ return hal2->ctl_regs->isr;
+}
+
+static inline u32 hal2_rev_look(hal2_card_t *hal2)
+{
+ return hal2->ctl_regs->rev;
+}
+
+#if 0
+static u16 hal2_i_look16(hal2_card_t *hal2, u32 addr)
+{
+ hal2_ctl_regs_t *regs = hal2->ctl_regs;
+
+ regs->iar = H2_READ_ADDR(addr);
+ H2_INDIRECT_WAIT(regs);
+ return (regs->idr0 & 0xffff);
+}
+#endif
+
+static u32 hal2_i_look32(hal2_card_t *hal2, u32 addr)
+{
+ u32 ret;
+ hal2_ctl_regs_t *regs = hal2->ctl_regs;
+
+ regs->iar = H2_READ_ADDR(addr);
+ H2_INDIRECT_WAIT(regs);
+ ret = regs->idr0 & 0xffff;
+ regs->iar = H2_READ_ADDR(addr | 0x1);
+ H2_INDIRECT_WAIT(regs);
+ ret |= (regs->idr0 & 0xffff) << 16;
+ return ret;
+}
+
+static void hal2_i_write16(hal2_card_t *hal2, u32 addr, u16 val)
+{
+ hal2_ctl_regs_t *regs = hal2->ctl_regs;
+
+ regs->idr0 = val;
+ regs->idr1 = 0;
+ regs->idr2 = 0;
+ regs->idr3 = 0;
+ regs->iar = H2_WRITE_ADDR(addr);
+ H2_INDIRECT_WAIT(regs);
+}
+
+static void hal2_i_write32(hal2_card_t *hal2, u32 addr, u32 val)
+{
+ hal2_ctl_regs_t *regs = hal2->ctl_regs;
+
+ regs->idr0 = val & 0xffff;
+ regs->idr1 = val >> 16;
+ regs->idr2 = 0;
+ regs->idr3 = 0;
+ regs->iar = H2_WRITE_ADDR(addr);
+ H2_INDIRECT_WAIT(regs);
+}
+
+static void hal2_i_setbit16(hal2_card_t *hal2, u32 addr, u16 bit)
+{
+ hal2_ctl_regs_t *regs = hal2->ctl_regs;
+
+ regs->iar = H2_READ_ADDR(addr);
+ H2_INDIRECT_WAIT(regs);
+ regs->idr0 = regs->idr0 | bit;
+ regs->idr1 = 0;
+ regs->idr2 = 0;
+ regs->idr3 = 0;
+ regs->iar = H2_WRITE_ADDR(addr);
+ H2_INDIRECT_WAIT(regs);
+}
+
+static void hal2_i_setbit32(hal2_card_t *hal2, u32 addr, u32 bit)
+{
+ u32 tmp;
+ hal2_ctl_regs_t *regs = hal2->ctl_regs;
+
+ regs->iar = H2_READ_ADDR(addr);
+ H2_INDIRECT_WAIT(regs);
+ tmp = regs->idr0 | (regs->idr1 << 16) | bit;
+ regs->idr0 = tmp & 0xffff;
+ regs->idr1 = tmp >> 16;
+ regs->idr2 = 0;
+ regs->idr3 = 0;
+ regs->iar = H2_WRITE_ADDR(addr);
+ H2_INDIRECT_WAIT(regs);
+}
+
+static void hal2_i_clearbit16(hal2_card_t *hal2, u32 addr, u16 bit)
+{
+ hal2_ctl_regs_t *regs = hal2->ctl_regs;
+
+ regs->iar = H2_READ_ADDR(addr);
+ H2_INDIRECT_WAIT(regs);
+ regs->idr0 = regs->idr0 & ~bit;
+ regs->idr1 = 0;
+ regs->idr2 = 0;
+ regs->idr3 = 0;
+ regs->iar = H2_WRITE_ADDR(addr);
+ H2_INDIRECT_WAIT(regs);
+}
+
+#if 0
+static void hal2_i_clearbit32(hal2_card_t *hal2, u32 addr, u32 bit)
+{
+ u32 tmp;
+ hal2_ctl_regs_t *regs = hal2->ctl_regs;
+
+ regs->iar = H2_READ_ADDR(addr);
+ H2_INDIRECT_WAIT(regs);
+ tmp = (regs->idr0 | (regs->idr1 << 16)) & ~bit;
+ regs->idr0 = tmp & 0xffff;
+ regs->idr1 = tmp >> 16;
+ regs->idr2 = 0;
+ regs->idr3 = 0;
+ regs->iar = H2_WRITE_ADDR(addr);
+ H2_INDIRECT_WAIT(regs);
+}
+#endif
+
+#ifdef HAL2_DEBUG
+static void hal2_dump_regs(hal2_card_t *hal2)
+{
+ printk("isr: %08hx ", hal2_isr_look(hal2));
+ printk("rev: %08hx\n", hal2_rev_look(hal2));
+ printk("relay: %04hx\n", hal2_i_look16(hal2, H2I_RELAY_C));
+ printk("port en: %04hx ", hal2_i_look16(hal2, H2I_DMA_PORT_EN));
+ printk("dma end: %04hx ", hal2_i_look16(hal2, H2I_DMA_END));
+ printk("dma drv: %04hx\n", hal2_i_look16(hal2, H2I_DMA_DRV));
+ printk("syn ctl: %04hx ", hal2_i_look16(hal2, H2I_SYNTH_C));
+ printk("aesrx ctl: %04hx ", hal2_i_look16(hal2, H2I_AESRX_C));
+ printk("aestx ctl: %04hx ", hal2_i_look16(hal2, H2I_AESTX_C));
+ printk("dac ctl1: %04hx ", hal2_i_look16(hal2, H2I_ADC_C1));
+ printk("dac ctl2: %08lx ", hal2_i_look32(hal2, H2I_ADC_C2));
+ printk("adc ctl1: %04hx ", hal2_i_look16(hal2, H2I_DAC_C1));
+ printk("adc ctl2: %08lx ", hal2_i_look32(hal2, H2I_DAC_C2));
+ printk("syn map: %04hx\n", hal2_i_look16(hal2, H2I_SYNTH_MAP_C));
+ printk("bres1 ctl1: %04hx ", hal2_i_look16(hal2, H2I_BRES1_C1));
+ printk("bres1 ctl2: %04lx ", hal2_i_look32(hal2, H2I_BRES1_C2));
+ printk("bres2 ctl1: %04hx ", hal2_i_look16(hal2, H2I_BRES2_C1));
+ printk("bres2 ctl2: %04lx ", hal2_i_look32(hal2, H2I_BRES2_C2));
+ printk("bres3 ctl1: %04hx ", hal2_i_look16(hal2, H2I_BRES3_C1));
+ printk("bres3 ctl2: %04lx\n", hal2_i_look32(hal2, H2I_BRES3_C2));
+}
+#endif
+
+static hal2_card_t* hal2_dsp_find_card(int minor)
+{
+ int i;
+
+ for (i = 0; i < MAXCARDS; i++)
+ if (hal2_card[i] != NULL && hal2_card[i]->dev_dsp == minor)
+ return hal2_card[i];
+ return NULL;
+}
+
+static hal2_card_t* hal2_mixer_find_card(int minor)
+{
+ int i;
+
+ for (i = 0; i < MAXCARDS; i++)
+ if (hal2_card[i] != NULL && hal2_card[i]->dev_mixer == minor)
+ return hal2_card[i];
+ return NULL;
+}
+
+
+static void hal2_dac_interrupt(hal2_codec_t *dac)
+{
+ int running;
+
+ spin_lock(&dac->lock);
+
+ /* if tail buffer contains zero samples DMA stream was already
+ * stopped */
+ running = dac->tail->info.cnt;
+ dac->tail->info.cnt = 0;
+ dac->tail->info.desc.cntinfo = HPCDMA_XIE | HPCDMA_EOX;
+ dma_cache_wback_inv((unsigned long) dac->tail,
+ sizeof(struct hpc_dma_desc));
+ /* we just proccessed empty buffer, don't update tail pointer */
+ if (running)
+ dac->tail = dac->tail->info.next;
+
+ spin_unlock(&dac->lock);
+
+ wake_up(&dac->dma_wait);
+}
+
+static void hal2_adc_interrupt(hal2_codec_t *adc)
+{
+ int running;
+
+ spin_lock(&adc->lock);
+
+ /* if head buffer contains nonzero samples DMA stream was already
+ * stopped */
+ running = !adc->head->info.cnt;
+ adc->head->info.cnt = H2_BUFFER_SIZE;
+ adc->head->info.desc.cntinfo = HPCDMA_XIE | HPCDMA_EOX;
+ dma_cache_wback_inv((unsigned long) adc->head,
+ sizeof(struct hpc_dma_desc));
+ /* we just proccessed empty buffer, don't update head pointer */
+ if (running) {
+ dma_cache_inv((unsigned long) adc->head->data, H2_BUFFER_SIZE);
+ adc->head = adc->head->info.next;
+ }
+
+ spin_unlock(&adc->lock);
+
+ wake_up(&adc->dma_wait);
+}
+
+static irqreturn_t hal2_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ hal2_card_t *hal2 = (hal2_card_t*)dev_id;
+
+ /* decide what caused this interrupt */
+ if (hal2->dac.pbus.pbus->pbdma_ctrl & HPC3_PDMACTRL_INT)
+ hal2_dac_interrupt(&hal2->dac);
+ if (hal2->adc.pbus.pbus->pbdma_ctrl & HPC3_PDMACTRL_INT)
+ hal2_adc_interrupt(&hal2->adc);
+ return IRQ_HANDLED;
+}
+
+static int hal2_compute_rate(hal2_codec_t *codec, unsigned int rate)
+{
+ unsigned short inc;
+
+ /* We default to 44.1 kHz and if it isn't possible to fall back to
+ * 48.0 kHz with the needed adjustments of real_rate.
+ */
+
+ DEBUG("rate: %d\n", rate);
+
+ /* Refer to CS4216 data sheet */
+ if (rate < 4000)
+ rate = 4000;
+ if (rate > 50000)
+ rate = 50000;
+
+ /* Note: This is NOT the way they set up the bresenham clock generators
+ * in the specification. I've tried to implement that method but it
+ * doesn't work. It's probably another silly bug in the spec.
+ *
+ * I accidently discovered this method while I was testing and it seems
+ * to work very well with all frequencies, and thee shall follow rule #1
+ * of programming :-)
+ */
+
+ if (44100 % rate == 0) {
+ inc = 44100 / rate;
+ if (inc < 1) inc = 1;
+ codec->master = 44100;
+ } else {
+ inc = 48000 / rate;
+ if (inc < 1) inc = 1;
+ rate = 48000 / inc;
+ codec->master = 48000;
+ }
+ codec->inc = inc;
+ codec->mod = 1;
+
+ DEBUG("real_rate: %d\n", rate);
+
+ return rate;
+}
+
+static void hal2_set_dac_rate(hal2_card_t *hal2)
+{
+ unsigned int master = hal2->dac.master;
+ int inc = hal2->dac.inc;
+ int mod = hal2->dac.mod;
+
+ DEBUG("master: %d inc: %d mod: %d\n", master, inc, mod);
+
+ hal2_i_write16(hal2, H2I_BRES1_C1, (master == 44100) ? 1 : 0);
+ hal2_i_write32(hal2, H2I_BRES1_C2, ((0xffff & (mod - inc - 1)) << 16) | 1);
+}
+
+static void hal2_set_adc_rate(hal2_card_t *hal2)
+{
+ unsigned int master = hal2->adc.master;
+ int inc = hal2->adc.inc;
+ int mod = hal2->adc.mod;
+
+ DEBUG("master: %d inc: %d mod: %d\n", master, inc, mod);
+
+ hal2_i_write16(hal2, H2I_BRES2_C1, (master == 44100) ? 1 : 0);
+ hal2_i_write32(hal2, H2I_BRES2_C2, ((0xffff & (mod - inc - 1)) << 16) | 1);
+}
+
+static void hal2_setup_dac(hal2_card_t *hal2)
+{
+ unsigned int fifobeg, fifoend, highwater, sample_size;
+ hal2_pbus_t *pbus = &hal2->dac.pbus;
+
+ DEBUG("hal2_setup_dac\n");
+
+ /* Now we set up some PBUS information. The PBUS needs information about
+ * what portion of the fifo it will use. If it's receiving or
+ * transmitting, and finally whether the stream is little endian or big
+ * endian. The information is written later, on the start call.
+ */
+ sample_size = 2 * hal2->dac.voices;
+
+ /* Fifo should be set to hold exactly four samples. Highwater mark
+ * should be set to two samples. */
+ highwater = (sample_size * 2) >> 1; /* halfwords */
+ fifobeg = 0; /* playback is first */
+ fifoend = (sample_size * 4) >> 3; /* doublewords */
+ pbus->ctrl = HPC3_PDMACTRL_RT | HPC3_PDMACTRL_LD |
+ (highwater << 8) | (fifobeg << 16) | (fifoend << 24);
+ /* We disable everything before we do anything at all */
+ pbus->pbus->pbdma_ctrl = HPC3_PDMACTRL_LD;
+ hal2_i_clearbit16(hal2, H2I_DMA_PORT_EN, H2I_DMA_PORT_EN_CODECTX);
+ hal2_i_clearbit16(hal2, H2I_DMA_DRV, (1 << pbus->pbusnr));
+ /* Setup the HAL2 for playback */
+ hal2_set_dac_rate(hal2);
+ /* We are using 1st Bresenham clock generator for playback */
+ hal2_i_write16(hal2, H2I_DAC_C1, (pbus->pbusnr << H2I_C1_DMA_SHIFT)
+ | (1 << H2I_C1_CLKID_SHIFT)
+ | (hal2->dac.voices << H2I_C1_DATAT_SHIFT));
+}
+
+static void hal2_setup_adc(hal2_card_t *hal2)
+{
+ unsigned int fifobeg, fifoend, highwater, sample_size;
+ hal2_pbus_t *pbus = &hal2->adc.pbus;
+
+ DEBUG("hal2_setup_adc\n");
+
+ sample_size = 2 * hal2->adc.voices;
+
+ highwater = (sample_size * 2) >> 1; /* halfwords */
+ fifobeg = (4 * 4) >> 3; /* record is second */
+ fifoend = (4 * 4 + sample_size * 4) >> 3; /* doublewords */
+ pbus->ctrl = HPC3_PDMACTRL_RT | HPC3_PDMACTRL_RCV | HPC3_PDMACTRL_LD |
+ (highwater << 8) | (fifobeg << 16) | (fifoend << 24);
+ pbus->pbus->pbdma_ctrl = HPC3_PDMACTRL_LD;
+ hal2_i_clearbit16(hal2, H2I_DMA_PORT_EN, H2I_DMA_PORT_EN_CODECR);
+ hal2_i_clearbit16(hal2, H2I_DMA_DRV, (1 << pbus->pbusnr));
+ /* Setup the HAL2 for record */
+ hal2_set_adc_rate(hal2);
+ /* We are using 2nd Bresenham clock generator for record */
+ hal2_i_write16(hal2, H2I_ADC_C1, (pbus->pbusnr << H2I_C1_DMA_SHIFT)
+ | (2 << H2I_C1_CLKID_SHIFT)
+ | (hal2->adc.voices << H2I_C1_DATAT_SHIFT));
+}
+
+static void hal2_start_dac(hal2_card_t *hal2)
+{
+ hal2_pbus_t *pbus = &hal2->dac.pbus;
+
+ DEBUG("hal2_start_dac\n");
+
+ pbus->pbus->pbdma_dptr = PHYSADDR(hal2->dac.tail);
+ pbus->pbus->pbdma_ctrl = pbus->ctrl | HPC3_PDMACTRL_ACT;
+
+ /* set endianess */
+ if (hal2->dac.format & AFMT_S16_LE)
+ hal2_i_setbit16(hal2, H2I_DMA_END, H2I_DMA_END_CODECTX);
+ else
+ hal2_i_clearbit16(hal2, H2I_DMA_END, H2I_DMA_END_CODECTX);
+ /* set DMA bus */
+ hal2_i_setbit16(hal2, H2I_DMA_DRV, (1 << pbus->pbusnr));
+ /* enable DAC */
+ hal2_i_setbit16(hal2, H2I_DMA_PORT_EN, H2I_DMA_PORT_EN_CODECTX);
+}
+
+static void hal2_start_adc(hal2_card_t *hal2)
+{
+ hal2_pbus_t *pbus = &hal2->adc.pbus;
+
+ DEBUG("hal2_start_adc\n");
+
+ pbus->pbus->pbdma_dptr = PHYSADDR(hal2->adc.head);
+ pbus->pbus->pbdma_ctrl = pbus->ctrl | HPC3_PDMACTRL_ACT;
+
+ /* set endianess */
+ if (hal2->adc.format & AFMT_S16_LE)
+ hal2_i_setbit16(hal2, H2I_DMA_END, H2I_DMA_END_CODECR);
+ else
+ hal2_i_clearbit16(hal2, H2I_DMA_END, H2I_DMA_END_CODECR);
+ /* set DMA bus */
+ hal2_i_setbit16(hal2, H2I_DMA_DRV, (1 << pbus->pbusnr));
+ /* enable ADC */
+ hal2_i_setbit16(hal2, H2I_DMA_PORT_EN, H2I_DMA_PORT_EN_CODECR);
+}
+
+static inline void hal2_stop_dac(hal2_card_t *hal2)
+{
+ DEBUG("hal2_stop_dac\n");
+
+ hal2->dac.pbus.pbus->pbdma_ctrl = HPC3_PDMACTRL_LD;
+ /* The HAL2 itself may remain enabled safely */
+}
+
+static inline void hal2_stop_adc(hal2_card_t *hal2)
+{
+ DEBUG("hal2_stop_adc\n");
+
+ hal2->adc.pbus.pbus->pbdma_ctrl = HPC3_PDMACTRL_LD;
+}
+
+#define hal2_alloc_dac_dmabuf(hal2) hal2_alloc_dmabuf(hal2, 1)
+#define hal2_alloc_adc_dmabuf(hal2) hal2_alloc_dmabuf(hal2, 0)
+static int hal2_alloc_dmabuf(hal2_card_t *hal2, int is_dac)
+{
+ int buffers, cntinfo;
+ hal2_buf_t *buf, *prev;
+ hal2_codec_t *codec;
+
+ if (is_dac) {
+ codec = &hal2->dac;
+ buffers = obuffers;
+ cntinfo = HPCDMA_XIE | HPCDMA_EOX;
+ } else {
+ codec = &hal2->adc;
+ buffers = ibuffers;
+ cntinfo = HPCDMA_XIE | H2_BUFFER_SIZE;
+ }
+
+ DEBUG("allocating %d DMA buffers.\n", buffers);
+
+ buf = (hal2_buf_t*) get_zeroed_page(GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+ codec->head = buf;
+ codec->tail = buf;
+
+ while (--buffers) {
+ buf->info.desc.pbuf = PHYSADDR(&buf->data);
+ buf->info.desc.cntinfo = cntinfo;
+ buf->info.cnt = 0;
+ prev = buf;
+ buf = (hal2_buf_t*) get_zeroed_page(GFP_KERNEL);
+ if (!buf) {
+ printk("HAL2: Not enough memory for DMA buffer.\n");
+ buf = codec->head;
+ while (buf) {
+ prev = buf;
+ free_page((unsigned long) buf);
+ buf = prev->info.next;
+ }
+ return -ENOMEM;
+ }
+ prev->info.next = buf;
+ prev->info.desc.pnext = PHYSADDR(buf);
+ /* The PBUS can prolly not read this stuff when it's in
+ * the cache so we have to flush it back to main memory
+ */
+ dma_cache_wback_inv((unsigned long) prev, PAGE_SIZE);
+ }
+ buf->info.desc.pbuf = PHYSADDR(&buf->data);
+ buf->info.desc.cntinfo = cntinfo;
+ buf->info.cnt = 0;
+ buf->info.next = codec->head;
+ buf->info.desc.pnext = PHYSADDR(codec->head);
+ dma_cache_wback_inv((unsigned long) buf, PAGE_SIZE);
+
+ return 0;
+}
+
+#define hal2_free_dac_dmabuf(hal2) hal2_free_dmabuf(hal2, 1)
+#define hal2_free_adc_dmabuf(hal2) hal2_free_dmabuf(hal2, 0)
+static void hal2_free_dmabuf(hal2_card_t *hal2, int is_dac)
+{
+ hal2_buf_t *buf, *next;
+ hal2_codec_t *codec = (is_dac) ? &hal2->dac : &hal2->adc;
+
+ if (!codec->head)
+ return;
+
+ buf = codec->head->info.next;
+ codec->head->info.next = NULL;
+ while (buf) {
+ next = buf->info.next;
+ free_page((unsigned long) buf);
+ buf = next;
+ }
+ codec->head = codec->tail = NULL;
+}
+
+/*
+ * Add 'count' bytes to 'buffer' from DMA ring buffers. Return number of
+ * bytes added or -EFAULT if copy_from_user failed.
+ */
+static int hal2_get_buffer(hal2_card_t *hal2, char *buffer, int count)
+{
+ unsigned long flags;
+ int size, ret = 0;
+ hal2_codec_t *adc = &hal2->adc;
+
+ spin_lock_irqsave(&adc->lock, flags);
+
+ DEBUG("getting %d bytes ", count);
+
+ /* enable DMA stream if there are no data */
+ if (!(adc->pbus.pbus->pbdma_ctrl & HPC3_PDMACTRL_ISACT) &&
+ adc->tail->info.cnt == 0)
+ hal2_start_adc(hal2);
+
+ DEBUG("... ");
+
+ while (adc->tail->info.cnt > 0 && count > 0) {
+ size = min(adc->tail->info.cnt, count);
+ spin_unlock_irqrestore(&adc->lock, flags);
+
+ if (copy_to_user(buffer, &adc->tail->data[H2_BUFFER_SIZE-size],
+ size)) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ spin_lock_irqsave(&adc->lock, flags);
+
+ adc->tail->info.cnt -= size;
+ /* buffer is empty, update tail pointer */
+ if (adc->tail->info.cnt == 0) {
+ adc->tail->info.desc.cntinfo = HPCDMA_XIE |
+ H2_BUFFER_SIZE;
+ dma_cache_wback_inv((unsigned long) adc->tail,
+ sizeof(struct hpc_dma_desc));
+ adc->tail = adc->tail->info.next;
+ /* enable DMA stream again if needed */
+ if (!(adc->pbus.pbus->pbdma_ctrl & HPC3_PDMACTRL_ISACT))
+ hal2_start_adc(hal2);
+
+ }
+ buffer += size;
+ ret += size;
+ count -= size;
+
+ DEBUG("(%d) ", size);
+ }
+ spin_unlock_irqrestore(&adc->lock, flags);
+out:
+ DEBUG("\n");
+
+ return ret;
+}
+
+/*
+ * Add 'count' bytes from 'buffer' to DMA ring buffers. Return number of
+ * bytes added or -EFAULT if copy_from_user failed.
+ */
+static int hal2_add_buffer(hal2_card_t *hal2, char *buffer, int count)
+{
+ unsigned long flags;
+ int size, ret = 0;
+ hal2_codec_t *dac = &hal2->dac;
+
+ spin_lock_irqsave(&dac->lock, flags);
+
+ DEBUG("adding %d bytes ", count);
+
+ while (dac->head->info.cnt == 0 && count > 0) {
+ size = min((int)H2_BUFFER_SIZE, count);
+ spin_unlock_irqrestore(&dac->lock, flags);
+
+ if (copy_from_user(dac->head->data, buffer, size)) {
+ ret = -EFAULT;
+ goto out;
+ }
+ spin_lock_irqsave(&dac->lock, flags);
+
+ dac->head->info.desc.cntinfo = size | HPCDMA_XIE;
+ dac->head->info.cnt = size;
+ dma_cache_wback_inv((unsigned long) dac->head,
+ size + PAGE_SIZE - H2_BUFFER_SIZE);
+ buffer += size;
+ ret += size;
+ count -= size;
+ dac->head = dac->head->info.next;
+
+ DEBUG("(%d) ", size);
+ }
+ if (!(dac->pbus.pbus->pbdma_ctrl & HPC3_PDMACTRL_ISACT) && ret > 0)
+ hal2_start_dac(hal2);
+
+ spin_unlock_irqrestore(&dac->lock, flags);
+out:
+ DEBUG("\n");
+
+ return ret;
+}
+
+#define hal2_reset_dac_pointer(hal2) hal2_reset_pointer(hal2, 1)
+#define hal2_reset_adc_pointer(hal2) hal2_reset_pointer(hal2, 0)
+static void hal2_reset_pointer(hal2_card_t *hal2, int is_dac)
+{
+ hal2_codec_t *codec = (is_dac) ? &hal2->dac : &hal2->adc;
+
+ DEBUG("hal2_reset_pointer\n");
+
+ codec->tail = codec->head;
+ do {
+ codec->tail->info.desc.cntinfo = HPCDMA_XIE | (is_dac) ?
+ HPCDMA_EOX : H2_BUFFER_SIZE;
+ codec->tail->info.cnt = 0;
+ dma_cache_wback_inv((unsigned long) codec->tail,
+ sizeof(struct hpc_dma_desc));
+ codec->tail = codec->tail->info.next;
+ } while (codec->tail != codec->head);
+}
+
+static int hal2_sync_dac(hal2_card_t *hal2)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ hal2_codec_t *dac = &hal2->dac;
+ int ret = 0;
+ signed long timeout = 1000 * H2_BUFFER_SIZE * 2 * dac->voices *
+ HZ / dac->sample_rate / 900;
+
+ down(&dac->sem);
+
+ while (dac->pbus.pbus->pbdma_ctrl & HPC3_PDMACTRL_ISACT) {
+ add_wait_queue(&dac->dma_wait, &wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (!schedule_timeout(timeout))
+ /* We may get bogus timeout when system is
+ * heavily loaded */
+ if (dac->tail->info.cnt) {
+ printk("HAL2: timeout...\n");
+ ret = -ETIME;
+ }
+ if (signal_pending(current))
+ ret = -ERESTARTSYS;
+ if (ret) {
+ hal2_stop_dac(hal2);
+ hal2_reset_dac_pointer(hal2);
+ }
+ remove_wait_queue(&dac->dma_wait, &wait);
+ }
+
+ up(&dac->sem);
+
+ return ret;
+}
+
+static int hal2_write_mixer(hal2_card_t *hal2, int index, int vol)
+{
+ unsigned int l, r;
+
+ DEBUG_MIX("mixer %d write\n", index);
+
+ if (index >= SOUND_MIXER_NRDEVICES || !mixtable[index].avail)
+ return -EINVAL;
+
+ r = (vol >> 8) & 0xff;
+ if (r > 100)
+ r = 100;
+ l = vol & 0xff;
+ if (l > 100)
+ l = 100;
+
+ hal2->mixer.volume[mixtable[index].idx] = l | (r << 8);
+
+ switch (mixtable[index].idx) {
+ case H2_MIX_OUTPUT_ATT: {
+
+ DEBUG_MIX("output attenuator %d,%d\n", l, r);
+
+ if (r | l) {
+ unsigned int tmp = hal2_i_look32(hal2, H2I_DAC_C2);
+
+ tmp &= ~(H2I_C2_L_ATT_M | H2I_C2_R_ATT_M | H2I_C2_MUTE);
+
+ /* Attenuator has five bits */
+ l = (31 * (100 - l) / 99);
+ r = (31 * (100 - r) / 99);
+
+ DEBUG_MIX("left: %d, right %d\n", l, r);
+
+ tmp |= (l << H2I_C2_L_ATT_SHIFT) & H2I_C2_L_ATT_M;
+ tmp |= (r << H2I_C2_R_ATT_SHIFT) & H2I_C2_R_ATT_M;
+ hal2_i_write32(hal2, H2I_DAC_C2, tmp);
+ } else
+ hal2_i_setbit32(hal2, H2I_DAC_C2, H2I_C2_MUTE);
+ }
+ case H2_MIX_INPUT_GAIN: {
+ /* TODO */
+ }
+ }
+ return 0;
+}
+
+static void hal2_init_mixer(hal2_card_t *hal2)
+{
+ int i;
+
+ for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
+ hal2_write_mixer(hal2, i, 100 | (100 << 8));
+
+}
+
+static int hal2_mixer_ioctl(hal2_card_t *hal2, unsigned int cmd,
+ unsigned long arg)
+{
+ int val;
+
+ if (cmd == SOUND_MIXER_INFO) {
+ mixer_info info;
+
+ strncpy(info.id, hal2str, sizeof(info.id));
+ strncpy(info.name, hal2str, sizeof(info.name));
+ info.modify_counter = hal2->mixer.modcnt;
+ if (copy_to_user((void *)arg, &info, sizeof(info)))
+ return -EFAULT;
+ return 0;
+ }
+ if (cmd == SOUND_OLD_MIXER_INFO) {
+ _old_mixer_info info;
+
+ strncpy(info.id, hal2str, sizeof(info.id));
+ strncpy(info.name, hal2str, sizeof(info.name));
+ if (copy_to_user((void *)arg, &info, sizeof(info)))
+ return -EFAULT;
+ return 0;
+ }
+ if (cmd == OSS_GETVERSION)
+ return put_user(SOUND_VERSION, (int *)arg);
+
+ if (_IOC_TYPE(cmd) != 'M' || _IOC_SIZE(cmd) != sizeof(int))
+ return -EINVAL;
+
+ if (_IOC_DIR(cmd) == _IOC_READ) {
+ switch (_IOC_NR(cmd)) {
+ /* Give the current record source */
+ case SOUND_MIXER_RECSRC:
+ val = 0; /* FIXME */
+ break;
+ /* Give the supported mixers, all of them support stereo */
+ case SOUND_MIXER_DEVMASK:
+ case SOUND_MIXER_STEREODEVS: {
+ int i;
+
+ for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++)
+ if (mixtable[i].avail)
+ val |= 1 << i;
+ break;
+ }
+ /* Arg contains a bit for each supported recording source */
+ case SOUND_MIXER_RECMASK:
+ val = 0;
+ break;
+ case SOUND_MIXER_CAPS:
+ val = 0;
+ break;
+ /* Read a specific mixer */
+ default: {
+ int i = _IOC_NR(cmd);
+
+ if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i].avail)
+ return -EINVAL;
+ val = hal2->mixer.volume[mixtable[i].idx];
+ break;
+ }
+ }
+ return put_user(val, (int *)arg);
+ }
+
+ if (_IOC_DIR(cmd) != (_IOC_WRITE|_IOC_READ))
+ return -EINVAL;
+
+ hal2->mixer.modcnt++;
+
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+
+ switch (_IOC_NR(cmd)) {
+ /* Arg contains a bit for each recording source */
+ case SOUND_MIXER_RECSRC:
+ return 0; /* FIXME */
+ default:
+ return hal2_write_mixer(hal2, _IOC_NR(cmd), val);
+ }
+
+ return 0;
+}
+
+static int hal2_open_mixdev(struct inode *inode, struct file *file)
+{
+ hal2_card_t *hal2 = hal2_mixer_find_card(MINOR(inode->i_rdev));
+
+ if (hal2) {
+ file->private_data = hal2;
+ return 0;
+ }
+ return -ENODEV;
+}
+
+static int hal2_release_mixdev(struct inode *inode, struct file *file)
+{
+ return 0;
+}
+
+static int hal2_ioctl_mixdev(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ return hal2_mixer_ioctl((hal2_card_t *)file->private_data, cmd, arg);
+}
+
+
+static int hal2_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ int val;
+ hal2_card_t *hal2 = (hal2_card_t *) file->private_data;
+
+ switch (cmd) {
+ case OSS_GETVERSION:
+ return put_user(SOUND_VERSION, (int *)arg);
+
+ case SNDCTL_DSP_SYNC:
+ if (file->f_mode & FMODE_WRITE)
+ return hal2_sync_dac(hal2);
+ return 0;
+
+ case SNDCTL_DSP_SETDUPLEX:
+ return 0;
+
+ case SNDCTL_DSP_GETCAPS:
+ return put_user(DSP_CAP_DUPLEX | DSP_CAP_MULTI, (int *)arg);
+
+ case SNDCTL_DSP_RESET:
+ if (file->f_mode & FMODE_READ) {
+ hal2_stop_adc(hal2);
+ hal2_reset_adc_pointer(hal2);
+ }
+ if (file->f_mode & FMODE_WRITE) {
+ hal2_stop_dac(hal2);
+ hal2_reset_dac_pointer(hal2);
+ }
+ return 0;
+
+ case SNDCTL_DSP_SPEED:
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ if (file->f_mode & FMODE_READ) {
+ hal2_stop_adc(hal2);
+ val = hal2_compute_rate(&hal2->adc, val);
+ hal2->adc.sample_rate = val;
+ hal2_set_adc_rate(hal2);
+ }
+ if (file->f_mode & FMODE_WRITE) {
+ hal2_stop_dac(hal2);
+ val = hal2_compute_rate(&hal2->dac, val);
+ hal2->dac.sample_rate = val;
+ hal2_set_dac_rate(hal2);
+ }
+ return put_user(val, (int *)arg);
+
+ case SNDCTL_DSP_STEREO:
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ if (file->f_mode & FMODE_READ) {
+ hal2_stop_adc(hal2);
+ hal2->adc.voices = (val) ? 2 : 1;
+ hal2_setup_adc(hal2);
+ }
+ if (file->f_mode & FMODE_WRITE) {
+ hal2_stop_dac(hal2);
+ hal2->dac.voices = (val) ? 2 : 1;
+ hal2_setup_dac(hal2);
+ }
+ return 0;
+
+ case SNDCTL_DSP_CHANNELS:
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ if (val != 0) {
+ if (file->f_mode & FMODE_READ) {
+ hal2_stop_adc(hal2);
+ hal2->adc.voices = (val == 1) ? 1 : 2;
+ hal2_setup_adc(hal2);
+ }
+ if (file->f_mode & FMODE_WRITE) {
+ hal2_stop_dac(hal2);
+ hal2->dac.voices = (val == 1) ? 1 : 2;
+ hal2_setup_dac(hal2);
+ }
+ }
+ val = -EINVAL;
+ if (file->f_mode & FMODE_READ)
+ val = hal2->adc.voices;
+ if (file->f_mode & FMODE_WRITE)
+ val = hal2->dac.voices;
+ return put_user(val, (int *)arg);
+
+ case SNDCTL_DSP_GETFMTS: /* Returns a mask */
+ return put_user(H2_SUPPORTED_FORMATS, (int *)arg);
+
+ case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+ if (val != AFMT_QUERY) {
+ if (!(val & H2_SUPPORTED_FORMATS))
+ return -EINVAL;
+ if (file->f_mode & FMODE_READ) {
+ hal2_stop_adc(hal2);
+ hal2->adc.format = val;
+ hal2_setup_adc(hal2);
+ }
+ if (file->f_mode & FMODE_WRITE) {
+ hal2_stop_dac(hal2);
+ hal2->dac.format = val;
+ hal2_setup_dac(hal2);
+ }
+ } else {
+ val = -EINVAL;
+ if (file->f_mode & FMODE_READ)
+ val = hal2->adc.format;
+ if (file->f_mode & FMODE_WRITE)
+ val = hal2->dac.format;
+ }
+ return put_user(val, (int *)arg);
+
+ case SNDCTL_DSP_POST:
+ return 0;
+
+ case SNDCTL_DSP_GETOSPACE: {
+ unsigned long flags;
+ audio_buf_info info;
+ hal2_buf_t *buf;
+ hal2_codec_t *dac = &hal2->dac;
+
+ if (!(file->f_mode & FMODE_WRITE))
+ return -EINVAL;
+
+ spin_lock_irqsave(&dac->lock, flags);
+ info.fragments = 0;
+ buf = dac->head;
+ while (buf->info.cnt == 0 && buf != dac->tail) {
+ info.fragments++;
+ buf = buf->info.next;
+ }
+ spin_unlock_irqrestore(&dac->lock, flags);
+
+ info.fragstotal = obuffers;
+ info.fragsize = H2_BUFFER_SIZE;
+ info.bytes = info.fragsize * info.fragments;
+
+ return copy_to_user((void *)arg, &info, sizeof(info)) ? -EFAULT : 0;
+ }
+
+ case SNDCTL_DSP_GETISPACE: {
+ unsigned long flags;
+ audio_buf_info info;
+ hal2_buf_t *buf;
+ hal2_codec_t *adc = &hal2->adc;
+
+ if (!(file->f_mode & FMODE_READ))
+ return -EINVAL;
+
+ spin_lock_irqsave(&adc->lock, flags);
+ info.fragments = 0;
+ info.bytes = 0;
+ buf = adc->tail;
+ while (buf->info.cnt > 0 && buf != adc->head) {
+ info.fragments++;
+ info.bytes += buf->info.cnt;
+ buf = buf->info.next;
+ }
+ spin_unlock_irqrestore(&adc->lock, flags);
+
+ info.fragstotal = ibuffers;
+ info.fragsize = H2_BUFFER_SIZE;
+
+ return copy_to_user((void *)arg, &info, sizeof(info)) ? -EFAULT : 0;
+ }
+
+ case SNDCTL_DSP_NONBLOCK:
+ file->f_flags |= O_NONBLOCK;
+ return 0;
+
+ case SNDCTL_DSP_GETBLKSIZE:
+ return put_user(H2_BUFFER_SIZE, (int *)arg);
+
+ case SNDCTL_DSP_SETFRAGMENT:
+ return 0;
+
+ case SOUND_PCM_READ_RATE:
+ val = -EINVAL;
+ if (file->f_mode & FMODE_READ)
+ val = hal2->adc.sample_rate;
+ if (file->f_mode & FMODE_WRITE)
+ val = hal2->dac.sample_rate;
+ return put_user(val, (int *)arg);
+
+ case SOUND_PCM_READ_CHANNELS:
+ val = -EINVAL;
+ if (file->f_mode & FMODE_READ)
+ val = hal2->adc.voices;
+ if (file->f_mode & FMODE_WRITE)
+ val = hal2->dac.voices;
+ return put_user(val, (int *)arg);
+
+ case SOUND_PCM_READ_BITS:
+ val = 16;
+ return put_user(val, (int *)arg);
+ }
+
+ return hal2_mixer_ioctl(hal2, cmd, arg);
+}
+
+static ssize_t hal2_read(struct file *file, char *buffer,
+ size_t count, loff_t *ppos)
+{
+ ssize_t err;
+ hal2_card_t *hal2 = (hal2_card_t *) file->private_data;
+ hal2_codec_t *adc = &hal2->adc;
+
+ if (count == 0)
+ return 0;
+ if (ppos != &file->f_pos)
+ return -ESPIPE;
+
+ down(&adc->sem);
+
+ if (file->f_flags & O_NONBLOCK) {
+ err = hal2_get_buffer(hal2, buffer, count);
+ err = err == 0 ? -EAGAIN : err;
+ } else {
+ do {
+ /* ~10% longer */
+ signed long timeout = 1000 * H2_BUFFER_SIZE *
+ 2 * adc->voices * HZ / adc->sample_rate / 900;
+ DECLARE_WAITQUEUE(wait, current);
+ ssize_t cnt = 0;
+
+ err = hal2_get_buffer(hal2, buffer, count);
+ if (err > 0) {
+ count -= err;
+ cnt += err;
+ buffer += err;
+ err = cnt;
+ }
+ if (count > 0 && err >= 0) {
+ add_wait_queue(&adc->dma_wait, &wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+ /* Well, it is possible, that interrupt already
+ * arrived. Hmm, shit happens, we have one more
+ * buffer filled ;) */
+ if (!schedule_timeout(timeout))
+ /* We may get bogus timeout when system
+ * is heavily loaded */
+ if (!adc->tail->info.cnt) {
+ printk("HAL2: timeout...\n");
+ hal2_stop_adc(hal2);
+ hal2_reset_adc_pointer(hal2);
+ err = -EAGAIN;
+ }
+ if (signal_pending(current))
+ err = -ERESTARTSYS;
+ remove_wait_queue(&adc->dma_wait, &wait);
+ }
+ } while (count > 0 && err >= 0);
+
+ }
+
+ up(&adc->sem);
+
+ return err;
+}
+
+static ssize_t hal2_write(struct file *file, const char *buffer,
+ size_t count, loff_t *ppos)
+{
+ ssize_t err;
+ char *buf = (char*) buffer;
+ hal2_card_t *hal2 = (hal2_card_t *) file->private_data;
+ hal2_codec_t *dac = &hal2->dac;
+
+ if (count == 0)
+ return 0;
+ if (ppos != &file->f_pos)
+ return -ESPIPE;
+
+ down(&dac->sem);
+
+ if (file->f_flags & O_NONBLOCK) {
+ err = hal2_add_buffer(hal2, buf, count);
+ err = err == 0 ? -EAGAIN : err;
+ } else {
+ do {
+ /* ~10% longer */
+ signed long timeout = 1000 * H2_BUFFER_SIZE *
+ 2 * dac->voices * HZ / dac->sample_rate / 900;
+ DECLARE_WAITQUEUE(wait, current);
+ ssize_t cnt = 0;
+
+ err = hal2_add_buffer(hal2, buf, count);
+ if (err > 0) {
+ count -= err;
+ cnt += err;
+ buf += err;
+ err = cnt;
+ }
+ if (count > 0 && err >= 0) {
+ add_wait_queue(&dac->dma_wait, &wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+ /* Well, it is possible, that interrupt already
+ * arrived. Hmm, shit happens, we have one more
+ * buffer free ;) */
+ if (!schedule_timeout(timeout))
+ /* We may get bogus timeout when system
+ * is heavily loaded */
+ if (dac->head->info.cnt) {
+ printk("HAL2: timeout...\n");
+ hal2_stop_dac(hal2);
+ hal2_reset_dac_pointer(hal2);
+ err = -EAGAIN;
+ }
+ if (signal_pending(current))
+ err = -ERESTARTSYS;
+ remove_wait_queue(&dac->dma_wait, &wait);
+ }
+ } while (count > 0 && err >= 0);
+ }
+
+ up(&dac->sem);
+
+ return err;
+}
+
+static unsigned int hal2_poll(struct file *file, struct poll_table_struct *wait)
+{
+ unsigned long flags;
+ unsigned int mask = 0;
+ hal2_card_t *hal2 = (hal2_card_t *) file->private_data;
+
+ if (file->f_mode & FMODE_READ) {
+ hal2_codec_t *adc = &hal2->adc;
+
+ poll_wait(file, &hal2->adc.dma_wait, wait);
+ spin_lock_irqsave(&adc->lock, flags);
+ if (adc->tail->info.cnt > 0)
+ mask |= POLLIN;
+ spin_unlock_irqrestore(&adc->lock, flags);
+ }
+
+ if (file->f_mode & FMODE_WRITE) {
+ hal2_codec_t *dac = &hal2->dac;
+
+ poll_wait(file, &dac->dma_wait, wait);
+ spin_lock_irqsave(&dac->lock, flags);
+ if (dac->head->info.cnt == 0)
+ mask |= POLLOUT;
+ spin_unlock_irqrestore(&dac->lock, flags);
+ }
+
+ return mask;
+}
+
+static int hal2_open(struct inode *inode, struct file *file)
+{
+ int err;
+ hal2_card_t *hal2 = hal2_dsp_find_card(MINOR(inode->i_rdev));
+
+ DEBUG("opening audio device.\n");
+
+ if (!hal2) {
+ printk("HAL2: Whee?! Open door and go away!\n");
+ return -ENODEV;
+ }
+ file->private_data = hal2;
+
+ if (file->f_mode & FMODE_READ) {
+ if (hal2->adc.usecount)
+ return -EBUSY;
+
+ /* OSS spec wanted us to use 8 bit, 8 kHz mono by default,
+ * but HAL2 can't do 8bit audio */
+ hal2->adc.format = AFMT_S16_BE;
+ hal2->adc.voices = 1;
+ hal2->adc.sample_rate = hal2_compute_rate(&hal2->adc, 8000);
+ hal2_set_adc_rate(hal2);
+
+ /* alloc DMA buffers */
+ err = hal2_alloc_adc_dmabuf(hal2);
+ if (err)
+ return err;
+ hal2_setup_adc(hal2);
+
+ hal2->adc.usecount++;
+ }
+
+ if (file->f_mode & FMODE_WRITE) {
+ if (hal2->dac.usecount)
+ return -EBUSY;
+
+ hal2->dac.format = AFMT_S16_BE;
+ hal2->dac.voices = 1;
+ hal2->dac.sample_rate = hal2_compute_rate(&hal2->dac, 8000);
+ hal2_set_dac_rate(hal2);
+
+ /* alloc DMA buffers */
+ err = hal2_alloc_dac_dmabuf(hal2);
+ if (err)
+ return err;
+ hal2_setup_dac(hal2);
+
+ hal2->dac.usecount++;
+ }
+
+ return 0;
+}
+
+static int hal2_release(struct inode *inode, struct file *file)
+{
+ hal2_card_t *hal2 = (hal2_card_t *) file->private_data;
+
+ if (file->f_mode & FMODE_READ) {
+ hal2_stop_adc(hal2);
+ hal2_free_adc_dmabuf(hal2);
+ hal2->adc.usecount--;
+ }
+
+ if (file->f_mode & FMODE_WRITE) {
+ hal2_sync_dac(hal2);
+ hal2_free_dac_dmabuf(hal2);
+ hal2->dac.usecount--;
+ }
+
+ return 0;
+}
+
+static struct file_operations hal2_audio_fops = {
+ owner: THIS_MODULE,
+ llseek: no_llseek,
+ read: hal2_read,
+ write: hal2_write,
+ poll: hal2_poll,
+ ioctl: hal2_ioctl,
+ open: hal2_open,
+ release: hal2_release,
+};
+
+static struct file_operations hal2_mixer_fops = {
+ owner: THIS_MODULE,
+ llseek: no_llseek,
+ ioctl: hal2_ioctl_mixdev,
+ open: hal2_open_mixdev,
+ release: hal2_release_mixdev,
+};
+
+static int hal2_request_irq(hal2_card_t *hal2, int irq)
+{
+ unsigned long flags;
+ int ret = 0;
+
+ save_and_cli(flags);
+ if (request_irq(irq, hal2_interrupt, SA_SHIRQ, hal2str, hal2)) {
+ printk(KERN_ERR "HAL2: Can't get irq %d\n", irq);
+ ret = -EAGAIN;
+ }
+ restore_flags(flags);
+ return ret;
+}
+
+static int hal2_alloc_resources(hal2_card_t *hal2, struct hpc3_regs *hpc3)
+{
+ hal2_pbus_t *pbus;
+
+ pbus = &hal2->dac.pbus;
+ pbus->pbusnr = 0;
+ pbus->pbus = &hpc3->pbdma[pbus->pbusnr];
+ /* The spec says that we should write 0x08248844 but that's WRONG. HAL2
+ * does 8 bit DMA, not 16 bit even if it generates 16 bit audio. */
+ hpc3->pbus_dmacfgs[pbus->pbusnr][0] = 0x08208844; /* Magic :-) */
+
+ pbus = &hal2->adc.pbus;
+ pbus->pbusnr = 1;
+ pbus->pbus = &hpc3->pbdma[pbus->pbusnr];
+ hpc3->pbus_dmacfgs[pbus->pbusnr][0] = 0x08208844; /* Magic :-) */
+
+ return hal2_request_irq(hal2, SGI_HPCDMA_IRQ);
+}
+
+static void hal2_init_codec(hal2_codec_t *codec)
+{
+ init_waitqueue_head(&codec->dma_wait);
+ init_MUTEX(&codec->sem);
+ spin_lock_init(&codec->lock);
+}
+
+static void hal2_free_resources(hal2_card_t *hal2)
+{
+ free_irq(SGI_HPCDMA_IRQ, hal2);
+}
+
+static int hal2_detect(hal2_card_t *hal2)
+{
+ unsigned short board, major, minor;
+ unsigned short rev;
+
+ /* reset HAL2 */
+ hal2_isr_write(hal2, 0);
+
+ /* release reset */
+ hal2_isr_write(hal2, H2_ISR_GLOBAL_RESET_N | H2_ISR_CODEC_RESET_N);
+
+ hal2_i_write16(hal2, H2I_RELAY_C, H2I_RELAY_C_STATE);
+
+ if ((rev = hal2_rev_look(hal2)) & H2_REV_AUDIO_PRESENT) {
+ DEBUG("HAL2: no device detected, rev: 0x%04hx\n", rev);
+ return -ENODEV;
+ }
+
+ board = (rev & H2_REV_BOARD_M) >> 12;
+ major = (rev & H2_REV_MAJOR_CHIP_M) >> 4;
+ minor = (rev & H2_REV_MINOR_CHIP_M);
+
+ printk("SGI HAL2 Processor revision %i.%i.%i detected\n",
+ board, major, minor);
+
+ if (board != 4 || major != 1 || minor != 0)
+ printk( "Other revision than 4.1.0 detected. "
+ "Your card is probably unsupported\n");
+
+ return 0;
+}
+
+static int hal2_init_card(hal2_card_t **phal2, struct hpc3_regs *hpc3,
+ unsigned long hpc3_base)
+{
+ int ret = 0;
+ hal2_card_t *hal2;
+
+ hal2 = (hal2_card_t *) kmalloc(sizeof(hal2_card_t), GFP_KERNEL);
+ if (!hal2)
+ return -ENOMEM;
+ memset(hal2, 0, sizeof(hal2_card_t));
+
+ hal2->ctl_regs = (hal2_ctl_regs_t *) KSEG1ADDR(hpc3_base + H2_CTL_PIO);
+ hal2->aes_regs = (hal2_aes_regs_t *) KSEG1ADDR(hpc3_base + H2_AES_PIO);
+ hal2->vol_regs = (hal2_vol_regs_t *) KSEG1ADDR(hpc3_base + H2_VOL_PIO);
+ hal2->syn_regs = (hal2_syn_regs_t *) KSEG1ADDR(hpc3_base + H2_SYN_PIO);
+
+ if (hal2_detect(hal2) < 0) {
+ printk("HAL2 audio processor not found\n");
+ ret = -ENODEV;
+ goto fail1;
+ }
+
+ hal2_init_codec(&hal2->dac);
+ hal2_init_codec(&hal2->adc);
+
+ ret = hal2_alloc_resources(hal2, hpc3);
+ if (ret)
+ goto fail1;
+
+ hal2_init_mixer(hal2);
+
+ hal2->dev_dsp = register_sound_dsp(&hal2_audio_fops, -1);
+ if (hal2->dev_dsp < 0) {
+ ret = hal2->dev_dsp;
+ goto fail2;
+ }
+
+ hal2->dev_mixer = register_sound_mixer(&hal2_mixer_fops, -1);
+ if (hal2->dev_mixer < 0) {
+ ret = hal2->dev_mixer;
+ goto fail3;
+ }
+
+ *phal2 = hal2;
+ return 0;
+fail3:
+ unregister_sound_dsp(hal2->dev_dsp);
+fail2:
+ hal2_free_resources(hal2);
+fail1:
+ kfree(hal2);
+
+ return ret;
+}
+
+/*
+ * We are assuming only one HAL2 card. If you ever meet machine with more than
+ * one, tell immediately about it to someone. Preferably to me. --ladis
+ */
+static int __init init_hal2(void)
+{
+ int i;
+
+ for (i = 0; i < MAXCARDS; i++)
+ hal2_card[i] = NULL;
+
+ return hal2_init_card(&hal2_card[0], hpc3c0, HPC3_CHIP0_PBASE);
+}
+
+static void __exit exit_hal2(void)
+{
+ int i;
+
+ for (i = 0; i < MAXCARDS; i++)
+ if (hal2_card[i]) {
+ hal2_free_resources(hal2_card[i]);
+ unregister_sound_dsp(hal2_card[i]->dev_dsp);
+ unregister_sound_mixer(hal2_card[i]->dev_mixer);
+ kfree(hal2_card[i]);
+ }
+}
+
+module_init(init_hal2);
+module_exit(exit_hal2);
+
+MODULE_DESCRIPTION("OSS compatible driver for SGI HAL2 audio");
+MODULE_AUTHOR("Ladislav Michl");
+MODULE_LICENSE("GPL");
diff --git a/sound/oss/hal2.h b/sound/oss/hal2.h
new file mode 100644
index 000000000000..256be453d39b
--- /dev/null
+++ b/sound/oss/hal2.h
@@ -0,0 +1,328 @@
+#ifndef __HAL2_H
+#define __HAL2_H
+
+/*
+ * Driver for HAL2 sound processors
+ * Copyright (c) 1999 Ulf Carlsson <ulfc@bun.falkenberg.se>
+ * Copyright (c) 2001 Ladislav Michl <ladis@psi.cz>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <asm/addrspace.h>
+#include <asm/sgi/sgihpc.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+#define H2_HAL2_BASE 0x58000
+#define H2_CTL_PIO (H2_HAL2_BASE + 0 * 0x400)
+#define H2_AES_PIO (H2_HAL2_BASE + 1 * 0x400)
+#define H2_VOL_PIO (H2_HAL2_BASE + 2 * 0x400)
+#define H2_SYN_PIO (H2_HAL2_BASE + 3 * 0x400)
+
+/* Indirect status register */
+
+#define H2_ISR_TSTATUS 0x01 /* RO: transaction status 1=busy */
+#define H2_ISR_USTATUS 0x02 /* RO: utime status bit 1=armed */
+#define H2_ISR_QUAD_MODE 0x04 /* codec mode 0=indigo 1=quad */
+#define H2_ISR_GLOBAL_RESET_N 0x08 /* chip global reset 0=reset */
+#define H2_ISR_CODEC_RESET_N 0x10 /* codec/synth reset 0=reset */
+
+/* Revision register */
+
+#define H2_REV_AUDIO_PRESENT 0x8000 /* RO: audio present 0=present */
+#define H2_REV_BOARD_M 0x7000 /* RO: bits 14:12, board revision */
+#define H2_REV_MAJOR_CHIP_M 0x00F0 /* RO: bits 7:4, major chip revision */
+#define H2_REV_MINOR_CHIP_M 0x000F /* RO: bits 3:0, minor chip revision */
+
+/* Indirect address register */
+
+/*
+ * Address of indirect internal register to be accessed. A write to this
+ * register initiates read or write access to the indirect registers in the
+ * HAL2. Note that there af four indirect data registers for write access to
+ * registers larger than 16 byte.
+ */
+
+#define H2_IAR_TYPE_M 0xF000 /* bits 15:12, type of functional */
+ /* block the register resides in */
+ /* 1=DMA Port */
+ /* 9=Global DMA Control */
+ /* 2=Bresenham */
+ /* 3=Unix Timer */
+#define H2_IAR_NUM_M 0x0F00 /* bits 11:8 instance of the */
+ /* blockin which the indirect */
+ /* register resides */
+ /* If IAR_TYPE_M=DMA Port: */
+ /* 1=Synth In */
+ /* 2=AES In */
+ /* 3=AES Out */
+ /* 4=DAC Out */
+ /* 5=ADC Out */
+ /* 6=Synth Control */
+ /* If IAR_TYPE_M=Global DMA Control: */
+ /* 1=Control */
+ /* If IAR_TYPE_M=Bresenham: */
+ /* 1=Bresenham Clock Gen 1 */
+ /* 2=Bresenham Clock Gen 2 */
+ /* 3=Bresenham Clock Gen 3 */
+ /* If IAR_TYPE_M=Unix Timer: */
+ /* 1=Unix Timer */
+#define H2_IAR_ACCESS_SELECT 0x0080 /* 1=read 0=write */
+#define H2_IAR_PARAM 0x000C /* Parameter Select */
+#define H2_IAR_RB_INDEX_M 0x0003 /* Read Back Index */
+ /* 00:word0 */
+ /* 01:word1 */
+ /* 10:word2 */
+ /* 11:word3 */
+/*
+ * HAL2 internal addressing
+ *
+ * The HAL2 has "indirect registers" (idr) which are accessed by writing to the
+ * Indirect Data registers. Write the address to the Indirect Address register
+ * to transfer the data.
+ *
+ * We define the H2IR_* to the read address and H2IW_* to the write address and
+ * H2I_* to be fields in whatever register is referred to.
+ *
+ * When we write to indirect registers which are larger than one word (16 bit)
+ * we have to fill more than one indirect register before writing. When we read
+ * back however we have to read several times, each time with different Read
+ * Back Indexes (there are defs for doing this easily).
+ */
+
+/*
+ * Relay Control
+ */
+#define H2I_RELAY_C 0x9100
+#define H2I_RELAY_C_STATE 0x01 /* state of RELAY pin signal */
+
+/* DMA port enable */
+
+#define H2I_DMA_PORT_EN 0x9104
+#define H2I_DMA_PORT_EN_SY_IN 0x01 /* Synth_in DMA port */
+#define H2I_DMA_PORT_EN_AESRX 0x02 /* AES receiver DMA port */
+#define H2I_DMA_PORT_EN_AESTX 0x04 /* AES transmitter DMA port */
+#define H2I_DMA_PORT_EN_CODECTX 0x08 /* CODEC transmit DMA port */
+#define H2I_DMA_PORT_EN_CODECR 0x10 /* CODEC receive DMA port */
+
+#define H2I_DMA_END 0x9108 /* global dma endian select */
+#define H2I_DMA_END_SY_IN 0x01 /* Synth_in DMA port */
+#define H2I_DMA_END_AESRX 0x02 /* AES receiver DMA port */
+#define H2I_DMA_END_AESTX 0x04 /* AES transmitter DMA port */
+#define H2I_DMA_END_CODECTX 0x08 /* CODEC transmit DMA port */
+#define H2I_DMA_END_CODECR 0x10 /* CODEC receive DMA port */
+ /* 0=b_end 1=l_end */
+
+#define H2I_DMA_DRV 0x910C /* global PBUS DMA enable */
+
+#define H2I_SYNTH_C 0x1104 /* Synth DMA control */
+
+#define H2I_AESRX_C 0x1204 /* AES RX dma control */
+
+#define H2I_C_TS_EN 0x20 /* Timestamp enable */
+#define H2I_C_TS_FRMT 0x40 /* Timestamp format */
+#define H2I_C_NAUDIO 0x80 /* Sign extend */
+
+/* AESRX CTL, 16 bit */
+
+#define H2I_AESTX_C 0x1304 /* AES TX DMA control */
+#define H2I_AESTX_C_CLKID_SHIFT 3 /* Bresenham Clock Gen 1-3 */
+#define H2I_AESTX_C_CLKID_M 0x18
+#define H2I_AESTX_C_DATAT_SHIFT 8 /* 1=mono 2=stereo (3=quad) */
+#define H2I_AESTX_C_DATAT_M 0x300
+
+/* CODEC registers */
+
+#define H2I_DAC_C1 0x1404 /* DAC DMA control, 16 bit */
+#define H2I_DAC_C2 0x1408 /* DAC DMA control, 32 bit */
+#define H2I_ADC_C1 0x1504 /* ADC DMA control, 16 bit */
+#define H2I_ADC_C2 0x1508 /* ADC DMA control, 32 bit */
+
+/* Bits in CTL1 register */
+
+#define H2I_C1_DMA_SHIFT 0 /* DMA channel */
+#define H2I_C1_DMA_M 0x7
+#define H2I_C1_CLKID_SHIFT 3 /* Bresenham Clock Gen 1-3 */
+#define H2I_C1_CLKID_M 0x18
+#define H2I_C1_DATAT_SHIFT 8 /* 1=mono 2=stereo (3=quad) */
+#define H2I_C1_DATAT_M 0x300
+
+/* Bits in CTL2 register */
+
+#define H2I_C2_R_GAIN_SHIFT 0 /* right a/d input gain */
+#define H2I_C2_R_GAIN_M 0xf
+#define H2I_C2_L_GAIN_SHIFT 4 /* left a/d input gain */
+#define H2I_C2_L_GAIN_M 0xf0
+#define H2I_C2_R_SEL 0x100 /* right input select */
+#define H2I_C2_L_SEL 0x200 /* left input select */
+#define H2I_C2_MUTE 0x400 /* mute */
+#define H2I_C2_DO1 0x00010000 /* digital output port bit 0 */
+#define H2I_C2_DO2 0x00020000 /* digital output port bit 1 */
+#define H2I_C2_R_ATT_SHIFT 18 /* right d/a output - */
+#define H2I_C2_R_ATT_M 0x007c0000 /* attenuation */
+#define H2I_C2_L_ATT_SHIFT 23 /* left d/a output - */
+#define H2I_C2_L_ATT_M 0x0f800000 /* attenuation */
+
+#define H2I_SYNTH_MAP_C 0x1104 /* synth dma handshake ctrl */
+
+/* Clock generator CTL 1, 16 bit */
+
+#define H2I_BRES1_C1 0x2104
+#define H2I_BRES2_C1 0x2204
+#define H2I_BRES3_C1 0x2304
+
+#define H2I_BRES_C1_SHIFT 0 /* 0=48.0 1=44.1 2=aes_rx */
+#define H2I_BRES_C1_M 0x03
+
+/* Clock generator CTL 2, 32 bit */
+
+#define H2I_BRES1_C2 0x2108
+#define H2I_BRES2_C2 0x2208
+#define H2I_BRES3_C2 0x2308
+
+#define H2I_BRES_C2_INC_SHIFT 0 /* increment value */
+#define H2I_BRES_C2_INC_M 0xffff
+#define H2I_BRES_C2_MOD_SHIFT 16 /* modcontrol value */
+#define H2I_BRES_C2_MOD_M 0xffff0000 /* modctrl=0xffff&(modinc-1) */
+
+/* Unix timer, 64 bit */
+
+#define H2I_UTIME 0x3104
+#define H2I_UTIME_0_LD 0xffff /* microseconds, LSB's */
+#define H2I_UTIME_1_LD0 0x0f /* microseconds, MSB's */
+#define H2I_UTIME_1_LD1 0xf0 /* tenths of microseconds */
+#define H2I_UTIME_2_LD 0xffff /* seconds, LSB's */
+#define H2I_UTIME_3_LD 0xffff /* seconds, MSB's */
+
+typedef volatile u32 hal2_reg_t;
+
+typedef struct stru_hal2_ctl_regs hal2_ctl_regs_t;
+struct stru_hal2_ctl_regs {
+ hal2_reg_t _unused0[4];
+ hal2_reg_t isr; /* 0x10 Status Register */
+ hal2_reg_t _unused1[3];
+ hal2_reg_t rev; /* 0x20 Revision Register */
+ hal2_reg_t _unused2[3];
+ hal2_reg_t iar; /* 0x30 Indirect Address Register */
+ hal2_reg_t _unused3[3];
+ hal2_reg_t idr0; /* 0x40 Indirect Data Register 0 */
+ hal2_reg_t _unused4[3];
+ hal2_reg_t idr1; /* 0x50 Indirect Data Register 1 */
+ hal2_reg_t _unused5[3];
+ hal2_reg_t idr2; /* 0x60 Indirect Data Register 2 */
+ hal2_reg_t _unused6[3];
+ hal2_reg_t idr3; /* 0x70 Indirect Data Register 3 */
+};
+
+typedef struct stru_hal2_aes_regs hal2_aes_regs_t;
+struct stru_hal2_aes_regs {
+ hal2_reg_t rx_stat[2]; /* Status registers */
+ hal2_reg_t rx_cr[2]; /* Control registers */
+ hal2_reg_t rx_ud[4]; /* User data window */
+ hal2_reg_t rx_st[24]; /* Channel status data */
+
+ hal2_reg_t tx_stat[1]; /* Status register */
+ hal2_reg_t tx_cr[3]; /* Control registers */
+ hal2_reg_t tx_ud[4]; /* User data window */
+ hal2_reg_t tx_st[24]; /* Channel status data */
+};
+
+typedef struct stru_hal2_vol_regs hal2_vol_regs_t;
+struct stru_hal2_vol_regs {
+ hal2_reg_t right; /* 0x00 Right volume */
+ hal2_reg_t left; /* 0x04 Left volume */
+};
+
+typedef struct stru_hal2_syn_regs hal2_syn_regs_t;
+struct stru_hal2_syn_regs {
+ hal2_reg_t _unused0[2];
+ hal2_reg_t page; /* DOC Page register */
+ hal2_reg_t regsel; /* DOC Register selection */
+ hal2_reg_t dlow; /* DOC Data low */
+ hal2_reg_t dhigh; /* DOC Data high */
+ hal2_reg_t irq; /* IRQ Status */
+ hal2_reg_t dram; /* DRAM Access */
+};
+
+/* HAL2 specific structures */
+
+typedef struct stru_hal2_pbus hal2_pbus_t;
+struct stru_hal2_pbus {
+ struct hpc3_pbus_dmacregs *pbus;
+ int pbusnr;
+ unsigned int ctrl; /* Current state of pbus->pbdma_ctrl */
+};
+
+typedef struct stru_hal2_binfo hal2_binfo_t;
+typedef struct stru_hal2_buffer hal2_buf_t;
+struct stru_hal2_binfo {
+ volatile struct hpc_dma_desc desc;
+ hal2_buf_t *next; /* pointer to next buffer */
+ int cnt; /* bytes in buffer */
+};
+#define H2_BUFFER_SIZE (PAGE_SIZE - \
+ ((sizeof(hal2_binfo_t) - 1) / 8 + 1) * 8)
+struct stru_hal2_buffer {
+ hal2_binfo_t info;
+ char data[H2_BUFFER_SIZE] __attribute__((aligned(8)));
+};
+
+typedef struct stru_hal2_codec hal2_codec_t;
+struct stru_hal2_codec {
+ hal2_buf_t *head;
+ hal2_buf_t *tail;
+ hal2_pbus_t pbus;
+ unsigned int format; /* Audio data format */
+ int voices; /* mono/stereo */
+ unsigned int sample_rate;
+ unsigned int master; /* Master frequency */
+ unsigned short mod; /* MOD value */
+ unsigned short inc; /* INC value */
+
+ wait_queue_head_t dma_wait;
+ spinlock_t lock;
+ struct semaphore sem;
+
+ int usecount; /* recording and playback are
+ * independent */
+};
+
+#define H2_MIX_OUTPUT_ATT 0
+#define H2_MIX_INPUT_GAIN 1
+#define H2_MIXERS 2
+typedef struct stru_hal2_mixer hal2_mixer_t;
+struct stru_hal2_mixer {
+ int modcnt;
+ unsigned int volume[H2_MIXERS];
+};
+
+typedef struct stru_hal2_card hal2_card_t;
+struct stru_hal2_card {
+ int dev_dsp; /* audio device */
+ int dev_mixer; /* mixer device */
+ int dev_midi; /* midi device */
+
+ hal2_ctl_regs_t *ctl_regs; /* HAL2 ctl registers */
+ hal2_aes_regs_t *aes_regs; /* HAL2 vol registers */
+ hal2_vol_regs_t *vol_regs; /* HAL2 aes registers */
+ hal2_syn_regs_t *syn_regs; /* HAL2 syn registers */
+
+ hal2_codec_t dac;
+ hal2_codec_t adc;
+ hal2_mixer_t mixer;
+};
+
+#endif /* __HAL2_H */
diff --git a/sound/oss/harmony.c b/sound/oss/harmony.c
new file mode 100644
index 000000000000..43d92e1a795b
--- /dev/null
+++ b/sound/oss/harmony.c
@@ -0,0 +1,1307 @@
+/*
+ drivers/sound/harmony.c
+
+ This is a sound driver for ASP's and Lasi's Harmony sound chip
+ and is unlikely to be used for anything other than on a HP PA-RISC.
+
+ Harmony is found in HP 712s, 715/new and many other GSC based machines.
+ On older 715 machines you'll find the technically identical chip
+ called 'Vivace'. Both Harmony and Vicace are supported by this driver.
+
+ Copyright 2000 (c) Linuxcare Canada, Alex deVries <alex@linuxcare.com>
+ Copyright 2000-2002 (c) Helge Deller <deller@gmx.de>
+ Copyright 2001 (c) Matthieu Delahaye <delahaym@esiee.fr>
+ Copyright 2001 (c) Jean-Christophe Vaugeois <vaugeoij@esiee.fr>
+
+
+TODO:
+ - fix SNDCTL_DSP_GETOSPACE and SNDCTL_DSP_GETISPACE ioctls to
+ return the real values
+ - add private ioctl for selecting line- or microphone input
+ (only one of them is available at the same time)
+ - add module parameters
+ - implement mmap functionality
+ - implement gain meter ?
+ - ...
+*/
+
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/pci.h>
+
+#include <asm/gsc.h>
+#include <asm/io.h>
+#include <asm/pgalloc.h>
+
+#include "sound_config.h"
+
+
+#define PFX "harmony: "
+#define HARMONY_VERSION "V0.9a"
+
+#undef DEBUG
+#ifdef DEBUG
+# define DPRINTK printk
+#else
+# define DPRINTK(x,...)
+#endif
+
+
+#define MAX_BUFS 10 /* maximum number of rotating buffers */
+#define HARMONY_BUF_SIZE 4096 /* needs to be a multiple of PAGE_SIZE (4096)! */
+
+#define CNTL_C 0x80000000
+#define CNTL_ST 0x00000020
+#define CNTL_44100 0x00000015 /* HARMONY_SR_44KHZ */
+#define CNTL_8000 0x00000008 /* HARMONY_SR_8KHZ */
+
+#define GAINCTL_HE 0x08000000
+#define GAINCTL_LE 0x04000000
+#define GAINCTL_SE 0x02000000
+
+#define DSTATUS_PN 0x00000200
+#define DSTATUS_RN 0x00000002
+
+#define DSTATUS_IE 0x80000000
+
+#define HARMONY_DF_16BIT_LINEAR 0
+#define HARMONY_DF_8BIT_ULAW 1
+#define HARMONY_DF_8BIT_ALAW 2
+
+#define HARMONY_SS_MONO 0
+#define HARMONY_SS_STEREO 1
+
+#define HARMONY_SR_8KHZ 0x08
+#define HARMONY_SR_16KHZ 0x09
+#define HARMONY_SR_27KHZ 0x0A
+#define HARMONY_SR_32KHZ 0x0B
+#define HARMONY_SR_48KHZ 0x0E
+#define HARMONY_SR_9KHZ 0x0F
+#define HARMONY_SR_5KHZ 0x10
+#define HARMONY_SR_11KHZ 0x11
+#define HARMONY_SR_18KHZ 0x12
+#define HARMONY_SR_22KHZ 0x13
+#define HARMONY_SR_37KHZ 0x14
+#define HARMONY_SR_44KHZ 0x15
+#define HARMONY_SR_33KHZ 0x16
+#define HARMONY_SR_6KHZ 0x17
+
+/*
+ * Some magics numbers used to auto-detect file formats
+ */
+
+#define HARMONY_MAGIC_8B_ULAW 1
+#define HARMONY_MAGIC_8B_ALAW 27
+#define HARMONY_MAGIC_16B_LINEAR 3
+#define HARMONY_MAGIC_MONO 1
+#define HARMONY_MAGIC_STEREO 2
+
+/*
+ * Channels Positions in mixer register
+ */
+
+#define GAIN_HE_SHIFT 27
+#define GAIN_HE_MASK ( 1 << GAIN_HE_SHIFT)
+#define GAIN_LE_SHIFT 26
+#define GAIN_LE_MASK ( 1 << GAIN_LE_SHIFT)
+#define GAIN_SE_SHIFT 25
+#define GAIN_SE_MASK ( 1 << GAIN_SE_SHIFT)
+#define GAIN_IS_SHIFT 24
+#define GAIN_IS_MASK ( 1 << GAIN_IS_SHIFT)
+#define GAIN_MA_SHIFT 20
+#define GAIN_MA_MASK ( 0x0f << GAIN_MA_SHIFT)
+#define GAIN_LI_SHIFT 16
+#define GAIN_LI_MASK ( 0x0f << GAIN_LI_SHIFT)
+#define GAIN_RI_SHIFT 12
+#define GAIN_RI_MASK ( 0x0f << GAIN_RI_SHIFT)
+#define GAIN_LO_SHIFT 6
+#define GAIN_LO_MASK ( 0x3f << GAIN_LO_SHIFT)
+#define GAIN_RO_SHIFT 0
+#define GAIN_RO_MASK ( 0x3f << GAIN_RO_SHIFT)
+
+
+#define MAX_OUTPUT_LEVEL (GAIN_RO_MASK >> GAIN_RO_SHIFT)
+#define MAX_INPUT_LEVEL (GAIN_RI_MASK >> GAIN_RI_SHIFT)
+#define MAX_VOLUME_LEVEL (GAIN_MA_MASK >> GAIN_MA_SHIFT)
+
+/*
+ * Channels Mask in mixer register
+ */
+
+#define GAIN_TOTAL_SILENCE 0x00F00FFF
+#define GAIN_DEFAULT 0x0FF00000
+
+
+struct harmony_hpa {
+ u8 unused000;
+ u8 id;
+ u8 teleshare_id;
+ u8 unused003;
+ u32 reset;
+ u32 cntl;
+ u32 gainctl;
+ u32 pnxtadd;
+ u32 pcuradd;
+ u32 rnxtadd;
+ u32 rcuradd;
+ u32 dstatus;
+ u32 ov;
+ u32 pio;
+ u32 unused02c;
+ u32 unused030[3];
+ u32 diag;
+};
+
+struct harmony_dev {
+ int irq;
+ struct harmony_hpa *hpa;
+ u32 current_gain;
+ u8 data_format; /* HARMONY_DF_xx_BIT_xxx */
+ u8 sample_rate; /* HARMONY_SR_xx_KHZ */
+ u8 stereo_select; /* HARMONY_SS_MONO or HARMONY_SS_STEREO */
+ int format_initialized;
+ u32 dac_rate; /* 8000 ... 48000 (Hz) */
+ int suspended_playing;
+ int suspended_recording;
+
+ int blocked_playing;
+ int blocked_recording;
+
+ wait_queue_head_t wq_play, wq_record;
+ int first_filled_play; /* first buffer containing data (next to play) */
+ int nb_filled_play;
+ int play_offset;
+ int first_filled_record;
+ int nb_filled_record;
+
+ int audio_open, mixer_open;
+ int dsp_unit, mixer_unit;
+
+ struct pci_dev *fake_pci_dev; /* The fake pci_dev needed for
+ pci_* functions under ccio. */
+};
+
+
+static struct harmony_dev harmony;
+
+
+/*
+ * Dynamic sound buffer allocation and DMA memory
+ */
+
+struct harmony_buffer {
+ unsigned char *addr;
+ dma_addr_t dma_handle;
+ int dma_consistent; /* Zero if pci_alloc_consistent() fails */
+ int len;
+};
+
+/*
+ * Harmony memory buffers
+ */
+
+static struct harmony_buffer played_buf, recorded_buf, silent, graveyard;
+
+
+#define CHECK_WBACK_INV_OFFSET(b,offset,len) \
+ do { if (!b.dma_consistent) \
+ dma_cache_wback_inv((unsigned long)b.addr+offset,len); \
+ } while (0)
+
+
+static int __init harmony_alloc_buffer(struct harmony_buffer *b,
+ int buffer_count)
+{
+ b->len = buffer_count * HARMONY_BUF_SIZE;
+ b->addr = pci_alloc_consistent(harmony.fake_pci_dev,
+ b->len, &b->dma_handle);
+ if (b->addr && b->dma_handle) {
+ b->dma_consistent = 1;
+ DPRINTK(KERN_INFO PFX "consistent memory: 0x%lx, played_buf: 0x%lx\n",
+ (unsigned long)b->dma_handle, (unsigned long)b->addr);
+ } else {
+ b->dma_consistent = 0;
+ /* kmalloc()ed memory will HPMC on ccio machines ! */
+ b->addr = kmalloc(b->len, GFP_KERNEL);
+ if (!b->addr) {
+ printk(KERN_ERR PFX "couldn't allocate memory\n");
+ return -EBUSY;
+ }
+ b->dma_handle = __pa(b->addr);
+ }
+ return 0;
+}
+
+static void __exit harmony_free_buffer(struct harmony_buffer *b)
+{
+ if (!b->addr)
+ return;
+
+ if (b->dma_consistent)
+ pci_free_consistent(harmony.fake_pci_dev,
+ b->len, b->addr, b->dma_handle);
+ else
+ kfree(b->addr);
+
+ memset(b, 0, sizeof(*b));
+}
+
+
+
+/*
+ * Low-Level sound-chip programming
+ */
+
+static void __inline__ harmony_wait_CNTL(void)
+{
+ /* Wait until we're out of control mode */
+ while (gsc_readl(&harmony.hpa->cntl) & CNTL_C)
+ /* wait */ ;
+}
+
+
+static void harmony_update_control(void)
+{
+ u32 default_cntl;
+
+ /* Set CNTL */
+ default_cntl = (CNTL_C | /* The C bit */
+ (harmony.data_format << 6) | /* Set the data format */
+ (harmony.stereo_select << 5) | /* Stereo select */
+ (harmony.sample_rate)); /* Set sample rate */
+ harmony.format_initialized = 1;
+
+ /* initialize CNTL */
+ gsc_writel(default_cntl, &harmony.hpa->cntl);
+}
+
+static void harmony_set_control(u8 data_format, u8 sample_rate, u8 stereo_select)
+{
+ harmony.sample_rate = sample_rate;
+ harmony.data_format = data_format;
+ harmony.stereo_select = stereo_select;
+ harmony_update_control();
+}
+
+static void harmony_set_rate(u8 data_rate)
+{
+ harmony.sample_rate = data_rate;
+ harmony_update_control();
+}
+
+static int harmony_detect_rate(int *freq)
+{
+ int newrate;
+ switch (*freq) {
+ case 8000: newrate = HARMONY_SR_8KHZ; break;
+ case 16000: newrate = HARMONY_SR_16KHZ; break;
+ case 27428: newrate = HARMONY_SR_27KHZ; break;
+ case 32000: newrate = HARMONY_SR_32KHZ; break;
+ case 48000: newrate = HARMONY_SR_48KHZ; break;
+ case 9600: newrate = HARMONY_SR_9KHZ; break;
+ case 5125: newrate = HARMONY_SR_5KHZ; break;
+ case 11025: newrate = HARMONY_SR_11KHZ; break;
+ case 18900: newrate = HARMONY_SR_18KHZ; break;
+ case 22050: newrate = HARMONY_SR_22KHZ; break;
+ case 37800: newrate = HARMONY_SR_37KHZ; break;
+ case 44100: newrate = HARMONY_SR_44KHZ; break;
+ case 33075: newrate = HARMONY_SR_33KHZ; break;
+ case 6615: newrate = HARMONY_SR_6KHZ; break;
+ default: newrate = HARMONY_SR_8KHZ;
+ *freq = 8000; break;
+ }
+ return newrate;
+}
+
+static void harmony_set_format(u8 data_format)
+{
+ harmony.data_format = data_format;
+ harmony_update_control();
+}
+
+static void harmony_set_stereo(u8 stereo_select)
+{
+ harmony.stereo_select = stereo_select;
+ harmony_update_control();
+}
+
+static void harmony_disable_interrupts(void)
+{
+ harmony_wait_CNTL();
+ gsc_writel(0, &harmony.hpa->dstatus);
+}
+
+static void harmony_enable_interrupts(void)
+{
+ harmony_wait_CNTL();
+ gsc_writel(DSTATUS_IE, &harmony.hpa->dstatus);
+}
+
+/*
+ * harmony_silence()
+ *
+ * This subroutine fills in a buffer starting at location start and
+ * silences for length bytes. This references the current
+ * configuration of the audio format.
+ *
+ */
+
+static void harmony_silence(struct harmony_buffer *buffer, int start, int length)
+{
+ u8 silence_char;
+
+ /* Despite what you hear, silence is different in
+ different audio formats. */
+ switch (harmony.data_format) {
+ case HARMONY_DF_8BIT_ULAW: silence_char = 0x55; break;
+ case HARMONY_DF_8BIT_ALAW: silence_char = 0xff; break;
+ case HARMONY_DF_16BIT_LINEAR: /* fall through */
+ default: silence_char = 0;
+ }
+
+ memset(buffer->addr+start, silence_char, length);
+}
+
+
+static int harmony_audio_open(struct inode *inode, struct file *file)
+{
+ if (harmony.audio_open)
+ return -EBUSY;
+
+ harmony.audio_open++;
+ harmony.suspended_playing = harmony.suspended_recording = 1;
+ harmony.blocked_playing = harmony.blocked_recording = 0;
+ harmony.first_filled_play = harmony.first_filled_record = 0;
+ harmony.nb_filled_play = harmony.nb_filled_record = 0;
+ harmony.play_offset = 0;
+ init_waitqueue_head(&harmony.wq_play);
+ init_waitqueue_head(&harmony.wq_record);
+
+ /* Start off in a balanced mode. */
+ harmony_set_control(HARMONY_DF_8BIT_ULAW, HARMONY_SR_8KHZ, HARMONY_SS_MONO);
+ harmony_update_control();
+ harmony.format_initialized = 0;
+
+ /* Clear out all the buffers and flush to cache */
+ harmony_silence(&played_buf, 0, HARMONY_BUF_SIZE*MAX_BUFS);
+ CHECK_WBACK_INV_OFFSET(played_buf, 0, HARMONY_BUF_SIZE*MAX_BUFS);
+
+ return 0;
+}
+
+/*
+ * Release (close) the audio device.
+ */
+
+static int harmony_audio_release(struct inode *inode, struct file *file)
+{
+ if (!harmony.audio_open)
+ return -EBUSY;
+
+ harmony.audio_open--;
+
+ return 0;
+}
+
+/*
+ * Read recorded data off the audio device.
+ */
+
+static ssize_t harmony_audio_read(struct file *file,
+ char *buffer,
+ size_t size_count,
+ loff_t *ppos)
+{
+ int total_count = (int) size_count;
+ int count = 0;
+ int buf_to_read;
+
+ while (count<total_count) {
+ /* Wait until we're out of control mode */
+ harmony_wait_CNTL();
+
+ /* Figure out which buffer to fill in */
+ if (harmony.nb_filled_record <= 2) {
+ harmony.blocked_recording = 1;
+ if (harmony.suspended_recording) {
+ harmony.suspended_recording = 0;
+ harmony_enable_interrupts();
+ }
+
+ interruptible_sleep_on(&harmony.wq_record);
+ harmony.blocked_recording = 0;
+ }
+
+ if (harmony.nb_filled_record < 2)
+ return -EBUSY;
+
+ buf_to_read = harmony.first_filled_record;
+
+ /* Copy the page to an aligned buffer */
+ if (copy_to_user(buffer+count, recorded_buf.addr +
+ (HARMONY_BUF_SIZE*buf_to_read),
+ HARMONY_BUF_SIZE)) {
+ count = -EFAULT;
+ break;
+ }
+
+ harmony.nb_filled_record--;
+ harmony.first_filled_record++;
+ harmony.first_filled_record %= MAX_BUFS;
+
+ count += HARMONY_BUF_SIZE;
+ }
+ return count;
+}
+
+
+
+
+/*
+ * Here is the place where we try to recognize file format.
+ * Sun/NeXT .au files begin with the string .snd
+ * At offset 12 is specified the encoding.
+ * At offset 16 is specified speed rate
+ * At Offset 20 is specified the numbers of voices
+ */
+
+#define four_bytes_to_u32(start) (file_header[start] << 24)|\
+ (file_header[start+1] << 16)|\
+ (file_header[start+2] << 8)|\
+ (file_header[start+3]);
+
+#define test_rate(tested,real_value,harmony_value) if ((tested)<=(real_value))\
+
+
+static int harmony_format_auto_detect(const char *buffer, int block_size)
+{
+ u8 file_header[24];
+ u32 start_string;
+ int ret = 0;
+
+ if (block_size>24) {
+ if (copy_from_user(file_header, buffer, sizeof(file_header)))
+ ret = -EFAULT;
+
+ start_string = four_bytes_to_u32(0);
+
+ if ((file_header[4]==0) && (start_string==0x2E736E64)) {
+ u32 format;
+ u32 nb_voices;
+ u32 speed;
+
+ format = four_bytes_to_u32(12);
+ nb_voices = four_bytes_to_u32(20);
+ speed = four_bytes_to_u32(16);
+
+ switch (format) {
+ case HARMONY_MAGIC_8B_ULAW:
+ harmony.data_format = HARMONY_DF_8BIT_ULAW;
+ break;
+ case HARMONY_MAGIC_8B_ALAW:
+ harmony.data_format = HARMONY_DF_8BIT_ALAW;
+ break;
+ case HARMONY_MAGIC_16B_LINEAR:
+ harmony.data_format = HARMONY_DF_16BIT_LINEAR;
+ break;
+ default:
+ harmony_set_control(HARMONY_DF_16BIT_LINEAR,
+ HARMONY_SR_44KHZ, HARMONY_SS_STEREO);
+ goto out;
+ }
+ switch (nb_voices) {
+ case HARMONY_MAGIC_MONO:
+ harmony.stereo_select = HARMONY_SS_MONO;
+ break;
+ case HARMONY_MAGIC_STEREO:
+ harmony.stereo_select = HARMONY_SS_STEREO;
+ break;
+ default:
+ harmony.stereo_select = HARMONY_SS_MONO;
+ break;
+ }
+ harmony_set_rate(harmony_detect_rate(&speed));
+ harmony.dac_rate = speed;
+ goto out;
+ }
+ }
+ harmony_set_control(HARMONY_DF_8BIT_ULAW, HARMONY_SR_8KHZ, HARMONY_SS_MONO);
+out:
+ return ret;
+}
+#undef four_bytes_to_u32
+
+
+static ssize_t harmony_audio_write(struct file *file,
+ const char *buffer,
+ size_t size_count,
+ loff_t *ppos)
+{
+ int total_count = (int) size_count;
+ int count = 0;
+ int frame_size;
+ int buf_to_fill;
+
+ if (!harmony.format_initialized) {
+ if (harmony_format_auto_detect(buffer, total_count))
+ return -EFAULT;
+ }
+
+ while (count<total_count) {
+ /* Wait until we're out of control mode */
+ harmony_wait_CNTL();
+
+ /* Figure out which buffer to fill in */
+ if (harmony.nb_filled_play+2 >= MAX_BUFS && !harmony.play_offset) {
+ harmony.blocked_playing = 1;
+ interruptible_sleep_on(&harmony.wq_play);
+ harmony.blocked_playing = 0;
+ }
+ if (harmony.nb_filled_play+2 >= MAX_BUFS && !harmony.play_offset)
+ return -EBUSY;
+
+
+ buf_to_fill = (harmony.first_filled_play+harmony.nb_filled_play);
+ if (harmony.play_offset)
+ buf_to_fill--;
+ buf_to_fill %= MAX_BUFS;
+
+ /* Figure out the size of the frame */
+ if ((total_count-count) > HARMONY_BUF_SIZE - harmony.play_offset) {
+ frame_size = HARMONY_BUF_SIZE - harmony.play_offset;
+ } else {
+ frame_size = total_count - count;
+ /* Clear out the buffer, since there we'll only be
+ overlaying part of the old buffer with the new one */
+ harmony_silence(&played_buf,
+ HARMONY_BUF_SIZE*buf_to_fill+frame_size+harmony.play_offset,
+ HARMONY_BUF_SIZE-frame_size-harmony.play_offset);
+ }
+
+ /* Copy the page to an aligned buffer */
+ if (copy_from_user(played_buf.addr +(HARMONY_BUF_SIZE*buf_to_fill) + harmony.play_offset,
+ buffer+count, frame_size))
+ return -EFAULT;
+ CHECK_WBACK_INV_OFFSET(played_buf, (HARMONY_BUF_SIZE*buf_to_fill + harmony.play_offset),
+ frame_size);
+
+ if (!harmony.play_offset)
+ harmony.nb_filled_play++;
+
+ count += frame_size;
+ harmony.play_offset += frame_size;
+ harmony.play_offset %= HARMONY_BUF_SIZE;
+ if (harmony.suspended_playing && (harmony.nb_filled_play>=4))
+ harmony_enable_interrupts();
+ }
+
+ return count;
+}
+
+static unsigned int harmony_audio_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ unsigned int mask = 0;
+
+ if (file->f_mode & FMODE_READ) {
+ if (!harmony.suspended_recording)
+ poll_wait(file, &harmony.wq_record, wait);
+ if (harmony.nb_filled_record)
+ mask |= POLLIN | POLLRDNORM;
+ }
+
+ if (file->f_mode & FMODE_WRITE) {
+ if (!harmony.suspended_playing)
+ poll_wait(file, &harmony.wq_play, wait);
+ if (harmony.nb_filled_play)
+ mask |= POLLOUT | POLLWRNORM;
+ }
+
+ return mask;
+}
+
+static int harmony_audio_ioctl(struct inode *inode,
+ struct file *file,
+ unsigned int cmd,
+ unsigned long arg)
+{
+ int ival, new_format;
+ int frag_size, frag_buf;
+ struct audio_buf_info info;
+
+ switch (cmd) {
+ case OSS_GETVERSION:
+ return put_user(SOUND_VERSION, (int *) arg);
+
+ case SNDCTL_DSP_GETCAPS:
+ ival = DSP_CAP_DUPLEX;
+ return put_user(ival, (int *) arg);
+
+ case SNDCTL_DSP_GETFMTS:
+ ival = (AFMT_S16_BE | AFMT_MU_LAW | AFMT_A_LAW );
+ return put_user(ival, (int *) arg);
+
+ case SNDCTL_DSP_SETFMT:
+ if (get_user(ival, (int *) arg))
+ return -EFAULT;
+ if (ival != AFMT_QUERY) {
+ switch (ival) {
+ case AFMT_MU_LAW: new_format = HARMONY_DF_8BIT_ULAW; break;
+ case AFMT_A_LAW: new_format = HARMONY_DF_8BIT_ALAW; break;
+ case AFMT_S16_LE: /* fall through, but not really supported */
+ case AFMT_S16_BE: new_format = HARMONY_DF_16BIT_LINEAR;
+ ival = AFMT_S16_BE;
+ break;
+ default: {
+ DPRINTK(KERN_WARNING PFX
+ "unsupported sound format 0x%04x requested.\n",
+ ival);
+ return -EINVAL;
+ }
+ }
+ harmony_set_format(new_format);
+ } else {
+ switch (harmony.data_format) {
+ case HARMONY_DF_8BIT_ULAW: ival = AFMT_MU_LAW; break;
+ case HARMONY_DF_8BIT_ALAW: ival = AFMT_A_LAW; break;
+ case HARMONY_DF_16BIT_LINEAR: ival = AFMT_U16_BE; break;
+ default: ival = 0;
+ }
+ }
+ return put_user(ival, (int *) arg);
+
+ case SOUND_PCM_READ_RATE:
+ ival = harmony.dac_rate;
+ return put_user(ival, (int *) arg);
+
+ case SNDCTL_DSP_SPEED:
+ if (get_user(ival, (int *) arg))
+ return -EFAULT;
+ harmony_set_rate(harmony_detect_rate(&ival));
+ harmony.dac_rate = ival;
+ return put_user(ival, (int*) arg);
+
+ case SNDCTL_DSP_STEREO:
+ if (get_user(ival, (int *) arg))
+ return -EFAULT;
+ if (ival != 0 && ival != 1)
+ return -EINVAL;
+ harmony_set_stereo(ival);
+ return put_user(ival, (int *) arg);
+
+ case SNDCTL_DSP_GETBLKSIZE:
+ ival = HARMONY_BUF_SIZE;
+ return put_user(ival, (int *) arg);
+
+ case SNDCTL_DSP_NONBLOCK:
+ file->f_flags |= O_NONBLOCK;
+ return 0;
+
+ case SNDCTL_DSP_RESET:
+ if (!harmony.suspended_recording) {
+ /* TODO: stop_recording() */
+ }
+ return 0;
+
+ case SNDCTL_DSP_SETFRAGMENT:
+ if (get_user(ival, (int *)arg))
+ return -EFAULT;
+ frag_size = ival & 0xffff;
+ frag_buf = (ival>>16) & 0xffff;
+ /* TODO: We use hardcoded fragment sizes and numbers for now */
+ frag_size = 12; /* 4096 == 2^12 */
+ frag_buf = MAX_BUFS;
+ ival = (frag_buf << 16) + frag_size;
+ return put_user(ival, (int *) arg);
+
+ case SNDCTL_DSP_GETOSPACE:
+ if (!(file->f_mode & FMODE_WRITE))
+ return -EINVAL;
+ info.fragstotal = MAX_BUFS;
+ info.fragments = MAX_BUFS - harmony.nb_filled_play;
+ info.fragsize = HARMONY_BUF_SIZE;
+ info.bytes = info.fragments * info.fragsize;
+ return copy_to_user((void *)arg, &info, sizeof(info));
+
+ case SNDCTL_DSP_GETISPACE:
+ if (!(file->f_mode & FMODE_READ))
+ return -EINVAL;
+ info.fragstotal = MAX_BUFS;
+ info.fragments = /*MAX_BUFS-*/ harmony.nb_filled_record;
+ info.fragsize = HARMONY_BUF_SIZE;
+ info.bytes = info.fragments * info.fragsize;
+ return copy_to_user((void *)arg, &info, sizeof(info));
+
+ case SNDCTL_DSP_SYNC:
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+
+/*
+ * harmony_interrupt()
+ *
+ * harmony interruption service routine
+ *
+ */
+
+static irqreturn_t harmony_interrupt(int irq, void *dev, struct pt_regs *regs)
+{
+ u32 dstatus;
+ struct harmony_hpa *hpa;
+
+ /* Setup the hpa */
+ hpa = ((struct harmony_dev *)dev)->hpa;
+ harmony_wait_CNTL();
+
+ /* Read dstatus and pcuradd (the current address) */
+ dstatus = gsc_readl(&hpa->dstatus);
+
+ /* Turn off interrupts */
+ harmony_disable_interrupts();
+
+ /* Check if this is a request to get the next play buffer */
+ if (dstatus & DSTATUS_PN) {
+ if (!harmony.nb_filled_play) {
+ harmony.suspended_playing = 1;
+ gsc_writel((unsigned long)silent.dma_handle, &hpa->pnxtadd);
+
+ if (!harmony.suspended_recording)
+ harmony_enable_interrupts();
+ } else {
+ harmony.suspended_playing = 0;
+ gsc_writel((unsigned long)played_buf.dma_handle +
+ (HARMONY_BUF_SIZE*harmony.first_filled_play),
+ &hpa->pnxtadd);
+ harmony.first_filled_play++;
+ harmony.first_filled_play %= MAX_BUFS;
+ harmony.nb_filled_play--;
+
+ harmony_enable_interrupts();
+ }
+
+ if (harmony.blocked_playing)
+ wake_up_interruptible(&harmony.wq_play);
+ }
+
+ /* Check if we're being asked to fill in a recording buffer */
+ if (dstatus & DSTATUS_RN) {
+ if((harmony.nb_filled_record+2>=MAX_BUFS) || harmony.suspended_recording)
+ {
+ harmony.nb_filled_record = 0;
+ harmony.first_filled_record = 0;
+ harmony.suspended_recording = 1;
+ gsc_writel((unsigned long)graveyard.dma_handle, &hpa->rnxtadd);
+ if (!harmony.suspended_playing)
+ harmony_enable_interrupts();
+ } else {
+ int buf_to_fill;
+ buf_to_fill = (harmony.first_filled_record+harmony.nb_filled_record) % MAX_BUFS;
+ CHECK_WBACK_INV_OFFSET(recorded_buf, HARMONY_BUF_SIZE*buf_to_fill, HARMONY_BUF_SIZE);
+ gsc_writel((unsigned long)recorded_buf.dma_handle +
+ HARMONY_BUF_SIZE*buf_to_fill,
+ &hpa->rnxtadd);
+ harmony.nb_filled_record++;
+ harmony_enable_interrupts();
+ }
+
+ if (harmony.blocked_recording && harmony.nb_filled_record>3)
+ wake_up_interruptible(&harmony.wq_record);
+ }
+ return IRQ_HANDLED;
+}
+
+/*
+ * Sound playing functions
+ */
+
+static struct file_operations harmony_audio_fops = {
+ owner: THIS_MODULE,
+ llseek: no_llseek,
+ read: harmony_audio_read,
+ write: harmony_audio_write,
+ poll: harmony_audio_poll,
+ ioctl: harmony_audio_ioctl,
+ open: harmony_audio_open,
+ release:harmony_audio_release,
+};
+
+static int harmony_audio_init(void)
+{
+ /* Request that IRQ */
+ if (request_irq(harmony.irq, harmony_interrupt, 0 ,"harmony", &harmony)) {
+ printk(KERN_ERR PFX "Error requesting irq %d.\n", harmony.irq);
+ return -EFAULT;
+ }
+
+ harmony.dsp_unit = register_sound_dsp(&harmony_audio_fops, -1);
+ if (harmony.dsp_unit < 0) {
+ printk(KERN_ERR PFX "Error registering dsp\n");
+ free_irq(harmony.irq, &harmony);
+ return -EFAULT;
+ }
+
+ /* Clear the buffers so you don't end up with crap in the buffers. */
+ harmony_silence(&played_buf, 0, HARMONY_BUF_SIZE*MAX_BUFS);
+
+ /* Make sure this makes it to cache */
+ CHECK_WBACK_INV_OFFSET(played_buf, 0, HARMONY_BUF_SIZE*MAX_BUFS);
+
+ /* Clear out the silent buffer and flush to cache */
+ harmony_silence(&silent, 0, HARMONY_BUF_SIZE);
+ CHECK_WBACK_INV_OFFSET(silent, 0, HARMONY_BUF_SIZE);
+
+ harmony.audio_open = 0;
+
+ return 0;
+}
+
+
+/*
+ * mixer functions
+ */
+
+static void harmony_mixer_set_gain(void)
+{
+ harmony_wait_CNTL();
+ gsc_writel(harmony.current_gain, &harmony.hpa->gainctl);
+}
+
+/*
+ * Read gain of selected channel.
+ * The OSS rate is from 0 (silent) to 100 -> need some conversions
+ *
+ * The harmony gain are attenuation for output and monitor gain.
+ * is amplifaction for input gain
+ */
+#define to_harmony_level(level,max) ((level)*max/100)
+#define to_oss_level(level,max) ((level)*100/max)
+
+static int harmony_mixer_get_level(int channel)
+{
+ int left_level;
+ int right_level;
+
+ switch (channel) {
+ case SOUND_MIXER_OGAIN:
+ left_level = (harmony.current_gain & GAIN_LO_MASK) >> GAIN_LO_SHIFT;
+ right_level = (harmony.current_gain & GAIN_RO_MASK) >> GAIN_RO_SHIFT;
+ left_level = to_oss_level(MAX_OUTPUT_LEVEL - left_level, MAX_OUTPUT_LEVEL);
+ right_level = to_oss_level(MAX_OUTPUT_LEVEL - right_level, MAX_OUTPUT_LEVEL);
+ return (right_level << 8)+left_level;
+
+ case SOUND_MIXER_IGAIN:
+ left_level = (harmony.current_gain & GAIN_LI_MASK) >> GAIN_LI_SHIFT;
+ right_level= (harmony.current_gain & GAIN_RI_MASK) >> GAIN_RI_SHIFT;
+ left_level = to_oss_level(left_level, MAX_INPUT_LEVEL);
+ right_level= to_oss_level(right_level, MAX_INPUT_LEVEL);
+ return (right_level << 8)+left_level;
+
+ case SOUND_MIXER_VOLUME:
+ left_level = (harmony.current_gain & GAIN_MA_MASK) >> GAIN_MA_SHIFT;
+ left_level = to_oss_level(MAX_VOLUME_LEVEL-left_level, MAX_VOLUME_LEVEL);
+ return left_level;
+ }
+ return -EINVAL;
+}
+
+
+
+/*
+ * Some conversions for the same reasons.
+ * We give back the new real value(s) due to
+ * the rescale.
+ */
+
+static int harmony_mixer_set_level(int channel, int value)
+{
+ int left_level;
+ int right_level;
+ int new_left_level;
+ int new_right_level;
+
+ right_level = (value & 0x0000ff00) >> 8;
+ left_level = value & 0x000000ff;
+
+ switch (channel) {
+ case SOUND_MIXER_OGAIN:
+ right_level = to_harmony_level(100-right_level, MAX_OUTPUT_LEVEL);
+ left_level = to_harmony_level(100-left_level, MAX_OUTPUT_LEVEL);
+ new_right_level = to_oss_level(MAX_OUTPUT_LEVEL - right_level, MAX_OUTPUT_LEVEL);
+ new_left_level = to_oss_level(MAX_OUTPUT_LEVEL - left_level, MAX_OUTPUT_LEVEL);
+ harmony.current_gain = (harmony.current_gain & ~(GAIN_LO_MASK | GAIN_RO_MASK))
+ | (left_level << GAIN_LO_SHIFT) | (right_level << GAIN_RO_SHIFT);
+ harmony_mixer_set_gain();
+ return (new_right_level << 8) + new_left_level;
+
+ case SOUND_MIXER_IGAIN:
+ right_level = to_harmony_level(right_level, MAX_INPUT_LEVEL);
+ left_level = to_harmony_level(left_level, MAX_INPUT_LEVEL);
+ new_right_level = to_oss_level(right_level, MAX_INPUT_LEVEL);
+ new_left_level = to_oss_level(left_level, MAX_INPUT_LEVEL);
+ harmony.current_gain = (harmony.current_gain & ~(GAIN_LI_MASK | GAIN_RI_MASK))
+ | (left_level << GAIN_LI_SHIFT) | (right_level << GAIN_RI_SHIFT);
+ harmony_mixer_set_gain();
+ return (new_right_level << 8) + new_left_level;
+
+ case SOUND_MIXER_VOLUME:
+ left_level = to_harmony_level(100-left_level, MAX_VOLUME_LEVEL);
+ new_left_level = to_oss_level(MAX_VOLUME_LEVEL-left_level, MAX_VOLUME_LEVEL);
+ harmony.current_gain = (harmony.current_gain & ~GAIN_MA_MASK)| (left_level << GAIN_MA_SHIFT);
+ harmony_mixer_set_gain();
+ return new_left_level;
+ }
+
+ return -EINVAL;
+}
+
+#undef to_harmony_level
+#undef to_oss_level
+
+/*
+ * Return the selected input device (mic or line)
+ */
+
+static int harmony_mixer_get_recmask(void)
+{
+ int current_input_line;
+
+ current_input_line = (harmony.current_gain & GAIN_IS_MASK)
+ >> GAIN_IS_SHIFT;
+ if (current_input_line)
+ return SOUND_MASK_MIC;
+
+ return SOUND_MASK_LINE;
+}
+
+/*
+ * Set the input (only one at time, arbitrary priority to line in)
+ */
+
+static int harmony_mixer_set_recmask(int recmask)
+{
+ int new_input_line;
+ int new_input_mask;
+
+ if ((recmask & SOUND_MASK_LINE)) {
+ new_input_line = 0;
+ new_input_mask = SOUND_MASK_LINE;
+ } else {
+ new_input_line = 1;
+ new_input_mask = SOUND_MASK_MIC;
+ }
+ harmony.current_gain = ((harmony.current_gain & ~GAIN_IS_MASK) |
+ (new_input_line << GAIN_IS_SHIFT ));
+ harmony_mixer_set_gain();
+ return new_input_mask;
+}
+
+
+/*
+ * give the active outlines
+ */
+
+static int harmony_mixer_get_outmask(void)
+{
+ int outmask = 0;
+
+ if (harmony.current_gain & GAIN_HE_MASK) outmask |=SOUND_MASK_PHONEOUT;
+ if (harmony.current_gain & GAIN_LE_MASK) outmask |=SOUND_MASK_LINE;
+ if (harmony.current_gain & GAIN_SE_MASK) outmask |=SOUND_MASK_SPEAKER;
+
+ return outmask;
+}
+
+
+static int harmony_mixer_set_outmask(int outmask)
+{
+ if (outmask & SOUND_MASK_PHONEOUT)
+ harmony.current_gain |= GAIN_HE_MASK;
+ else
+ harmony.current_gain &= ~GAIN_HE_MASK;
+
+ if (outmask & SOUND_MASK_LINE)
+ harmony.current_gain |= GAIN_LE_MASK;
+ else
+ harmony.current_gain &= ~GAIN_LE_MASK;
+
+ if (outmask & SOUND_MASK_SPEAKER)
+ harmony.current_gain |= GAIN_SE_MASK;
+ else
+ harmony.current_gain &= ~GAIN_SE_MASK;
+
+ harmony_mixer_set_gain();
+
+ return (outmask & (SOUND_MASK_PHONEOUT | SOUND_MASK_LINE | SOUND_MASK_SPEAKER));
+}
+
+/*
+ * This code is inspired from sb_mixer.c
+ */
+
+static int harmony_mixer_ioctl(struct inode * inode, struct file * file,
+ unsigned int cmd, unsigned long arg)
+{
+ int val;
+ int ret;
+
+ if (cmd == SOUND_MIXER_INFO) {
+ mixer_info info;
+ memset(&info, 0, sizeof(info));
+ strncpy(info.id, "harmony", sizeof(info.id)-1);
+ strncpy(info.name, "Harmony audio", sizeof(info.name)-1);
+ info.modify_counter = 1; /* ? */
+ if (copy_to_user((void *)arg, &info, sizeof(info)))
+ return -EFAULT;
+ return 0;
+ }
+
+ if (cmd == OSS_GETVERSION)
+ return put_user(SOUND_VERSION, (int *)arg);
+
+ /* read */
+ val = 0;
+ if (_SIOC_DIR(cmd) & _SIOC_WRITE)
+ if (get_user(val, (int *)arg))
+ return -EFAULT;
+
+ switch (cmd) {
+ case MIXER_READ(SOUND_MIXER_CAPS):
+ ret = SOUND_CAP_EXCL_INPUT;
+ break;
+ case MIXER_READ(SOUND_MIXER_STEREODEVS):
+ ret = SOUND_MASK_IGAIN | SOUND_MASK_OGAIN;
+ break;
+
+ case MIXER_READ(SOUND_MIXER_RECMASK):
+ ret = SOUND_MASK_MIC | SOUND_MASK_LINE;
+ break;
+ case MIXER_READ(SOUND_MIXER_DEVMASK):
+ ret = SOUND_MASK_OGAIN | SOUND_MASK_IGAIN |
+ SOUND_MASK_VOLUME;
+ break;
+ case MIXER_READ(SOUND_MIXER_OUTMASK):
+ ret = SOUND_MASK_SPEAKER | SOUND_MASK_LINE |
+ SOUND_MASK_PHONEOUT;
+ break;
+
+ case MIXER_WRITE(SOUND_MIXER_RECSRC):
+ ret = harmony_mixer_set_recmask(val);
+ break;
+ case MIXER_READ(SOUND_MIXER_RECSRC):
+ ret = harmony_mixer_get_recmask();
+ break;
+
+ case MIXER_WRITE(SOUND_MIXER_OUTSRC):
+ ret = harmony_mixer_set_outmask(val);
+ break;
+ case MIXER_READ(SOUND_MIXER_OUTSRC):
+ ret = harmony_mixer_get_outmask();
+ break;
+
+ case MIXER_WRITE(SOUND_MIXER_OGAIN):
+ case MIXER_WRITE(SOUND_MIXER_IGAIN):
+ case MIXER_WRITE(SOUND_MIXER_VOLUME):
+ ret = harmony_mixer_set_level(cmd & 0xff, val);
+ break;
+
+ case MIXER_READ(SOUND_MIXER_OGAIN):
+ case MIXER_READ(SOUND_MIXER_IGAIN):
+ case MIXER_READ(SOUND_MIXER_VOLUME):
+ ret = harmony_mixer_get_level(cmd & 0xff);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ if (put_user(ret, (int *)arg))
+ return -EFAULT;
+ return 0;
+}
+
+
+static int harmony_mixer_open(struct inode *inode, struct file *file)
+{
+ if (harmony.mixer_open)
+ return -EBUSY;
+ harmony.mixer_open++;
+ return 0;
+}
+
+static int harmony_mixer_release(struct inode *inode, struct file *file)
+{
+ if (!harmony.mixer_open)
+ return -EBUSY;
+ harmony.mixer_open--;
+ return 0;
+}
+
+static struct file_operations harmony_mixer_fops = {
+ owner: THIS_MODULE,
+ llseek: no_llseek,
+ open: harmony_mixer_open,
+ release: harmony_mixer_release,
+ ioctl: harmony_mixer_ioctl,
+};
+
+
+/*
+ * Mute all the output and reset Harmony.
+ */
+
+static void __init harmony_mixer_reset(void)
+{
+ harmony.current_gain = GAIN_TOTAL_SILENCE;
+ harmony_mixer_set_gain();
+ harmony_wait_CNTL();
+ gsc_writel(1, &harmony.hpa->reset);
+ mdelay(50); /* wait 50 ms */
+ gsc_writel(0, &harmony.hpa->reset);
+ harmony.current_gain = GAIN_DEFAULT;
+ harmony_mixer_set_gain();
+}
+
+static int __init harmony_mixer_init(void)
+{
+ /* Register the device file operations */
+ harmony.mixer_unit = register_sound_mixer(&harmony_mixer_fops, -1);
+ if (harmony.mixer_unit < 0) {
+ printk(KERN_WARNING PFX "Error Registering Mixer Driver\n");
+ return -EFAULT;
+ }
+
+ harmony_mixer_reset();
+ harmony.mixer_open = 0;
+
+ return 0;
+}
+
+
+
+/*
+ * This is the callback that's called by the inventory hardware code
+ * if it finds a match to the registered driver.
+ */
+static int __init
+harmony_driver_callback(struct parisc_device *dev)
+{
+ u8 id;
+ u8 rev;
+ u32 cntl;
+ int ret;
+
+ if (harmony.hpa) {
+ /* We only support one Harmony at this time */
+ printk(KERN_ERR PFX "driver already registered\n");
+ return -EBUSY;
+ }
+
+ /* Set the HPA of harmony */
+ harmony.hpa = (struct harmony_hpa *)dev->hpa;
+
+ harmony.irq = dev->irq;
+ if (!harmony.irq) {
+ printk(KERN_ERR PFX "no irq found\n");
+ return -ENODEV;
+ }
+
+ /* Grab the ID and revision from the device */
+ id = gsc_readb(&harmony.hpa->id);
+ if ((id | 1) != 0x15) {
+ printk(KERN_WARNING PFX "wrong harmony id 0x%02x\n", id);
+ return -EBUSY;
+ }
+ cntl = gsc_readl(&harmony.hpa->cntl);
+ rev = (cntl>>20) & 0xff;
+
+ printk(KERN_INFO "Lasi Harmony Audio driver " HARMONY_VERSION ", "
+ "h/w id %i, rev. %i at 0x%lx, IRQ %i\n",
+ id, rev, dev->hpa, harmony.irq);
+
+ /* Make sure the control bit isn't set, although I don't think it
+ ever is. */
+ if (cntl & CNTL_C) {
+ printk(KERN_WARNING PFX "CNTL busy\n");
+ harmony.hpa = 0;
+ return -EBUSY;
+ }
+
+ /* a fake pci_dev is needed for pci_* functions under ccio */
+ harmony.fake_pci_dev = ccio_get_fake(dev);
+
+ /* Initialize the memory buffers */
+ if (harmony_alloc_buffer(&played_buf, MAX_BUFS) ||
+ harmony_alloc_buffer(&recorded_buf, MAX_BUFS) ||
+ harmony_alloc_buffer(&graveyard, 1) ||
+ harmony_alloc_buffer(&silent, 1)) {
+ ret = -EBUSY;
+ goto out_err;
+ }
+
+ /* Initialize /dev/mixer and /dev/audio */
+ if ((ret=harmony_mixer_init()))
+ goto out_err;
+ if ((ret=harmony_audio_init()))
+ goto out_err;
+
+ return 0;
+
+out_err:
+ harmony.hpa = 0;
+ harmony_free_buffer(&played_buf);
+ harmony_free_buffer(&recorded_buf);
+ harmony_free_buffer(&graveyard);
+ harmony_free_buffer(&silent);
+ return ret;
+}
+
+
+static struct parisc_device_id harmony_tbl[] = {
+ /* { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007A }, Bushmaster/Flounder */
+ { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007B }, /* 712/715 Audio */
+ { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007E }, /* Pace Audio */
+ { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007F }, /* Outfield / Coral II */
+ { 0, }
+};
+
+MODULE_DEVICE_TABLE(parisc, harmony_tbl);
+
+static struct parisc_driver harmony_driver = {
+ name: "Lasi Harmony",
+ id_table: harmony_tbl,
+ probe: harmony_driver_callback,
+};
+
+static int __init init_harmony(void)
+{
+ return register_parisc_driver(&harmony_driver);
+}
+
+static void __exit cleanup_harmony(void)
+{
+ free_irq(harmony.irq, &harmony);
+ unregister_sound_mixer(harmony.mixer_unit);
+ unregister_sound_dsp(harmony.dsp_unit);
+ harmony_free_buffer(&played_buf);
+ harmony_free_buffer(&recorded_buf);
+ harmony_free_buffer(&graveyard);
+ harmony_free_buffer(&silent);
+ unregister_parisc_driver(&harmony_driver);
+}
+
+EXPORT_NO_SYMBOLS;
+
+MODULE_AUTHOR("Alex DeVries <alex@linuxcare.com>");
+MODULE_DESCRIPTION("Harmony sound driver");
+MODULE_LICENSE("GPL");
+
+module_init(init_harmony);
+module_exit(cleanup_harmony);
+
diff --git a/sound/oss/kahlua.c b/sound/oss/kahlua.c
new file mode 100644
index 000000000000..f8b37cb88116
--- /dev/null
+++ b/sound/oss/kahlua.c
@@ -0,0 +1,227 @@
+/*
+ * Initialisation code for Cyrix/NatSemi VSA1 softaudio
+ *
+ * (C) Copyright 2003 Red Hat Inc <alan@redhat.com>
+ *
+ * XpressAudio(tm) is used on the Cyrix MediaGX (now NatSemi Geode) systems.
+ * The older version (VSA1) provides fairly good soundblaster emulation
+ * although there are a couple of bugs: large DMA buffers break record,
+ * and the MPU event handling seems suspect. VSA2 allows the native driver
+ * to control the AC97 audio engine directly and requires a different driver.
+ *
+ * Thanks to National Semiconductor for providing the needed information
+ * on the XpressAudio(tm) internals.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * TO DO:
+ * Investigate whether we can portably support Cognac (5520) in the
+ * same manner.
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+
+#include "sound_config.h"
+
+#include "sb.h"
+
+/*
+ * Read a soundblaster compatible mixer register.
+ * In this case we are actually reading an SMI trap
+ * not real hardware.
+ */
+
+static u8 __devinit mixer_read(unsigned long io, u8 reg)
+{
+ outb(reg, io + 4);
+ udelay(20);
+ reg = inb(io + 5);
+ udelay(20);
+ return reg;
+}
+
+static int __devinit probe_one(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ struct address_info *hw_config;
+ unsigned long base;
+ void *mem;
+ unsigned long io;
+ u16 map;
+ u8 irq, dma8, dma16;
+ int oldquiet;
+ extern int sb_be_quiet;
+
+ base = pci_resource_start(pdev, 0);
+ if(base == 0UL)
+ return 1;
+
+ mem = ioremap(base, 128);
+ if(mem == 0UL)
+ return 1;
+ map = readw(mem + 0x18); /* Read the SMI enables */
+ iounmap(mem);
+
+ /* Map bits
+ 0:1 * 0x20 + 0x200 = sb base
+ 2 sb enable
+ 3 adlib enable
+ 5 MPU enable 0x330
+ 6 MPU enable 0x300
+
+ The other bits may be used internally so must be masked */
+
+ io = 0x220 + 0x20 * (map & 3);
+
+ if(map & (1<<2))
+ printk(KERN_INFO "kahlua: XpressAudio at 0x%lx\n", io);
+ else
+ return 1;
+
+ if(map & (1<<5))
+ printk(KERN_INFO "kahlua: MPU at 0x300\n");
+ else if(map & (1<<6))
+ printk(KERN_INFO "kahlua: MPU at 0x330\n");
+
+ irq = mixer_read(io, 0x80) & 0x0F;
+ dma8 = mixer_read(io, 0x81);
+
+ // printk("IRQ=%x MAP=%x DMA=%x\n", irq, map, dma8);
+
+ if(dma8 & 0x20)
+ dma16 = 5;
+ else if(dma8 & 0x40)
+ dma16 = 6;
+ else if(dma8 & 0x80)
+ dma16 = 7;
+ else
+ {
+ printk(KERN_ERR "kahlua: No 16bit DMA enabled.\n");
+ return 1;
+ }
+
+ if(dma8 & 0x01)
+ dma8 = 0;
+ else if(dma8 & 0x02)
+ dma8 = 1;
+ else if(dma8 & 0x08)
+ dma8 = 3;
+ else
+ {
+ printk(KERN_ERR "kahlua: No 8bit DMA enabled.\n");
+ return 1;
+ }
+
+ if(irq & 1)
+ irq = 9;
+ else if(irq & 2)
+ irq = 5;
+ else if(irq & 4)
+ irq = 7;
+ else if(irq & 8)
+ irq = 10;
+ else
+ {
+ printk(KERN_ERR "kahlua: SB IRQ not set.\n");
+ return 1;
+ }
+
+ printk(KERN_INFO "kahlua: XpressAudio on IRQ %d, DMA %d, %d\n",
+ irq, dma8, dma16);
+
+ hw_config = kmalloc(sizeof(struct address_info), GFP_KERNEL);
+ if(hw_config == NULL)
+ {
+ printk(KERN_ERR "kahlua: out of memory.\n");
+ return 1;
+ }
+ memset(hw_config, 0, sizeof(*hw_config));
+
+ pci_set_drvdata(pdev, hw_config);
+
+ hw_config->io_base = io;
+ hw_config->irq = irq;
+ hw_config->dma = dma8;
+ hw_config->dma2 = dma16;
+ hw_config->name = "Cyrix XpressAudio";
+ hw_config->driver_use_1 = SB_NO_MIDI | SB_PCI_IRQ;
+
+ if(sb_dsp_detect(hw_config, 0, 0, NULL)==0)
+ {
+ printk(KERN_ERR "kahlua: audio not responding.\n");
+ goto err_out_free;
+ }
+
+ oldquiet = sb_be_quiet;
+ sb_be_quiet = 1;
+ if(sb_dsp_init(hw_config, THIS_MODULE))
+ {
+ sb_be_quiet = oldquiet;
+ goto err_out_free;
+ }
+ sb_be_quiet = oldquiet;
+
+ return 0;
+
+err_out_free:
+ pci_set_drvdata(pdev, NULL);
+ kfree(hw_config);
+ return 1;
+}
+
+static void __devexit remove_one(struct pci_dev *pdev)
+{
+ struct address_info *hw_config = pci_get_drvdata(pdev);
+ sb_dsp_unload(hw_config, 0);
+ pci_set_drvdata(pdev, NULL);
+ kfree(hw_config);
+}
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("Kahlua VSA1 PCI Audio");
+MODULE_LICENSE("GPL");
+
+/*
+ * 5530 only. The 5510/5520 decode is different.
+ */
+
+static struct pci_device_id id_tbl[] __devinitdata = {
+ { PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_AUDIO, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { }
+};
+
+MODULE_DEVICE_TABLE(pci, id_tbl);
+
+static struct pci_driver kahlua_driver = {
+ name: "kahlua",
+ id_table: id_tbl,
+ probe: probe_one,
+ remove: __devexit_p(remove_one),
+};
+
+
+static int __init kahlua_init_module(void)
+{
+ printk(KERN_INFO "Cyrix Kahlua VSA1 XpressAudio support (c) Copyright 2003 Red Hat Inc\n");
+ return pci_module_init(&kahlua_driver);
+}
+
+static void __devexit kahlua_cleanup_module(void)
+{
+ return pci_unregister_driver(&kahlua_driver);
+}
+
+
+module_init(kahlua_init_module);
+module_exit(kahlua_cleanup_module);
+