S: San Jose, California 95131
S: USA
+N: Fernando Fuganti
+E: fuganti@conectiva.com.br
+E: fuganti@netbank.com.br
+D: random kernel hacker, ZF MachZ Watchdog driver
+S: Conectiva S.A.
+S: R. Tocantins, 89 - Cristo Rei
+S: 80050-430 - Curitiba - ParanĂ¡
+S: Brazil
+
N: Nigel Gamble
E: nigel@nrg.org
E: nigel@sgi.com
+
LINUX ALLOCATED DEVICES
Maintained by H. Peter Anvin <device@lanana.org>
- Last revised: December 29, 2000
+ Last revised: 3 June 2001
This list is the Linux Device List, the official registry of allocated
device numbers and /dev directory nodes for the Linux operating
system.
-The latest version of this list is included with the Linux kernel
-sources. It is also available separately from
-http://www.kernel.org/pub/linux/docs/device-list/ or
-ftp://ftp.kernel.org/pub/linux/docs/device-list/. The LaTeX version
-of this document is no longer maintained.
+The latest version of this list is available from
+http://www.lanana.org/docs/device-list/ or
+ftp://ftp.kernel.org/pub/linux/docs/device-list/. This version may be
+newer than the one distributed with the Linux kernel.
+
+The LaTeX version of this document is no longer maintained.
This document is included by reference into the Filesystem Hierarchy
Standard (FHS). The FHS is available from http://www.pathname.com/fhs/.
**** DEVICE DRIVERS AUTHORS PLEASE READ THIS ****
+THE DEVICE REGISTRY IS OFFICIALLY FROZEN FOR LINUS TORVALDS' KERNEL
+TREE. At Linus' request, no more allocations will be made official
+for Linus' kernel tree; the 3 June 2001 version of this list is the
+official final version of this registry. At Alan Cox' request,
+however, the registry will continue to be maintained for the -ac
+series of kernels, and registrations will be accepted.
+
To have a major number allocated, or a minor number in situations
where that applies (e.g. busmice), please contact me with the
appropriate device information. Also, if you have additional
199 = /dev/scanners/cuecat :CueCat barcode scanner
200 = /dev/net/tun TAP/TUN network device
201 = /dev/button/gulpb Transmeta GULP-B buttons
- 204 = /dev/video/em8300 EM8300 DVD decoder control
- 205 = /dev/video/em8300_mv EM8300 DVD decoder video
- 206 = /dev/video/em8300_ma EM8300 DVD decoder audio
- 207 = /dev/video/em8300_sp EM8300 DVD decoder subpicture
- 208 = /dev/compaq/cpqphpc Compaq PCI Hot Plug Controller
- 209 = /dev/compaq/cpqrid Compaq Remote Insight Driver
+ 204 = /dev/video/em8300 EM8300 DVD decoder control
+ 205 = /dev/video/em8300_mv EM8300 DVD decoder video
+ 206 = /dev/video/em8300_ma EM8300 DVD decoder audio
+ 207 = /dev/video/em8300_sp EM8300 DVD decoder subpicture
+ 208 = /dev/compaq/cpqphpc Compaq PCI Hot Plug Controller
+ 209 = /dev/compaq/cpqrid Compaq Remote Insight Driver
+ 210 = /dev/impi/bt IMPI coprocessor block transfer
+ 211 = /dev/impi/smic IMPI coprocessor stream interface
+ 212 = /dev/watchdogs/0 First watchdog device
+ 213 = /dev/watchdogs/1 Second watchdog device
+ 214 = /dev/watchdogs/2 Third watchdog device
+ 215 = /dev/watchdogs/3 Fourth watchdog device
+ 216 = /dev/fujitsu/apanel Fujitsu/Siemens application panel
+ 217 = /dev/ni/natmotn National Instruments Motion
+ 218 = /dev/kchuid Inter-process chuid control
+ 219 = /dev/modems/mwave MWave modem firmware upload
+ 220 = /dev/mptctl Message passing technology (MPT) control
+ 221 = /dev/mvista/hssdsi Montavista PICMG hot swap system driver
+ 222 = /dev/mvista/hasi Montavista PICMG high availability
240-255 Reserved for local use
11 char Raw keyboard device
1 = /dev/dos_cd1 Second MSCDEX CD-ROM
...
- 13 char PC speaker (OBSOLETE)
- 0 = /dev/pcmixer Emulates /dev/mixer
- 1 = /dev/pcsp Emulates /dev/dsp (8-bit)
- 4 = /dev/pcaudio Emulates /dev/audio
- 5 = /dev/pcsp16 Emulates /dev/dsp (16-bit)
+ 13 char Input core
+ 0 = /dev/input/js0 First joystick
+ 1 = /dev/input/js1 Second joystick
+ ...
+ 32 = /dev/input/mouse0 First mouse
+ 33 = /dev/input/mouse1 Second mouse
+ ...
+ 63 = /dev/input/mice Unified mouse
+ 64 = /dev/input/event0 First event queue
+ 65 = /dev/input/event1 Second event queue
+ ...
- The current PC speaker driver uses the Open Sound
- System interface, and these devices are obsolete.
+ Each device type has 5 bits (32 minors).
block 8-bit MFM/RLL/IDE controller
0 = /dev/xda First XT disk whole disk
...
31 = /dev/fb31 32nd frame buffer
- Backward compatibility aliases {2.6}
-
- 32 = /dev/fb1 Second frame buffer
+ For backwards compatibility {2.6} the following
+ progression is also handled by current kernels:
+ 0 = /dev/fb0
+ 32 = /dev/fb1
...
- 224 = /dev/fb7 Eighth frame buffer
-
- All additional minor numbers are reserved.
+ 224 = /dev/fb7
block Aztech/Orchid/Okano/Wearnes CD-ROM
0 = /dev/aztcd Aztech CD-ROM
0 = /dev/rd/c0d0 First disk, whole disk
8 = /dev/rd/c0d1 Second disk, whole disk
...
- 248 = /dev/rd/c0d15 16th disk, whole disk
+ 248 = /dev/rd/c0d15 32nd disk, whole disk
For partitions add:
0 = /dev/rd/c?d? Whole disk
0 = /dev/rd/c1d0 First disk, whole disk
8 = /dev/rd/c1d1 Second disk, whole disk
...
- 248 = /dev/rd/c1d15 16th disk, whole disk
+ 248 = /dev/rd/c1d31 32nd disk, whole disk
Partitions are handled as for major 48.
0 = /dev/rd/c2d0 First disk, whole disk
8 = /dev/rd/c2d1 Second disk, whole disk
...
- 248 = /dev/rd/c2d15 16th disk, whole disk
+ 248 = /dev/rd/c2d31 32nd disk, whole disk
51 char Baycom radio modem
0 = /dev/bc0 First Baycom radio modem
0 = /dev/rd/c3d0 First disk, whole disk
8 = /dev/rd/c3d1 Second disk, whole disk
...
- 248 = /dev/rd/c3d15 16th disk, whole disk
+ 248 = /dev/rd/c3d31 32nd disk, whole disk
Partitions are handled as for major 48.
0 = /dev/rd/c4d0 First disk, whole disk
8 = /dev/rd/c4d1 Second disk, whole disk
...
- 248 = /dev/rd/c4d15 16th disk, whole disk
+ 248 = /dev/rd/c4d31 32nd disk, whole disk
Partitions are handled as for major 48.
0 = /dev/rd/c5d0 First disk, whole disk
8 = /dev/rd/c5d1 Second disk, whole disk
...
- 248 = /dev/rd/c5d15 16th disk, whole disk
+ 248 = /dev/rd/c5d31 32nd disk, whole disk
Partitions are handled as for major 48.
0 = /dev/rd/c6d0 First disk, whole disk
8 = /dev/rd/c6d1 Second disk, whole disk
...
- 248 = /dev/rd/c6d15 16th disk, whole disk
+ 248 = /dev/rd/c6d31 32nd disk, whole disk
Partitions are handled as for major 48.
0 = /dev/rd/c7d0 First disk, whole disk
8 = /dev/rd/c7d1 Second disk, whole disk
...
- 248 = /dev/rd/c7d15 16th disk, whole disk
+ 248 = /dev/rd/c7d31 32nd disk, whole disk
Partitions are handled as for major 48.
Partitions are handled the same way as for the first
interface (see major number 3).
-
89 char I2C bus interface
0 = /dev/i2c-0 First I2C adapter
1 = /dev/i2c-1 Second I2C adapter
1 = /dev/dcxx1 Second capture card
...
+ block IBM S/390 DASD block storage
+ 0 = /dev/dasda First DASD device, major
+ 1 = /dev/dasda1 First DASD device, block 1
+ 2 = /dev/dasda2 First DASD device, block 2
+ 3 = /dev/dasda3 First DASD device, block 3
+ 4 = /dev/dasdb Second DASD device, major
+ 5 = /dev/dasdb1 Second DASD device, block 1
+ 6 = /dev/dasdb2 Second DASD device, block 2
+ 7 = /dev/dasdb3 Second DASD device, block 3
+ ...
+
95 char IP filter
0 = /dev/ipl Filter control device/log file
1 = /dev/ipnat NAT control device/log file
2 = /dev/ipstate State information log file
3 = /dev/ipauth Authentication control device/log file
-
- block IBM S/390 DASD block storage
- 0 = /dev/dasd0 First DASD device, major
- 1 = /dev/dasd0a First DASD device, block 1
- 2 = /dev/dasd0b First DASD device, block 2
- 3 = /dev/dasd0c First DASD device, block 3
- 4 = /dev/dasd1 Second DASD device, major
- 5 = /dev/dasd1a Second DASD device, block 1
- 6 = /dev/dasd1b Second DASD device, block 2
- 7 = /dev/dasd1c Second DASD device, block 3
...
+ block IBM S/390 VM/ESA minidisk
+ 0 = /dev/mnda First VM/ESA minidisk
+ 1 = /dev/mndb Second VM/ESA minidisk
+ ...
+
96 char Parallel port ATAPI tape devices
0 = /dev/pt0 First parallel port ATAPI tape
1 = /dev/pt1 Second parallel port ATAPI tape
129 = /dev/npt1 Second p.p. ATAPI tape, no rewind
...
- block IBM S/390 VM/ESA minidisk
- 0 = /dev/msd0 First VM/ESA minidisk
- 1 = /dev/msd1 Second VM/ESA minidisk
- ...
-
97 char Parallel port generic ATAPI interface
0 = /dev/pg0 First parallel port ATAPI device
1 = /dev/pg1 Second parallel port ATAPI device
2 = /dev/tlk2 Third Teletext decoder
3 = /dev/tlk3 Fourth Teletext decoder
+ block Compressed block device
+ 0 = /dev/cbd/a First compressed block device, whole device
+ 16 = /dev/cbd/b Second compressed block device, whole device
+ ...
+ 240 = /dev/cbd/p 16th compressed block device, whole device
+
+ Partitions are handled in the same way as for IDE
+ disks (see major number 3) except that the limit on
+ partitions is 15.
+
103 char Arla network file system
0 = /dev/xfs0 Arla XFS
There is currently a device-naming conflict between
these and PAM multimodems (major 78).
+ block IBM iSeries virtual disk
+ 0 = /dev/iseries/vda First virtual disk, whole disk
+ 8 = /dev/iseries/vdb Second virtual disk, whole disk
+ ...
+ 200 = /dev/iseries/vdz 26th virtual disk, whole disk
+ 208 = /dev/iseries/vdaa 27th virtual disk, whole disk
+ ...
+ 240 = /dev/iseries/vdaf 32nd virtual disk, whole disk
+
+ Partitions are handled in the same way as for IDE
+ disks (see major number 3) except that the limit on
+ partitions is 7.
+
113 char ISI serial card - alternate devices
0 = /dev/cum0 Callout device for ttyM0
1 = /dev/cum1 Callout device for ttyM1
...
+ block IBM iSeries virtual CD-ROM
+
+ 0 = /dev/iseries/vcda First virtual CD-ROM
+ 1 = /dev/iseries/vcdb Second virtual CD-ROM
+ ...
+
114 char Picture Elements ISE board
0 = /dev/ise0 First ISE board
1 = /dev/ise1 Second ISE board
...
162 char Raw block device interface
- 0 = /dev/raw Raw I/O control device
- 1 = /dev/raw1 First raw I/O device
- 2 = /dev/raw2 Second raw I/O device
+ 0 = /dev/rawctl Raw I/O control device
+ 1 = /dev/raw/raw1 First raw I/O device
+ 2 = /dev/raw/raw2 Second raw I/O device
...
163 char Radio Tech BIM-XXX-RS232 radio modem
...
255 = /dev/nvidiactl Nvidia card control device
-196-197 UNASSIGNED
+196 char Tormenta T1 card
+ 0 = /dev/tor/0 Master control channel for all cards
+ 1 = /dev/tor/1 First DS0
+ 2 = /dev/tor/2 Second DS0
+ ...
+ 48 = /dev/tor/48 48th DS0
+ 49 = /dev/tor/49 First pseudo-channel
+ 50 = /dev/tor/50 Second pseudo-channel
+ ...
+
+197 char OpenTNF tracing facility
+ 0 = /dev/tnf/t0 Trace 0 data extraction
+ 1 = /dev/tnf/t1 Trace 1 data extraction
+ ...
+ 128 = /dev/tnf/status Tracing facility status
+ 130 = /dev/tnf/trace Tracing device
198 char Total Impact TPMP2 quad coprocessor PCI card
0 = /dev/tpmp2/0 First card
16 = /dev/ttyAM0 ARM "AMBA" serial port 0
...
31 = /dev/ttyAM15 ARM "AMBA" serial port 15
+ 32 = /dev/ttyDB0 DataBooster serial port 0
+ ...
+ 39 = /dev/ttyDB7 DataBooster serial port 7
205 char Low-density serial ports (alternate device)
0 = /dev/culu0 Callout device for ttyLU0
16 = /dev/cuam0 Callout device for ttyAM0
...
31 = /dev/cuam15 Callout device for ttyAM15
+ 32 = /dev/cudb0 Callout device for ttyDB0
+ ...
+ 39 = /dev/cudb7 Callout device for ttyDB7
206 char OnStream SC-x0 tape devices
0 = /dev/osst0 First OnStream SCSI tape, mode 0
1 = /dev/cuy1 Callout device for ttyY1
...
-226-239 UNASSIGNED
+226 char Direct Rendering Infrastructure (DRI)
+ 0 = /dev/dri/card0 First graphics card
+ 1 = /dev/dri/card1 Second graphics card
+ ...
+
+227 char IBM 3270 terminal block-mode access
+ 0 = /dev/3270/tub Controlling interface
+ 1 = /dev/3270/tub1 First 3270 terminal
+ 2 = /dev/3270/tub2 Second 3270 terminal
+ ...
+
+228 char IBM 3270 terminal Unix tty access
+ 1 = /dev/3270/tty1 First 3270 terminal
+ 2 = /dev/3270/tty2 Seconds 3270 terminal
+ ...
+
+229 char IBM iSeries virtual console
+ 0 = /dev/iseries/vtty0 First console port
+ 1 = /dev/iseries/vtty1 Second console port
+ ...
+
+230 char IBM iSeries virtual tape
+ 0 = /dev/iseries/vt0 First virtual tape, mode 0
+ 1 = /dev/iseries/vt1 Second virtual tape, mode 0
+ ...
+ 32 = /dev/iseries/vt0l First virtual tape, mode 1
+ 33 = /dev/iseries/vt1l Second virtual tape, mode 1
+ ...
+ 64 = /dev/iseries/vt0m First virtual tape, mode 2
+ 65 = /dev/iseries/vt1m Second virtual tape, mode 2
+ ...
+ 96 = /dev/iseries/vt0a First virtual tape, mode 3
+ 97 = /dev/iseries/vt1a Second virtual tape, mode 3
+ ...
+ 128 = /dev/iseries/nvt0 First virtual tape, mode 0, no rewind
+ 129 = /dev/iseries/nvt1 Second virtual tape, mode 0, no rewind
+ ...
+ 160 = /dev/iseries/nvt0l First virtual tape, mode 1, no rewind
+ 161 = /dev/iseries/nvt1l Second virtual tape, mode 1, no rewind
+ ...
+ 192 = /dev/iseries/nvt0m First virtual tape, mode 2, no rewind
+ 193 = /dev/iseries/nvt1m Second virtual tape, mode 2, no rewind
+ ...
+ 224 = /dev/iseries/nvt0a First virtual tape, mode 3, no rewind
+ 225 = /dev/iseries/nvt1a Second virtual tape, mode 3, no rewind
+ ...
+
+ "No rewind" refers to the omission of the default
+ automatic rewind on device close. The MTREW or MTOFFL
+ ioctl()'s can be used to rewind the tape regardless of
+ the device used to access it.
+
+231-239 UNASSIGNED
240-254 LOCAL/EXPERIMENTAL USE
in our notation). This removes the problem of exhausting the
namespace and enables the kernel to automatically create the device
nodes for the slaves on demand using the "devpts" filesystem.
+
+++ /dev/null
-
-The current state of Linux/PA-RISC mm is BROKEN.
-
-Someone needs to sit down and thoroughly rewrite all the cache flushing
-macro definitions. Here are some of the problems, followed by what I
-think needs to be done about them.
-
-(1) We're using fdce / fice everywhere. This has to stop (except in
-the routines which flush the entire cache). The right instructions to
-be using are fdc/fic.
-
-(2) fdc/fic will throw exceptions if the address they reference isn't
-mapped. Therefore we need to check the page is mapped before flushing
-(we're guaranteed not to have the page dirty if we don't have a software
-mapping for it any longer, right?)
-
-(3) the flush macros are right now tunnelled down to one routine to flush
-the data cache and one routine to flush the insn cache. this is wrong.
-we should take hints from how we're called and optimise our routines
-accordingly.
-
-(4) fdc/fic actually take space register arguments. fic takes an 3-bit sr
-argument and fdc takes a 2-bit sr argument. right now, there's a lot of
-pissing about with %sr1 and all the macros use %sr1. This is crazy. We
-normally _know_ what's being referred to, and it's the current task. So
-if we want to flush that, just use %sr3. If it happens to be kernel,
-use %sr0 for fdc and %sr4 for fic.
-
-(5) we need to write flush_kernel_dcache_range and use it on kernel
-addresses. all the macros are defined to work on the _current task's_
-virtual address space.
This file contains some additional information for the Philips webcams.
-E-mail: webcam@smcc.demon.nl Last updated: 2001-04-25
+E-mail: webcam@smcc.demon.nl Last updated: 2001-07-27
The main webpage for the Philips driver is http://www.smcc.demon.nl/webcam/.
It contains a lot of extra information, a FAQ, and the binary plugin
palette
Specifies the desired colour order that should be delivered by read() and
- mmap(). The string can be one of bgr24, rgb24, rgb32, bgr32, yuyv,
- yuv420, yuv420p. If the tool you use produces odd colours (more
- specificly, red and blue are swapped), try palette=bgr24 or
- palette=rgb24.
+ mmap(). The string can be one of yuv420 or yuv420p; however, yuv420 will
+ be phased out, leaving only yuv420p, so this option will disappear
+ entirely.
Only the native yuv420/yuv420p format is supported by the in kernel driver.
If you want to use other formats with in-kernel conversion download the
compression (only useful with the plugin)
With this option you can control the compression factor that the camera
- use to squeeze the image through the USB bus. You can set the
+ uses to squeeze the image through the USB bus. You can set the
parameter between 0 and 3:
0 = prefer uncompressed images; if the requested mode is not available
in an uncompressed format, the driver will silently switch to low
3 = high compression.
High compression takes less bandwidth of course, but it could also
- introduce some unwanted artefacts. The default is 2, medium compression.
+ introduce some unwanted artefacts. The default is 2, medium compression.
See the FAQ on the website for an overview of which modes require
compression.
The 645 and 646 have fixed compression parameters.
trace
-
In order to better detect problems, it is now possible to turn on a
'trace' of some of the calls the module makes; it logs all items in your
kernel log at debug level.
L: linux-kernel@vger.kernel.org
S: Maintained
+BLUETOOTH SUBSYSTEM (BlueZ)
+P: Maxim Krasnyansky
+M: maxk@qualcomm.com
+W: http://bluez.sf.net
+S: Maintained
+
BTTV VIDEO4LINUX DRIVER
P: Gerd Knorr
M: kraxel@goldbach.in-berlin.de
L: linux-kernel@vger.kernel.org
S: Maintained
+FARSYNC SYNCHRONOUS DRIVER
+P: Bob Dunlop
+M: rjd@xyzzy.clara.co.uk
+M: bob.dunlop@farsite.co.uk
+W: http://www.farsite.co.uk/
+S: Supported
+
FILE LOCKING (flock() and fcntl()/lockf())
P: Matthew Wilcox
M: matthew@wil.cx
IDE DRIVER [GENERAL]
P: Andre Hedrick
M: andre@linux-ide.org
-M: ahedrick@atipa.com
+M: andre@aslab.com
M: andre@suse.com
L: linux-kernel@vger.kernel.org
W: http://www.kernel.org/pub/linux/kernel/people/hedrick/
L: linux1394-devel@lists.sourceforge.net
S: Maintained
+IMS TWINTURBO FRAMEBUFFER DRIVER
+P: Paul Mundt
+M: lethal@chaoticdreams.org
+L: linux-fbdev-devel@lists.sourceforge.net
+S: Maintained
+
INTEL APIC/IOAPIC, LOWLEVEL X86 SMP SUPPORT
P: Ingo Molnar
M: mingo@redhat.com
L: linux-hams@vger.kernel.org
S: Maintained
+ZF MACHZ WATCHDOG
+P: Fernando Fuganti
+M: fuganti@conectiva.com.br
+M: fuganti@netbank.com.br
+W: http://cvs.conectiva.com.br/drivers/ZFL-watchdog/
+S: Maintained
+
ZR36120 VIDEO FOR LINUX DRIVER
P: Pauline Middelink
M: middelin@polyware.nl
W: http://www.polyware.nl/~middelin/hobbies.html
S: Maintained
-Bluetooth Subsystem (BlueZ)
-P: Maxim Krasnyansky
-M: maxk@qualcomm.com
-W: http://bluez.sf.net
-S: Maintained
-
THE REST
P: Linus Torvalds
S: Buried alive in reporters
VERSION = 2
PATCHLEVEL = 4
SUBLEVEL = 9
-EXTRAVERSION =-pre1
+EXTRAVERSION =-pre2
KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
"$CONFIG_ARCH_INTEGRATOR" = "y" -o \
"$CONFIG_ARCH_TBOX" = "y" -o \
"$CONFIG_ARCH_CLPS7500" = "y" -o \
- "$CONFIG_ARCH_P720T" = "y" -o \
- "$CONFIG_ARCH_ANAKIN" = "y" ]; then
+ "$CONFIG_ARCH_P720T" = "y" -o \
+ "$CONFIG_ARCH_ANAKIN" = "y" ]; then
define_bool CONFIG_PC_KEYMAP y
fi
if [ "$CONFIG_ARCH_ACORN" != "y" -a "$CONFIG_ARCH_EBSA110" != "y" ]; then
--- /dev/null
+#
+# Automatically generated by make menuconfig: don't edit
+#
+CONFIG_ARM=y
+# CONFIG_EISA is not set
+# CONFIG_SBUS is not set
+# CONFIG_MCA is not set
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+# CONFIG_OBSOLETE is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODVERSIONS is not set
+CONFIG_KMOD=y
+
+#
+# System Type
+#
+# CONFIG_ARCH_ARCA5K is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_RPC is not set
+CONFIG_ARCH_SA1100=y
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_ANAKIN is not set
+
+#
+# Archimedes/A5000 Implementations
+#
+# CONFIG_ARCH_ARC is not set
+# CONFIG_ARCH_A5K is not set
+
+#
+# Footbridge Implementations
+#
+# CONFIG_ARCH_CATS is not set
+# CONFIG_ARCH_PERSONAL_SERVER is not set
+# CONFIG_ARCH_EBSA285_ADDIN is not set
+# CONFIG_ARCH_EBSA285_HOST is not set
+# CONFIG_ARCH_NETWINDER is not set
+
+#
+# SA11x0 Implementations
+#
+# CONFIG_SA1100_ASSABET is not set
+# CONFIG_ASSABET_NEPONSET is not set
+# CONFIG_SA1100_BRUTUS is not set
+# CONFIG_SA1100_CERF is not set
+# CONFIG_SA1100_BITSY is not set
+# CONFIG_SA1100_EXTENEX1 is not set
+# CONFIG_SA1100_FLEXANET is not set
+# CONFIG_SA1100_FREEBIRD is not set
+# CONFIG_SA1100_GRAPHICSCLIENT is not set
+# CONFIG_SA1100_JORNADA720 is not set
+# CONFIG_SA1100_HUW_WEBPANEL is not set
+# CONFIG_SA1100_ITSY is not set
+# CONFIG_SA1100_LART is not set
+# CONFIG_SA1100_NANOENGINE is not set
+# CONFIG_SA1100_OMNIMETER is not set
+# CONFIG_SA1100_PANGOLIN is not set
+CONFIG_SA1100_PLEB=y
+# CONFIG_SA1100_SHERMAN is not set
+# CONFIG_SA1100_PFS168 is not set
+# CONFIG_SA1100_VICTOR is not set
+# CONFIG_SA1100_XP860 is not set
+# CONFIG_SA1100_YOPY is not set
+# CONFIG_SA1100_USB is not set
+# CONFIG_SA1100_USB_NETLINK is not set
+# CONFIG_SA1100_USB_CHAR is not set
+
+#
+# CLPS711X/EP721X Implementations
+#
+# CONFIG_ARCH_P720T is not set
+# CONFIG_ARCH_ACORN is not set
+# CONFIG_FOOTBRIDGE is not set
+# CONFIG_FOOTBRIDGE_HOST is not set
+# CONFIG_FOOTBRIDGE_ADDIN is not set
+CONFIG_CPU_32=y
+# CONFIG_CPU_26 is not set
+# CONFIG_CPU_32v3 is not set
+CONFIG_CPU_32v4=y
+# CONFIG_CPU_ARM610 is not set
+# CONFIG_CPU_ARM710 is not set
+# CONFIG_CPU_ARM720T is not set
+# CONFIG_CPU_ARM920T is not set
+# CONFIG_CPU_ARM1020 is not set
+# CONFIG_CPU_SA110 is not set
+CONFIG_CPU_SA1100=y
+CONFIG_DISCONTIGMEM=y
+# CONFIG_CPU_BIG_ENDIAN is not set
+
+#
+# General setup
+#
+# CONFIG_PCI is not set
+# CONFIG_ISA is not set
+# CONFIG_ISA_DMA is not set
+CONFIG_CPU_FREQ=y
+# CONFIG_HOTPLUG is not set
+# CONFIG_PCMCIA is not set
+CONFIG_NET=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_FASTFPE is not set
+CONFIG_KCORE_ELF=y
+# CONFIG_KCORE_AOUT is not set
+CONFIG_BINFMT_AOUT=y
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_PM is not set
+# CONFIG_APM is not set
+# CONFIG_ARTHUR is not set
+CONFIG_CMDLINE="console=ttySA0,9600"
+# CONFIG_PFS168_CMDLINE is not set
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_AMDSTD is not set
+# CONFIG_MTD_SHARP is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_JEDEC is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_SUN_UFLASH is not set
+# CONFIG_MTD_NORA is not set
+# CONFIG_MTD_PNC2000 is not set
+# CONFIG_MTD_RPXLITE is not set
+# CONFIG_MTD_SC520CDP is not set
+# CONFIG_MTD_NETSC520 is not set
+# CONFIG_MTD_SBC_GXX is not set
+# CONFIG_MTD_ELAN_104NC is not set
+# CONFIG_MTD_SA1100 is not set
+# CONFIG_MTD_SA1100_REDBOOT_PARTITIONS is not set
+# CONFIG_MTD_SA1100_BOOTLDR_PARTITIONS is not set
+# CONFIG_MTD_DC21285 is not set
+# CONFIG_MTD_IQ80310 is not set
+# CONFIG_MTD_DBOX2 is not set
+# CONFIG_MTD_CSTM_MIPS_IXX is not set
+# CONFIG_MTD_CFI_FLAGADM is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+# CONFIG_MTD_MIXMEM is not set
+# CONFIG_MTD_OCTAGON is not set
+# CONFIG_MTD_VMAX is not set
+# CONFIG_MTD_OCELOT is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_DOC1000 is not set
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOCPROBE is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# Plug and Play configuration
+#
+# CONFIG_PNP is not set
+# CONFIG_ISAPNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_XD is not set
+# CONFIG_PARIDE is not set
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_INITRD=y
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+# CONFIG_BLK_DEV_MD is not set
+# CONFIG_MD_LINEAR is not set
+# CONFIG_MD_RAID0 is not set
+# CONFIG_MD_RAID1 is not set
+# CONFIG_MD_RAID5 is not set
+# CONFIG_BLK_DEV_LVM is not set
+
+#
+# Networking options
+#
+CONFIG_PACKET=m
+# CONFIG_PACKET_MMAP is not set
+# CONFIG_NETLINK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_FILTER is not set
+CONFIG_UNIX=y
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+CONFIG_INET_ECN=y
+CONFIG_SYN_COOKIES=y
+# CONFIG_IPV6 is not set
+# CONFIG_KHTTPD is not set
+# CONFIG_ATM is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_DECNET is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_LLC is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+CONFIG_DUMMY=m
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+# CONFIG_NET_ETHERNET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_ACENIC_OMIT_TIGON_I is not set
+# CONFIG_MYRI_SBUS is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PLIP is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+# CONFIG_NET_FC is not set
+# CONFIG_RCPCI is not set
+# CONFIG_SHAPER is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+
+#
+# Amateur Radio support
+#
+# CONFIG_HAMRADIO is not set
+
+#
+# IrDA (infrared) support
+#
+# CONFIG_IRDA is not set
+
+#
+# ATA/IDE/MFM/RLL support
+#
+# CONFIG_IDE is not set
+# CONFIG_BLK_DEV_IDE_MODES is not set
+# CONFIG_BLK_DEV_HD is not set
+
+#
+# SCSI support
+#
+# CONFIG_SCSI is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+# CONFIG_I2O_BLOCK is not set
+# CONFIG_I2O_LAN is not set
+# CONFIG_I2O_SCSI is not set
+# CONFIG_I2O_PROC is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input core support
+#
+# CONFIG_INPUT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL is not set
+# CONFIG_SERIAL_EXTENDED is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_SERIAL_21285 is not set
+# CONFIG_SERIAL_21285_OLD is not set
+# CONFIG_SERIAL_21285_CONSOLE is not set
+CONFIG_SERIAL_SA1100=y
+# CONFIG_SERIAL_SA1100_OLD is not set
+CONFIG_SERIAL_SA1100_CONSOLE=y
+CONFIG_SA1100_DEFAULT_BAUDRATE=9600
+# CONFIG_SERIAL_AMBA is not set
+# CONFIG_SERIAL_AMBA_CONSOLE is not set
+# CONFIG_SERIAL_CLPS711X is not set
+# CONFIG_SERIAL_CLPS711X_CONSOLE is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_UNIX98_PTY_COUNT=256
+# CONFIG_UCB1200 is not set
+# CONFIG_TOUCHSCREEN_UCB1200 is not set
+# CONFIG_AUDIO_UCB1200 is not set
+# CONFIG_ADC_UCB1200 is not set
+# CONFIG_TOUCHSCREEN_BITSY is not set
+CONFIG_PROFILER=y
+# CONFIG_PFS168_SPI is not set
+# CONFIG_PFS168_DTMF is not set
+# CONFIG_PFS168_MISC is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# Mice
+#
+# CONFIG_BUSMOUSE is not set
+# CONFIG_MOUSE is not set
+
+#
+# Joysticks
+#
+# CONFIG_JOYSTICK is not set
+# CONFIG_QIC02_TAPE is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_INTEL_RNG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+CONFIG_SA1100_RTC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_FTAPE is not set
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# File systems
+#
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_ADFS_FS is not set
+# CONFIG_ADFS_FS_RW is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_FAT_FS is not set
+# CONFIG_MSDOS_FS is not set
+# CONFIG_UMSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+# CONFIG_CRAMFS is not set
+CONFIG_TMPFS=y
+# CONFIG_RAMFS is not set
+# CONFIG_ISO9660_FS is not set
+# CONFIG_JOLIET is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_NTFS_RW is not set
+# CONFIG_HPFS_FS is not set
+CONFIG_PROC_FS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVFS_MOUNT is not set
+# CONFIG_DEVFS_DEBUG is not set
+CONFIG_DEVPTS_FS=y
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_QNX4FS_RW is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UDF_FS is not set
+# CONFIG_UDF_RW is not set
+# CONFIG_UFS_FS is not set
+# CONFIG_UFS_FS_WRITE is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
+# CONFIG_NFS_FS is not set
+# CONFIG_NFS_V3 is not set
+# CONFIG_ROOT_NFS is not set
+# CONFIG_NFSD is not set
+# CONFIG_NFSD_V3 is not set
+# CONFIG_SUNRPC is not set
+# CONFIG_LOCKD is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_NCPFS_PACKET_SIGNING is not set
+# CONFIG_NCPFS_IOCTL_LOCKING is not set
+# CONFIG_NCPFS_STRONG is not set
+# CONFIG_NCPFS_NFS_NS is not set
+# CONFIG_NCPFS_OS2_NS is not set
+# CONFIG_NCPFS_SMALLDOS is not set
+# CONFIG_NCPFS_NLS is not set
+# CONFIG_NCPFS_EXTRAS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_SMB_NLS is not set
+# CONFIG_NLS is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+
+#
+# Bluetooth support
+#
+# CONFIG_BLUEZ is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_NO_FRAME_POINTER is not set
+CONFIG_DEBUG_ERRORS=y
+CONFIG_DEBUG_USER=y
+# CONFIG_DEBUG_INFO is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_NO_PGT_CACHE is not set
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_DC21285_PORT is not set
+# CONFIG_DEBUG_CLPS711X_UART2 is not set
/*
* Ensure that the first section of RAM is present.
* we assume that:
- * 1. the RAM is aligned to a 128MB boundary
- * 2. the kernel is executing in the same 128MB chunk
+ * 1. the RAM is aligned to a 32MB boundary
+ * 2. the kernel is executing in the same 32MB chunk
* as the start of RAM.
*/
- bic r0, r0, #0x07f00000 >> 18 @ round down
- and r2, r5, #0xf8000000 @ round down
+ bic r0, r0, #0x01f00000 >> 18 @ round down
+ and r2, r5, #0xfe000000 @ round down
add r3, r8, r2 @ flags + rambase
str r3, [r0]
pm_power_off();
}
-void machine_restart(char * __unused)
+void machine_restart(void * __unused)
{
/*
* Clean and disable cache, and turn off interrupts
static void __init
fixup_anakin(struct machine_desc *desc, struct param_struct *unused,
- char **cmdline, struct meminfo *mi)
+ char **cmdline, struct meminfo *mi)
{
ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
setup_ramdisk(1, 0, 0, CONFIG_BLK_DEV_RAM_SIZE);
static int __init assabet_init(void)
{
- if (machine_has_neponset()) {
+ if (machine_is_assabet() && machine_has_neponset()) {
/*
* Angel sets this, but other bootloaders may not.
*
{ 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */
{ 0xf1000000, 0x12000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* Board Control Register */
{ 0xf2800000, 0x4b800000, 0x00800000, DOMAIN_IO, 1, 1, 0, 0 }, /* MQ200 */
+ /* f3000000 - neponset system registers */
+ /* f4000000 - neponset SA1111 registers */
LAST_DESC
};
{
if (port->mapbase == _Ser3UTCR0) {
if (mctrl & TIOCM_RTS)
- GPSR = GPIO_BITSY_COM_RTS;
- else
GPCR = GPIO_BITSY_COM_RTS;
+ else
+ GPSR = GPIO_BITSY_COM_RTS;
}
}
if (port->mapbase == _Ser3UTCR0) {
int gplr = GPLR;
- if (!(gplr & GPIO_BITSY_COM_DCD))
+ if (gplr & GPIO_BITSY_COM_DCD)
ret &= ~TIOCM_CD;
- if (!(gplr & GPIO_BITSY_COM_CTS))
+ if (gplr & GPIO_BITSY_COM_CTS)
ret &= ~TIOCM_CTS;
}
static struct map_desc bitsy_io_desc[] __initdata = {
/* virtual physical length domain r w c b */
{ 0xe8000000, 0x00000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* Flash bank 0 */
- { 0xf0000000, 0x49000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* EGPIO 0 */
+ { 0xf0000000, 0x49000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* EGPIO 0 */
{ 0xf1000000, 0x10000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* static memory bank 2 */
{ 0xf3000000, 0x40000000, 0x02000000, DOMAIN_IO, 1, 1, 0, 0 }, /* static memory bank 4 */
LAST_DESC
*
* Copyright (C) 2001 Russell King
*
- * $Id: cpu-sa1110.c,v 1.2 2001/07/24 20:25:25 rmk Exp $
+ * $Id: cpu-sa1110.c,v 1.3 2001/08/12 15:41:53 rmk Exp $
*
* 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
u_short refresh; /* refresh time for array (us) */
};
-static struct sdram_params tc59sm716_cl2_params = {
+static struct sdram_params tc59sm716_cl2_params __initdata = {
rows: 12,
tck: 10,
trcd: 20,
cas_latency: 2,
};
-static struct sdram_params tc59sm716_cl3_params = {
+static struct sdram_params tc59sm716_cl3_params __initdata = {
rows: 12,
tck: 8,
trcd: 20,
cas_latency: 3,
};
+static struct sdram_params sdram_params;
+
/*
* Given a period in ns and frequency in khz, calculate the number of
* cycles of frequency in period. Note that we round up to the next
sdram_notifier(struct notifier_block *nb, unsigned long val, void *data)
{
struct cpufreq_info *ci = data;
- struct sdram_params *sdram = &tc59sm716_cl3_params;
+ struct sdram_params *sdram = &sdram_params;
+
+ /* were we initialised? */
+ if (sdram->cas_latency == 0) {
+ struct cpufreq_minmax *m = data;
+ m->min_freq = m->max_freq = m->cur_freq;
+ return 0;
+ }
switch (val) {
case CPUFREQ_MINMAX:
static int __init sa1110_sdram_init(void)
{
- struct sdram_params *sdram = &tc59sm716_cl3_params;
+ struct sdram_params *sdram = NULL;
unsigned int cur_freq = cpufreq_get(smp_processor_id());
+ int ret = -ENODEV;
+
+ if (machine_is_assabet())
+ sdram = &tc59sm716_cl3_params;
- sdram_update_timing(cur_freq, sdram);
- sdram_update_refresh(cur_freq, sdram);
+ if (sdram) {
+ printk(KERN_DEBUG "SDRAM: tck: %d trcd: %d trp: %d"
+ " twr: %d refresh: %d cas_latency: %d",
+ sdram->tck, sdram->trcd, sdram->trp,
+ sdram->twr, sdram->refresh, sdram->cas_latency);
+
+ memcpy(&sdram_params, sdram, sizeof(sdram_params));
+
+ sdram_update_timing(cur_freq, &sdram_params);
+ sdram_update_refresh(cur_freq, &sdram_params);
+ }
return cpufreq_register_notifier(&sa1110_clkchg_block);
}
for (;;) {
buf = dma->tail;
- if (!buf) {
+ if (!buf || dma->stopped) {
/* no more data available */
DPRINTK("process: no more buf (dma %s)\n",
dma->curr ? "active" : "inactive");
*addr = buf->dma_ptr;
DPRINTK("curr_pos: b=%#x a=%#x\n", (int)dma->curr->id, *addr);
ret = 0;
+ } else if (dma->tail && dma->stopped) {
+ dma_buf_t *buf = dma->tail;
+ if (buf_id)
+ *buf_id = buf->id;
+ *addr = buf->dma_ptr;
+ ret = 0;
} else {
if (buf_id)
*buf_id = NULL;
*addr = 0;
- DPRINTK("curr_pos: spinning\n");
ret = -ENXIO;
}
local_irq_restore(flags);
int sa1100_dma_stop(dmach_t channel)
{
sa1100_dma_t *dma = &dma_chan[channel];
+ int flags;
if (channel_is_sa1111_sac(channel))
return sa1111_dma_stop(channel);
+ if (dma->stopped)
+ return 0;
+ local_irq_save(flags);
+ dma->stopped = 1;
+ /*
+ * Stop DMA and tweak state variables so everything could restart
+ * from there when resume/wakeup occurs.
+ */
dma->regs->ClrDCSR = DCSR_RUN | DCSR_IE;
+ if (dma->curr) {
+ dma_buf_t *buf = dma->curr;
+ if (dma->spin_ref <= 0) {
+ dma_addr_t curpos;
+ sa1100_dma_get_current(channel, NULL, &curpos);
+ buf->size += buf->dma_ptr - curpos;
+ buf->dma_ptr = curpos;
+ }
+ buf->ref = 0;
+ dma->tail = buf;
+ dma->curr = NULL;
+ }
+ dma->spin_ref = 0;
+ dma->regs->ClrDCSR = DCSR_STRTA|DCSR_STRTB;
+ process_dma(dma);
+ local_irq_restore(flags);
return 0;
}
if (channel_is_sa1111_sac(channel))
return sa1111_dma_resume(channel);
- dma->regs->SetDCSR = DCSR_RUN | DCSR_IE;
+ if (dma->stopped) {
+ int flags;
+ save_flags_cli(flags);
+ dma->regs->ClrDCSR = DCSR_STRTA|DCSR_STRTB|DCSR_RUN|DCSR_IE;
+ dma->stopped = 0;
+ dma->spin_ref = 0;
+ process_dma(dma);
+ restore_flags(flags);
+ }
return 0;
}
if (!buf)
buf = dma->tail;
dma->head = dma->tail = dma->curr = NULL;
+ dma->stopped = 0;
dma->spin_ref = 0;
- if (dma->spin_size)
- process_dma(dma);
+ process_dma(dma);
local_irq_restore(flags);
while (buf) {
next_buf = buf->next;
int sa1100_dma_sleep(dmach_t channel)
{
- sa1100_dma_t *dma = &dma_chan[channel];
+ sa1100_dma_t *dma = &dma_chan[channel];
+ int orig_state;
if ((unsigned)channel >= MAX_SA1100_DMA_CHANNELS || !dma->in_use)
return -EINVAL;
return 0;
}
- /*
- * Stop DMA and tweak state variables so everything could restart
- * from there when wakeup occurs.
- */
- dma->regs->ClrDCSR = DCSR_RUN | DCSR_IE;
- if (dma->curr) {
- dma_buf_t *buf = dma->curr;
- dma_addr_t curpos;
- sa1100_dma_get_current(channel, NULL, &curpos);
- buf->size += buf->dma_ptr - curpos;
- buf->dma_ptr = curpos;
- buf->ref = 0;
- dma->tail = buf;
- dma->curr = NULL;
- }
+ orig_state = dma->stopped;
+ sa1100_dma_stop(channel);
+ dma->regs->ClrDCSR = DCSR_RUN | DCSR_IE | DCSR_STRTA | DCSR_STRTB;
+ dma->stopped = orig_state;
dma->spin_ref = 0;
return 0;
}
int sa1100_dma_wakeup(dmach_t channel)
{
- sa1100_dma_t *dma = &dma_chan[channel];
+ sa1100_dma_t *dma = &dma_chan[channel];
dma_regs_t *regs;
int flags;
dma->device_id = device_id;
dma->callback = NULL;
dma->spin_size = 0;
- dma->ready = 1;
return 0;
}
dma_buf_t *head; /* where to insert buffers */
dma_buf_t *tail; /* where to remove buffers */
dma_buf_t *curr; /* buffer currently DMA'ed */
- int ready; /* 1 if DMA can occur */
+ int stopped; /* 1 if DMA is stalled */
dma_regs_t *regs; /* points to appropriate DMA registers */
int irq; /* IRQ used by the channel */
dma_callback_t callback; /* ... to call when buffers are done */
/* virtual physical length domain r w c b */
{ 0xf6000000, 0x20000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* PCMCIA0 IO */
{ 0xf7000000, 0x30000000, 0x01000000, DOMAIN_IO, 1, 1, 0, 0 }, /* PCMCIA1 IO */
- { 0xf8000000, 0x80000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCM */
- { 0xfa000000, 0x90000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* SCM */
- { 0xfc000000, 0xa0000000, 0x02000000, DOMAIN_IO, 0, 1, 0, 0 }, /* MER */
- { 0xfe000000, 0xb0000000, 0x01f00000, DOMAIN_IO, 0, 1, 0, 0 }, /* LCD + DMA */
+ { 0xf8000000, 0x80000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* PCM */
+ { 0xfa000000, 0x90000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* SCM */
+ { 0xfc000000, 0xa0000000, 0x00100000, DOMAIN_IO, 0, 1, 0, 0 }, /* MER */
+ { 0xfe000000, 0xb0000000, 0x00200000, DOMAIN_IO, 0, 1, 0, 0 }, /* LCD + DMA */
LAST_DESC
};
#include "generic.h"
-static void __init
-fixup_lart(struct machine_desc *desc, struct param_struct *params,
- char **cmdline, struct meminfo *mi)
-{
- /*
- * Note that LART is a special case - it doesn't use physical
- * address line A23 on the DRAM, so we effectively have 4 * 8MB
- * in two SA1100 banks.
- */
- SET_BANK( 0, 0xc0000000, 8*1024*1024 );
- SET_BANK( 1, 0xc1000000, 8*1024*1024 );
- SET_BANK( 2, 0xc8000000, 8*1024*1024 );
- SET_BANK( 3, 0xc9000000, 8*1024*1024 );
- SET_BANK( 4, 0xd0000000, 64*1024*1024 );
- SET_BANK( 5, 0xd8000000, 64*1024*1024 );
-
- /* make this 5 if you have the 64MB expansion card, or
- * 6 if you have two 64MB expansion cards */
- mi->nr_banks = 4;
-
- ROOT_DEV = MKDEV(RAMDISK_MAJOR,0);
- setup_ramdisk(1, 0, 0, 8192);
- setup_initrd(0xc0400000, 4*1024*1024);
-}
-
static struct map_desc lart_io_desc[] __initdata = {
/* virtual physical length domain r w c b */
{ 0xe8000000, 0x00000000, 0x00400000, DOMAIN_IO, 1, 1, 0, 0 }, /* main flash memory */
sa1100_register_uart(0, 3);
sa1100_register_uart(1, 1);
+ sa1100_register_uart(2, 2);
GAFR |= (GPIO_UART_TXD | GPIO_UART_RXD);
GPDR |= GPIO_UART_TXD;
GPDR &= ~GPIO_UART_RXD;
MACHINE_START(LART, "LART")
BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
- FIXUP(fixup_lart)
+ BOOT_PARAMS(0xc0000100)
MAPIO(lart_map_io)
INITIRQ(sa1100_init_irq)
MACHINE_END
void cerf_leds_event(led_event_t evt)
{
- unsigned long flags;
+ unsigned long flags;
local_irq_save(flags);
- switch (evt) {
- case led_start:
- hw_led_state = LED_MASK;
- led_state = LED_STATE_ENABLED;
- break;
-
- case led_stop:
- led_state &= ~LED_STATE_ENABLED;
- break;
-
- case led_claim:
- led_state |= LED_STATE_CLAIMED;
- hw_led_state = LED_MASK;
- break;
- case led_release:
- led_state &= ~LED_STATE_CLAIMED;
- hw_led_state = LED_MASK;
- break;
+ switch (evt) {
+ case led_start:
+ hw_led_state = LED_MASK;
+ led_state = LED_STATE_ENABLED;
+ break;
+
+ case led_stop:
+ led_state &= ~LED_STATE_ENABLED;
+ break;
+
+ case led_claim:
+ led_state |= LED_STATE_CLAIMED;
+ hw_led_state = LED_MASK;
+ break;
+ case led_release:
+ led_state &= ~LED_STATE_CLAIMED;
+ hw_led_state = LED_MASK;
+ break;
#ifdef CONFIG_LEDS_TIMER
- case led_timer:
- if (!(led_state & LED_STATE_CLAIMED))
- hw_led_state ^= LED_D0;
- break;
+ case led_timer:
+ if (!(led_state & LED_STATE_CLAIMED))
+ hw_led_state ^= LED_D0;
+ break;
#endif
#ifdef CONFIG_LEDS_CPU
- case led_idle_start:
- if (!(led_state & LED_STATE_CLAIMED))
- hw_led_state &= ~LED_D1;
- break;
-
- case led_idle_end:
- if (!(led_state & LED_STATE_CLAIMED))
- hw_led_state |= LED_D1;
- break;
+ case led_idle_start:
+ if (!(led_state & LED_STATE_CLAIMED))
+ hw_led_state &= ~LED_D1;
+ break;
+
+ case led_idle_end:
+ if (!(led_state & LED_STATE_CLAIMED))
+ hw_led_state |= LED_D1;
+ break;
#endif
- case led_green_on:
- if (!(led_state & LED_STATE_CLAIMED))
- hw_led_state &= ~LED_D2;
- break;
-
- case led_green_off:
- if (!(led_state & LED_STATE_CLAIMED))
- hw_led_state |= LED_D2;
- break;
-
- case led_amber_on:
- if (!(led_state & LED_STATE_CLAIMED))
- hw_led_state &= ~LED_D3;
- break;
-
- case led_amber_off:
- if (!(led_state & LED_STATE_CLAIMED))
- hw_led_state |= LED_D3;
- break;
-
- case led_red_on:
- if (!(led_state & LED_STATE_CLAIMED))
- hw_led_state &= ~LED_D1;
- break;
-
- case led_red_off:
- if (!(led_state & LED_STATE_CLAIMED))
- hw_led_state |= LED_D1;
- break;
-
- default:
- break;
- }
-
- if (led_state & LED_STATE_ENABLED) {
- GPSR = hw_led_state;
- GPCR = hw_led_state ^ LED_MASK;
- }
+ case led_green_on:
+ if (!(led_state & LED_STATE_CLAIMED))
+ hw_led_state &= ~LED_D2;
+ break;
+
+ case led_green_off:
+ if (!(led_state & LED_STATE_CLAIMED))
+ hw_led_state |= LED_D2;
+ break;
+
+ case led_amber_on:
+ if (!(led_state & LED_STATE_CLAIMED))
+ hw_led_state &= ~LED_D3;
+ break;
+
+ case led_amber_off:
+ if (!(led_state & LED_STATE_CLAIMED))
+ hw_led_state |= LED_D3;
+ break;
+
+ case led_red_on:
+ if (!(led_state & LED_STATE_CLAIMED))
+ hw_led_state &= ~LED_D1;
+ break;
+
+ case led_red_off:
+ if (!(led_state & LED_STATE_CLAIMED))
+ hw_led_state |= LED_D1;
+ break;
+
+ default:
+ break;
+ }
+
+ if (led_state & LED_STATE_ENABLED) {
+ GPSR = hw_led_state;
+ GPCR = hw_led_state ^ LED_MASK;
+ }
local_irq_restore(flags);
}
#ifdef CONFIG_LEDS_CPU
case led_idle_start:
/* The LART people like the LED to be off when the
- system is idle... */
+ system is idle... */
if (!(led_state & LED_STATE_CLAIMED))
hw_led_state &= ~LED_23;
break;
switch (evt)
{
case led_start:
- hw_led_state = LED_GREEN;
+ hw_led_state = LED_GREEN;
led_state = LED_STATE_ENABLED;
break;
static int __init neponset_init(void)
{
+ /* only on assabet */
+ if (!machine_is_assabet())
+ return 0;
+
if (machine_has_neponset()) {
LEDS = WHOAMI;
static struct map_desc neponset_io_desc[] __initdata = {
/* virtual physical length domain r w c b */
- { 0xf0000000, 0x10000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* System Registers */
+ { 0xf3000000, 0x10000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* System Registers */
{ 0xf4000000, 0x40000000, 0x00100000, DOMAIN_IO, 1, 1, 0, 0 }, /* SA-1111 */
LAST_DESC
};
#include "generic.h"
+static void __init
+fixup_pleb(struct machine_desc *desc, struct param_struct *params,
+ char **cmdline, struct meminfo *mi)
+{
+ SET_BANK(0, 0xc0000000, 16*1024*1024);
+ SET_BANK(1, 0xc8000000, 16*1024*1024);
+ SET_BANK(2, 0xd0000000, 16*1024*1024);
+ SET_BANK(3, 0xd8000000, 16*1024*1024);
+
+ /* make this 4 a second memory card is used to make 64MB */
+ /* make it 1 if a 16MB memory card is used */
+ mi->nr_banks = 2; /* Default 32MB */
+
+ ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
+ setup_ramdisk(1, 0, 0, 8192);
+ setup_initrd(0xc0400000, 4*1024*1024);
+}
static struct map_desc pleb_io_desc[] __initdata = {
/* virtual physical length domain r w c b */
iotable_init(pleb_io_desc);
sa1100_register_uart(0, 3);
+ sa1100_register_uart(1, 1);
+ GAFR |= (GPIO_UART_TXD | GPIO_UART_RXD);
+ GPDR |= GPIO_UART_TXD;
+ GPDR &= ~GPIO_UART_RXD;
+ PPAR |= PPAR_UPR;
}
MACHINE_START(PLEB, "PLEB")
BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
+ FIXUP(fixup_pleb)
MAPIO(pleb_map_io)
INITIRQ(sa1100_init_irq)
MACHINE_END
#include <linux/slab.h>
#include <linux/pci.h>
+#include "pcipool.h"
+
/*
* simple buffer allocator for copying of unsafe to safe buffers
* uses __alloc/__free for actual buffers
/* take out of reset */
/* set power sense and control lines (this from the diags code) */
- *Reset = ( PwrSensePolLow << 6 )
- | ( PwrCtrlPolLow << 7 );
+ *Reset = ( PwrSensePolLow << 6 )
+ | ( PwrCtrlPolLow << 7 );
*Status = 0;
}
MACHINE_START(SHERMAN, "Blazie Engineering Sherman")
- BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
- FIXUP(fixup_sherman)
- MAPIO(sherman_map_io)
+ BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
+ FIXUP(fixup_sherman)
+ MAPIO(sherman_map_io)
INITIRQ(sa1100_init_irq)
MACHINE_END
iotable_init(simpad_io_desc);
sa1100_register_uart(0, 3);
- sa1100_register_uart(1, 1);
+ sa1100_register_uart(1, 1);
}
}
/*
- * if PG_dcache_dirty is set for the page, we need to ensure that any
- * cache entries for the kernels virtual memory range are written
- * back to the page.
+ * We take the easy way out of this problem - we make the
+ * PTE uncacheable. However, we leave the write buffer on.
*/
-void check_pgcache_dirty(struct page *page)
+static void adjust_pte(struct vm_area_struct *vma, unsigned long address)
{
- if (VALID_PAGE(page) && page->mapping &&
- test_and_clear_bit(PG_dcache_dirty, &page->flags)) {
+ pgd_t *pgd;
+ pmd_t *pmd;
+ pte_t *pte, entry;
+
+ pgd = pgd_offset(vma->vm_mm, address);
+ if (pgd_none(*pgd))
+ return;
+ if (pgd_bad(*pgd))
+ goto bad_pgd;
+
+ pmd = pmd_offset(pgd, address);
+ if (pmd_none(*pmd))
+ return;
+ if (pmd_bad(*pmd))
+ goto bad_pmd;
+
+ pte = pte_offset(pmd, address);
+ entry = *pte;
+
+ /*
+ * If this page isn't present, or is already setup to
+ * fault (ie, is old), we can safely ignore any issues.
+ */
+ if (pte_present(entry) && pte_val(entry) & L_PTE_CACHEABLE) {
+ flush_cache_page(vma, address);
+ pte_val(entry) &= ~L_PTE_CACHEABLE;
+ set_pte(pte, entry);
+ flush_tlb_page(vma, address);
+ }
+ return;
+
+bad_pgd:
+ pgd_ERROR(*pgd);
+ pgd_clear(pgd);
+ return;
+
+bad_pmd:
+ pmd_ERROR(*pmd);
+ pmd_clear(pmd);
+ return;
+}
+
+/*
+ * Take care of architecture specific things when placing a new PTE into
+ * a page table, or changing an existing PTE. Basically, there are two
+ * things that we need to take care of:
+ *
+ * 1. If PG_dcache_dirty is set for the page, we need to ensure
+ * that any cache entries for the kernels virtual memory
+ * range are written back to the page.
+ * 2. If we have multiple shared mappings of the same space in
+ * an object, we need to deal with the cache aliasing issues.
+ *
+ * Note that the page_table_lock will be held.
+ */
+void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, pte_t pte)
+{
+ struct page *page = pte_page(pte);
+ struct vm_area_struct *mpnt;
+ struct mm_struct *mm;
+ unsigned long pgoff;
+ int aliases;
+
+ if (!VALID_PAGE(page) || !page->mapping)
+ return;
+
+ if (test_and_clear_bit(PG_dcache_dirty, &page->flags)) {
unsigned long kvirt = (unsigned long)page_address(page);
cpu_cache_clean_invalidate_range(kvirt, kvirt + PAGE_SIZE, 0);
}
+
+ mm = vma->vm_mm;
+ pgoff = (addr - vma->vm_start) >> PAGE_SHIFT;
+ aliases = 0;
+
+ /*
+ * If we have any shared mappings that are in the same mm
+ * space, then we need to handle them specially to maintain
+ * cache coherency.
+ */
+ for (mpnt = page->mapping->i_mmap_shared; mpnt;
+ mpnt = mpnt->vm_next_share) {
+ unsigned long off;
+
+ /*
+ * If this VMA is not in our MM, we can ignore it.
+ * Note that we intentionally don't mask out the VMA
+ * that we are fixing up.
+ */
+ if (mpnt->vm_mm != mm && mpnt != vma)
+ continue;
+
+ /*
+ * If the page isn't in this VMA, we can also ignore it.
+ */
+ if (pgoff < mpnt->vm_pgoff)
+ continue;
+
+ off = pgoff - mpnt->vm_pgoff;
+ if (off >= (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT)
+ continue;
+
+ /*
+ * Ok, it is within mpnt. Fix it up.
+ */
+ adjust_pte(mpnt, mpnt->vm_start + (off << PAGE_SHIFT));
+ aliases ++;
+ }
+ if (aliases)
+ adjust_pte(vma, addr);
}
# To add an entry into this database, please see Documentation/arm/README,
# or contact rmk@arm.linux.org.uk
#
-# Last update: Wed Jul 25 10:07:10 2001
+# Last update: Thu Aug 9 22:46:02 2001
#
# machine_is_xxx CONFIG_xxxx MACH_TYPE_xxx number
#
gator SA1100_GATOR GATOR 103
granite ARCH_GRANITE GRANITE 104
consus SA1100_CONSUS CONSUS 105
+aaec2000_aaed20 ARCH_AAEC2000_AAED2000 AAEC2000_AAED2000 106
#ifdef CONFIG_VT
extern void con_init_devfs (void);
#endif
-extern int rio_init(void);
#define CONSOLE_DEV MKDEV(TTY_MAJOR,0)
#define TTY_DEV MKDEV(TTYAUX_MAJOR,0)
extern void con3215_init(void);
extern void tty3215_init(void);
extern void tub3270_con_init(void);
-extern void tub3270_initfunc(void);
+extern void tub3270_init(void);
extern void rs285_console_init(void);
extern void sa1100_rs_console_init(void);
extern void sgi_serial_console_init(void);
return cmd == TIOCSPGRP ? -ENOTTY : -EIO;
}
-static loff_t tty_lseek(struct file * file, loff_t offset, int orig)
-{
- return -ESPIPE;
-}
-
static struct file_operations tty_fops = {
- llseek: tty_lseek,
+ llseek: no_llseek,
read: tty_read,
write: tty_write,
poll: tty_poll,
};
static struct file_operations hung_up_tty_fops = {
- llseek: tty_lseek,
+ llseek: no_llseek,
read: hung_up_tty_read,
write: hung_up_tty_write,
poll: hung_up_tty_poll,
#if (defined(CONFIG_8xx) || defined(CONFIG_8260))
console_8xx_init();
#elif defined(CONFIG_MAC_SERIAL)
- mac_scc_console_init();
+ mac_scc_console_init();
+#elif defined(CONFIG_PARISC)
+ pdc_console_init();
#elif defined(CONFIG_SERIAL)
serial_console_init();
#endif /* CONFIG_8xx */
sci_console_init();
#endif
#endif
-#ifdef CONFIG_3215
- con3215_init();
-#endif
-#ifdef CONFIG_3270_CONSOLE
+#ifdef CONFIG_TN3270_CONSOLE
tub3270_con_init();
#endif
+#ifdef CONFIG_TN3215
+ con3215_init();
+#endif
#ifdef CONFIG_HWC
hwc_console_init();
#endif
+#ifdef CONFIG_STDIO_CONSOLE
+ stdio_console_init();
+#endif
#ifdef CONFIG_SERIAL_21285_CONSOLE
rs285_console_init();
#endif
kbd_init();
#endif
+
#ifdef CONFIG_ESPSERIAL /* init ESP before rs, so rs doesn't see the port */
espserial_init();
#endif
#ifdef CONFIG_SPECIALIX
specialix_init();
#endif
-#ifdef CONFIG_RIO
- rio_init();
-#endif
#if (defined(CONFIG_8xx) || defined(CONFIG_8260))
rs_8xx_init();
#endif /* CONFIG_8xx */
#ifdef CONFIG_VT
vcs_init();
#endif
-#ifdef CONFIG_3270
- tub3270_initfunc();
+#ifdef CONFIG_TN3270
+ tub3270_init();
#endif
-#ifdef CONFIG_3215
+#ifdef CONFIG_TN3215
tty3215_init();
#endif
#ifdef CONFIG_HWC
#ifdef TTY_DEBUG_WAIT_UNTIL_SENT
char buf[64];
- printk("%s wait until sent...\n", tty_name(tty, buf));
+ printk(KERN_DEBUG "%s wait until sent...\n", tty_name(tty, buf));
#endif
if (!tty->driver.chars_in_buffer)
return;
timeout = MAX_SCHEDULE_TIMEOUT;
do {
#ifdef TTY_DEBUG_WAIT_UNTIL_SENT
- printk("waiting %s...(%d)\n", tty_name(tty, buf),
+ printk(KERN_DEBUG "waiting %s...(%d)\n", tty_name(tty, buf),
tty->driver.chars_in_buffer(tty));
#endif
set_current_state(TASK_INTERRUPTIBLE);
#define NOSET_MASK(x,y,z) (x = ((x) & ~(z)) | ((y) & (z)))
if (!locked) {
- printk("Warning?!? termios_locked is NULL.\n");
+ printk(KERN_WARNING "Warning?!? termios_locked is NULL.\n");
return;
}
* Dynamic keymap and string allocation - aeb@cwi.nl - May 1994
* Restrict VT switching via ioctl() - grif@cs.ucr.edu - Dec 1995
* Some code moved for less code duplication - Andi Kleen - Mar 1997
+ * Check put/get_user, cleanups - acme@conectiva.com.br - Jun 2001
*/
#include <linux/config.h>
p = func_table[i];
if(p)
for ( ; *p && sz; p++, sz--)
- put_user(*p, q++);
- put_user('\0', q);
+ if (put_user(*p, q++))
+ return -EFAULT;
+ if (put_user('\0', q))
+ return -EFAULT;
return ((p && *p) ? -EOVERFLOW : 0);
case KDSKBSENT:
if (!perm)
struct vt_stat *vtstat = (struct vt_stat *)arg;
unsigned short state, mask;
- i = verify_area(VERIFY_WRITE,(void *)vtstat, sizeof(struct vt_stat));
- if (i)
- return i;
- put_user(fg_console + 1, &vtstat->v_active);
+ if (put_user(fg_console + 1, &vtstat->v_active))
+ return -EFAULT;
state = 1; /* /dev/tty0 is always open */
for (i = 0, mask = 2; i < MAX_NR_CONSOLES && mask; ++i, mask <<= 1)
if (VT_IS_IN_USE(i))
ushort ll,cc;
if (!perm)
return -EPERM;
- i = verify_area(VERIFY_READ, (void *)vtsizes, sizeof(struct vt_sizes));
- if (i)
- return i;
- get_user(ll, &vtsizes->v_rows);
- get_user(cc, &vtsizes->v_cols);
+ if (get_user(ll, &vtsizes->v_rows) ||
+ get_user(cc, &vtsizes->v_cols))
+ return -EFAULT;
return vc_resize_all(ll, cc);
}
ushort ll,cc,vlin,clin,vcol,ccol;
if (!perm)
return -EPERM;
- i = verify_area(VERIFY_READ, (void *)vtconsize, sizeof(struct vt_consize));
- if (i)
- return i;
- get_user(ll, &vtconsize->v_rows);
- get_user(cc, &vtconsize->v_cols);
- get_user(vlin, &vtconsize->v_vlin);
- get_user(clin, &vtconsize->v_clin);
- get_user(vcol, &vtconsize->v_vcol);
- get_user(ccol, &vtconsize->v_ccol);
+ if (verify_area(VERIFY_READ, (void *)vtconsize,
+ sizeof(struct vt_consize)))
+ return -EFAULT;
+ __get_user(ll, &vtconsize->v_rows);
+ __get_user(cc, &vtconsize->v_cols);
+ __get_user(vlin, &vtconsize->v_vlin);
+ __get_user(clin, &vtconsize->v_clin);
+ __get_user(vcol, &vtconsize->v_vcol);
+ __get_user(ccol, &vtconsize->v_ccol);
vlin = vlin ? vlin : video_scan_lines;
if ( clin )
{
if (!perm)
return -EPERM;
- i = verify_area(VERIFY_READ, (void *) arg,
- sizeof(struct vc_mode));
- if (i)
- return i;
if (copy_from_user(&mode, (void *) arg, sizeof(mode)))
return -EFAULT;
return console_setmode(&mode, cmd == VC_SETMODE);
was changed from 0x766a to 0x766c */
return console_powermode((int) arg);
}
- i = verify_area(VERIFY_READ, (void *) arg,
- sizeof(int));
- if (i)
- return i;
if (get_user(cmap_size, (int *) arg))
return -EFAULT;
if (cmap_size % 3)
#define DIVAS_IRQ_RESET 0xC18
#define DIVAS_IRQ_RESET_VAL 0xFE
-#define PCI_LATENCY PCI_LATENCY_TIMER
-#define PCI_INTERRUPT PCI_INTERRUPT_LINE
-
#define TEST_INT_DIVAS 0x11
#define TEST_INT_DIVAS_BRI 0x12
#define TEST_INT_DIVAS_Q 0x13
int DivasCardNew(dia_card_t *card_info)
{
card_t *card;
- byte b;
static boolean_t first_call = TRUE;
boolean_t NeedISRandReset = FALSE;
return -1;
}
- b = card->cfg.irq;
-
- UxPciConfigWrite(card->hw, sizeof(b), PCI_INTERRUPT_LINE, &b);
-
if (card_info->card_type != DIA_CARD_TYPE_DIVA_SERVER_Q)
{
if ((*card->card_reset)(card))
return -1;
}
- bzero(card->e_tbl, sizeof(E_INFO) * num_entities);
+ memset(card->e_tbl, 0, sizeof(E_INFO) * num_entities);
card->e_max = num_entities;
DIVA_DIDD_Read(d, sizeof(d));
extern int DivasCardNext;
void UxPause(long ms);
-void bcopy(void *pSource, void *pDest, dword dwLength);
int DivasGetMem(mem_block_t *);
#define DIA_IOCTL_UNLOCK 12
{
word wMask = 0;
- if (!DivasLogFifoEmpty())
- {
+ if (!DivasLogFifoEmpty())
wMask |= POLLIN | POLLRDNORM;
- }
-
return wMask;
}
{
printk(KERN_WARNING "Divas: Divalog buffer specifed a size that is too small (%d - %d required)\n",
BufferSize, sizeof(klog_t));
- return 0;
+ return -EIO;
}
pHeadItem = (klog_t *) DivasLogFifoRead();
if (pHeadItem)
{
- bcopy(pHeadItem, pClientLogBuffer, sizeof(klog_t));
+ memcpy(pClientLogBuffer, pHeadItem, sizeof(klog_t));
kfree(pHeadItem);
return sizeof(klog_t);
}
#include "uxio.h"
-#ifdef MODULE
-void bcopy(void *pSource, void *pDest, dword dwLength)
-{
- memcpy(pDest, pSource, dwLength);
-}
-#endif
-
-void bzero(void *pDataArea, dword dwLength)
-{
- memset(pDataArea, 0, dwLength);
-}
-
int Divas4BRIInitPCI(card_t *card, dia_card_t *cfg)
{
/* Use UxPciConfigWrite routines to initialise PCI config space */
isr_fn_t *user_isr;
};
-void bcopy(void *pSource, void *pDest, dword dwLength);
-void bzero(void *pDataArea, dword dwLength);
-
-
/*
* Get a card handle to enable card to be accessed
*/
+++ /dev/null
-/* depca.c: A DIGITAL DEPCA & EtherWORKS ethernet driver for linux.
-
- Written 1994, 1995 by David C. Davies.
-
-
- Copyright 1994 David C. Davies
- and
- United States Government
- (as represented by the Director, National Security Agency).
-
- Copyright 1995 Digital Equipment Corporation.
-
-
- This software may be used and distributed according to the terms of
- the GNU General Public License, incorporated herein by reference.
-
- This driver is written for the Digital Equipment Corporation series
- of DEPCA and EtherWORKS ethernet cards:
-
- DEPCA (the original)
- DE100
- DE101
- DE200 Turbo
- DE201 Turbo
- DE202 Turbo (TP BNC)
- DE210
- DE422 (EISA)
-
- The driver has been tested on DE100, DE200 and DE202 cards in a
- relatively busy network. The DE422 has been tested a little.
-
- This driver will NOT work for the DE203, DE204 and DE205 series of
- cards, since they have a new custom ASIC in place of the AMD LANCE
- chip. See the 'ewrk3.c' driver in the Linux source tree for running
- those cards.
-
- I have benchmarked the driver with a DE100 at 595kB/s to (542kB/s from)
- a DECstation 5000/200.
-
- The author may be reached at davies@maniac.ultranet.com
-
- =========================================================================
-
- The driver was originally based on the 'lance.c' driver from Donald
- Becker which is included with the standard driver distribution for
- linux. V0.4 is a complete re-write with only the kernel interface
- remaining from the original code.
-
- 1) Lance.c code in /linux/drivers/net/
- 2) "Ethernet/IEEE 802.3 Family. 1992 World Network Data Book/Handbook",
- AMD, 1992 [(800) 222-9323].
- 3) "Am79C90 CMOS Local Area Network Controller for Ethernet (C-LANCE)",
- AMD, Pub. #17881, May 1993.
- 4) "Am79C960 PCnet-ISA(tm), Single-Chip Ethernet Controller for ISA",
- AMD, Pub. #16907, May 1992
- 5) "DEC EtherWORKS LC Ethernet Controller Owners Manual",
- Digital Equipment corporation, 1990, Pub. #EK-DE100-OM.003
- 6) "DEC EtherWORKS Turbo Ethernet Controller Owners Manual",
- Digital Equipment corporation, 1990, Pub. #EK-DE200-OM.003
- 7) "DEPCA Hardware Reference Manual", Pub. #EK-DEPCA-PR
- Digital Equipment Corporation, 1989
- 8) "DEC EtherWORKS Turbo_(TP BNC) Ethernet Controller Owners Manual",
- Digital Equipment corporation, 1991, Pub. #EK-DE202-OM.001
-
-
- Peter Bauer's depca.c (V0.5) was referred to when debugging V0.1 of this
- driver.
-
- The original DEPCA card requires that the ethernet ROM address counter
- be enabled to count and has an 8 bit NICSR. The ROM counter enabling is
- only done when a 0x08 is read as the first address octet (to minimise
- the chances of writing over some other hardware's I/O register). The
- NICSR accesses have been changed to byte accesses for all the cards
- supported by this driver, since there is only one useful bit in the MSB
- (remote boot timeout) and it is not used. Also, there is a maximum of
- only 48kB network RAM for this card. My thanks to Torbjorn Lindh for
- help debugging all this (and holding my feet to the fire until I got it
- right).
-
- The DE200 series boards have on-board 64kB RAM for use as a shared
- memory network buffer. Only the DE100 cards make use of a 2kB buffer
- mode which has not been implemented in this driver (only the 32kB and
- 64kB modes are supported [16kB/48kB for the original DEPCA]).
-
- At the most only 2 DEPCA cards can be supported on the ISA bus because
- there is only provision for two I/O base addresses on each card (0x300
- and 0x200). The I/O address is detected by searching for a byte sequence
- in the Ethernet station address PROM at the expected I/O address for the
- Ethernet PROM. The shared memory base address is 'autoprobed' by
- looking for the self test PROM and detecting the card name. When a
- second DEPCA is detected, information is placed in the base_addr
- variable of the next device structure (which is created if necessary),
- thus enabling ethif_probe initialization for the device. More than 2
- EISA cards can be supported, but care will be needed assigning the
- shared memory to ensure that each slot has the correct IRQ, I/O address
- and shared memory address assigned.
-
- ************************************************************************
-
- NOTE: If you are using two ISA DEPCAs, it is important that you assign
- the base memory addresses correctly. The driver autoprobes I/O 0x300
- then 0x200. The base memory address for the first device must be less
- than that of the second so that the auto probe will correctly assign the
- I/O and memory addresses on the same card. I can't think of a way to do
- this unambiguously at the moment, since there is nothing on the cards to
- tie I/O and memory information together.
-
- I am unable to test 2 cards together for now, so this code is
- unchecked. All reports, good or bad, are welcome.
-
- ************************************************************************
-
- The board IRQ setting must be at an unused IRQ which is auto-probed
- using Donald Becker's autoprobe routines. DEPCA and DE100 board IRQs are
- {2,3,4,5,7}, whereas the DE200 is at {5,9,10,11,15}. Note that IRQ2 is
- really IRQ9 in machines with 16 IRQ lines.
-
- No 16MB memory limitation should exist with this driver as DMA is not
- used and the common memory area is in low memory on the network card (my
- current system has 20MB and I've not had problems yet).
-
- The ability to load this driver as a loadable module has been added. To
- utilise this ability, you have to do <8 things:
-
- 0) have a copy of the loadable modules code installed on your system.
- 1) copy depca.c from the /linux/drivers/net directory to your favourite
- temporary directory.
- 2) if you wish, edit the source code near line 1530 to reflect the I/O
- address and IRQ you're using (see also 5).
- 3) compile depca.c, but include -DMODULE in the command line to ensure
- that the correct bits are compiled (see end of source code).
- 4) if you are wanting to add a new card, goto 5. Otherwise, recompile a
- kernel with the depca configuration turned off and reboot.
- 5) insmod depca.o [irq=7] [io=0x200] [mem=0xd0000] [adapter_name=DE100]
- [Alan Cox: Changed the code to allow command line irq/io assignments]
- [Dave Davies: Changed the code to allow command line mem/name
- assignments]
- 6) run the net startup bits for your eth?? interface manually
- (usually /etc/rc.inet[12] at boot time).
- 7) enjoy!
-
- Note that autoprobing is not allowed in loadable modules - the system is
- already up and running and you're messing with interrupts.
-
- To unload a module, turn off the associated interface
- 'ifconfig eth?? down' then 'rmmod depca'.
-
- To assign a base memory address for the shared memory when running as a
- loadable module, see 5 above. To include the adapter name (if you have
- no PROM but know the card name) also see 5 above. Note that this last
- option will not work with kernel built-in depca's.
-
- The shared memory assignment for a loadable module makes sense to avoid
- the 'memory autoprobe' picking the wrong shared memory (for the case of
- 2 depca's in a PC).
-
- ************************************************************************
- Support for MCA EtherWORKS cards added 11-3-98.
- Verified to work with up to 2 DE212 cards in a system (although not
- fully stress-tested).
-
- Currently known bugs/limitations:
-
- Note: with the MCA stuff as a module, it trusts the MCA configuration,
- not the command line for IRQ and memory address. You can
- specify them if you want, but it will throw your values out.
- You still have to pass the IO address it was configured as
- though.
-
- ************************************************************************
- TO DO:
- ------
-
-
- Revision History
- ----------------
-
- Version Date Description
-
- 0.1 25-jan-94 Initial writing.
- 0.2 27-jan-94 Added LANCE TX hardware buffer chaining.
- 0.3 1-feb-94 Added multiple DEPCA support.
- 0.31 4-feb-94 Added DE202 recognition.
- 0.32 19-feb-94 Tidy up. Improve multi-DEPCA support.
- 0.33 25-feb-94 Fix DEPCA ethernet ROM counter enable.
- Add jabber packet fix from murf@perftech.com
- and becker@super.org
- 0.34 7-mar-94 Fix DEPCA max network memory RAM & NICSR access.
- 0.35 8-mar-94 Added DE201 recognition. Tidied up.
- 0.351 30-apr-94 Added EISA support. Added DE422 recognition.
- 0.36 16-may-94 DE422 fix released.
- 0.37 22-jul-94 Added MODULE support
- 0.38 15-aug-94 Added DBR ROM switch in depca_close().
- Multi DEPCA bug fix.
- 0.38axp 15-sep-94 Special version for Alpha AXP Linux V1.0.
- 0.381 12-dec-94 Added DE101 recognition, fix multicast bug.
- 0.382 9-feb-95 Fix recognition bug reported by <bkm@star.rl.ac.uk>.
- 0.383 22-feb-95 Fix for conflict with VESA SCSI reported by
- <stromain@alf.dec.com>
- 0.384 17-mar-95 Fix a ring full bug reported by <bkm@star.rl.ac.uk>
- 0.385 3-apr-95 Fix a recognition bug reported by
- <ryan.niemi@lastfrontier.com>
- 0.386 21-apr-95 Fix the last fix...sorry, must be galloping senility
- 0.40 25-May-95 Rewrite for portability & updated.
- ALPHA support from <jestabro@amt.tay1.dec.com>
- 0.41 26-Jun-95 Added verify_area() calls in depca_ioctl() from
- suggestion by <heiko@colossus.escape.de>
- 0.42 27-Dec-95 Add 'mem' shared memory assignment for loadable
- modules.
- Add 'adapter_name' for loadable modules when no PROM.
- Both above from a suggestion by
- <pchen@woodruffs121.residence.gatech.edu>.
- Add new multicasting code.
- 0.421 22-Apr-96 Fix alloc_device() bug <jari@markkus2.fimr.fi>
- 0.422 29-Apr-96 Fix depca_hw_init() bug <jari@markkus2.fimr.fi>
- 0.423 7-Jun-96 Fix module load bug <kmg@barco.be>
- 0.43 16-Aug-96 Update alloc_device() to conform to de4x5.c
- 0.44 1-Sep-97 Fix *_probe() to test check_region() first - bug
- reported by <mmogilvi@elbert.uccs.edu>
- 0.45 3-Nov-98 Added support for MCA EtherWORKS (DE210/DE212) cards
- by <tymm@computer.org>
- 0.451 5-Nov-98 Fixed mca stuff cuz I'm a dummy. <tymm@computer.org>
- 0.5 14-Nov-98 Re-spin for 2.1.x kernels.
- 0.51 27-Jun-99 Correct received packet length for CRC from
- report by <worm@dkik.dk>
- 0.52 16-Oct-00 Fixes for 2.3 io memory accesses
- Fix show-stopper (ints left masked) in depca_interrupt
- by <peterd@pnd-pc.demon.co.uk>
- 0.53 12-Jan-01 Release resources on failure, bss tidbits
- by acme@conectiva.com.br
-
- =========================================================================
-*/
-
-#include <linux/config.h>
-#include <linux/module.h>
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/ptrace.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <asm/uaccess.h>
-#include <asm/bitops.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-
-#include <linux/time.h>
-#include <linux/types.h>
-#include <linux/unistd.h>
-#include <linux/ctype.h>
-
-#ifdef CONFIG_MCA
-#include <linux/mca.h>
-#endif
-
-#include "depca.h"
-
-static char version[] __initdata =
- "depca.c:v0.53 2001/1/12 davies@maniac.ultranet.com\n";
-
-#ifdef DEPCA_DEBUG
-static int depca_debug = DEPCA_DEBUG;
-#else
-static int depca_debug = 1;
-#endif
-
-#define DEPCA_NDA 0xffe0 /* No Device Address */
-
-#define TX_TIMEOUT (1*HZ)
-
-/*
-** Ethernet PROM defines
-*/
-#define PROBE_LENGTH 32
-#define ETH_PROM_SIG 0xAA5500FFUL
-
-/*
-** Set the number of Tx and Rx buffers. Ensure that the memory requested
-** here is <= to the amount of shared memory set up by the board switches.
-** The number of descriptors MUST BE A POWER OF 2.
-**
-** total_memory = NUM_RX_DESC*(8+RX_BUFF_SZ) + NUM_TX_DESC*(8+TX_BUFF_SZ)
-*/
-#define NUM_RX_DESC 8 /* Number of RX descriptors */
-#define NUM_TX_DESC 8 /* Number of TX descriptors */
-#define RX_BUFF_SZ 1536 /* Buffer size for each Rx buffer */
-#define TX_BUFF_SZ 1536 /* Buffer size for each Tx buffer */
-
-#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */
-#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */
-
-/*
-** EISA bus defines
-*/
-#define DEPCA_EISA_IO_PORTS 0x0c00 /* I/O port base address, slot 0 */
-#define MAX_EISA_SLOTS 16
-#define EISA_SLOT_INC 0x1000
-
-/*
-** ISA Bus defines
-*/
-#define DEPCA_RAM_BASE_ADDRESSES {0xc0000,0xd0000,0xe0000,0x00000}
-#define DEPCA_IO_PORTS {0x300, 0x200, 0}
-#define DEPCA_TOTAL_SIZE 0x10
-static short mem_chkd;
-
-/*
-** Adapter ID for the MCA EtherWORKS DE210/212 adapter
-*/
-#define DE212_ID 0x6def
-
-/*
-** Name <-> Adapter mapping
-*/
-#define DEPCA_SIGNATURE {"DEPCA",\
- "DE100","DE101",\
- "DE200","DE201","DE202",\
- "DE210","DE212",\
- "DE422",\
- ""}
-static enum {
- DEPCA, de100, de101, de200, de201, de202, de210, de212, de422, unknown
-} adapter;
-
-/*
-** Miscellaneous info...
-*/
-#define DEPCA_STRLEN 16
-#define MAX_NUM_DEPCAS 2
-
-/*
-** Memory Alignment. Each descriptor is 4 longwords long. To force a
-** particular alignment on the TX descriptor, adjust DESC_SKIP_LEN and
-** DESC_ALIGN. ALIGN aligns the start address of the private memory area
-** and hence the RX descriptor ring's first entry.
-*/
-#define ALIGN4 ((u_long)4 - 1) /* 1 longword align */
-#define ALIGN8 ((u_long)8 - 1) /* 2 longword (quadword) align */
-#define ALIGN ALIGN8 /* Keep the LANCE happy... */
-
-/*
-** The DEPCA Rx and Tx ring descriptors.
-*/
-struct depca_rx_desc {
- volatile s32 base;
- s16 buf_length; /* This length is negative 2's complement! */
- s16 msg_length; /* This length is "normal". */
-};
-
-struct depca_tx_desc {
- volatile s32 base;
- s16 length; /* This length is negative 2's complement! */
- s16 misc; /* Errors and TDR info */
-};
-
-#define LA_MASK 0x0000ffff /* LANCE address mask for mapping network RAM
- to LANCE memory address space */
-
-/*
-** The Lance initialization block, described in databook, in common memory.
-*/
-struct depca_init {
- u16 mode; /* Mode register */
- u8 phys_addr[ETH_ALEN]; /* Physical ethernet address */
- u8 mcast_table[8]; /* Multicast Hash Table. */
- u32 rx_ring; /* Rx ring base pointer & ring length */
- u32 tx_ring; /* Tx ring base pointer & ring length */
-};
-
-#define DEPCA_PKT_STAT_SZ 16
-#define DEPCA_PKT_BIN_SZ 128 /* Should be >=100 unless you
- increase DEPCA_PKT_STAT_SZ */
-struct depca_private {
- char devname[DEPCA_STRLEN]; /* Device Product String */
- char adapter_name[DEPCA_STRLEN];/* /proc/ioports string */
- char adapter; /* Adapter type */
- char mca_slot; /* MCA slot, if MCA else -1 */
- struct depca_init init_block;/* Shadow Initialization block */
-/* CPU address space fields */
- struct depca_rx_desc *rx_ring; /* Pointer to start of RX descriptor ring */
- struct depca_tx_desc *tx_ring; /* Pointer to start of TX descriptor ring */
- void *rx_buff[NUM_RX_DESC]; /* CPU virt address of sh'd memory buffs */
- void *tx_buff[NUM_TX_DESC]; /* CPU virt address of sh'd memory buffs */
- void *sh_mem; /* CPU mapped virt address of device RAM */
-/* Device address space fields */
- u_long device_ram_start; /* Start of RAM in device addr space */
-/* Offsets used in both address spaces */
- u_long rx_ring_offset; /* Offset from start of RAM to rx_ring */
- u_long tx_ring_offset; /* Offset from start of RAM to tx_ring */
- u_long buffs_offset; /* LANCE Rx and Tx buffers start address. */
-/* Kernel-only (not device) fields */
- int rx_new, tx_new; /* The next free ring entry */
- int rx_old, tx_old; /* The ring entries to be free()ed. */
- struct net_device_stats stats;
- spinlock_t lock;
- struct { /* Private stats counters */
- u32 bins[DEPCA_PKT_STAT_SZ];
- u32 unicast;
- u32 multicast;
- u32 broadcast;
- u32 excessive_collisions;
- u32 tx_underruns;
- u32 excessive_underruns;
- } pktStats;
- int txRingMask; /* TX ring mask */
- int rxRingMask; /* RX ring mask */
- s32 rx_rlen; /* log2(rxRingMask+1) for the descriptors */
- s32 tx_rlen; /* log2(txRingMask+1) for the descriptors */
-};
-
-/*
-** The transmit ring full condition is described by the tx_old and tx_new
-** pointers by:
-** tx_old = tx_new Empty ring
-** tx_old = tx_new+1 Full ring
-** tx_old+txRingMask = tx_new Full ring (wrapped condition)
-*/
-#define TX_BUFFS_AVAIL ((lp->tx_old<=lp->tx_new)?\
- lp->tx_old+lp->txRingMask-lp->tx_new:\
- lp->tx_old -lp->tx_new-1)
-
-/*
-** Public Functions
-*/
-static int depca_open(struct net_device *dev);
-static int depca_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static void depca_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static int depca_close(struct net_device *dev);
-static int depca_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static void depca_tx_timeout (struct net_device *dev);
-static struct net_device_stats *depca_get_stats(struct net_device *dev);
-static void set_multicast_list(struct net_device *dev);
-
-/*
-** Private functions
-*/
-static int depca_hw_init(struct net_device *dev, u_long ioaddr, int mca_slot);
-static void depca_init_ring(struct net_device *dev);
-static int depca_rx(struct net_device *dev);
-static int depca_tx(struct net_device *dev);
-
-static void LoadCSRs(struct net_device *dev);
-static int InitRestartDepca(struct net_device *dev);
-static void DepcaSignature(char *name, u_long paddr);
-static int DevicePresent(u_long ioaddr);
-static int get_hw_addr(struct net_device *dev);
-static int EISA_signature(char *name, s32 eisa_id);
-static void SetMulticastFilter(struct net_device *dev);
-static void isa_probe(struct net_device *dev, u_long iobase);
-static void eisa_probe(struct net_device *dev, u_long iobase);
-#ifdef CONFIG_MCA
-static void mca_probe(struct net_device *dev, u_long iobase);
-#endif
-static struct net_device *alloc_device(struct net_device *dev, u_long iobase);
-static int depca_dev_index(char *s);
-static struct net_device *insert_device(struct net_device *dev, u_long iobase, int (*init)(struct net_device *));
-static int load_packet(struct net_device *dev, struct sk_buff *skb);
-static void depca_dbg_open(struct net_device *dev);
-
-#ifdef MODULE
-int init_module(void);
-void cleanup_module(void);
-static int autoprobed = 1, loading_module = 1;
-# else
-static u_char de1xx_irq[] __initdata = {2,3,4,5,7,9,0};
-static u_char de2xx_irq[] __initdata = {5,9,10,11,15,0};
-static u_char de422_irq[] __initdata = {5,9,10,11,0};
-static u_char *depca_irq;
-static int autoprobed, loading_module;
-#endif /* MODULE */
-
-static char name[DEPCA_STRLEN];
-static int num_depcas, num_eth;
-static int mem; /* For loadable module assignment
- use insmod mem=0x????? .... */
-static char *adapter_name; /* = '\0'; If no PROM when loadable module
- use insmod adapter_name=DE??? ...
- bss initializes this to zero
- */
-/*
-** Miscellaneous defines...
-*/
-#define STOP_DEPCA \
- outw(CSR0, DEPCA_ADDR);\
- outw(STOP, DEPCA_DATA)
-
-int __init
-depca_probe(struct net_device *dev)
-{
- int tmp = num_depcas, status = -ENODEV;
- u_long iobase = dev->base_addr;
-
- SET_MODULE_OWNER(dev);
-
- if ((iobase == 0) && loading_module){
- printk("Autoprobing is not supported when loading a module based driver.\n");
- status = -EIO;
- } else {
-#ifdef CONFIG_MCA
- mca_probe(dev, iobase);
-#endif
- isa_probe(dev, iobase);
- eisa_probe(dev, iobase);
-
- if ((tmp == num_depcas) && (iobase != 0) && loading_module) {
- printk("%s: depca_probe() cannot find device at 0x%04lx.\n", dev->name,
- iobase);
- }
-
- /*
- ** Walk the device list to check that at least one device
- ** initialised OK
- */
- for (; (dev->priv == NULL) && (dev->next != NULL); dev = dev->next);
-
- if (dev->priv) status = 0;
- if (iobase == 0) autoprobed = 1;
- }
-
- return status;
-}
-
-static int __init
-depca_hw_init(struct net_device *dev, u_long ioaddr, int mca_slot)
-{
- struct depca_private *lp;
- int i, j, offset, netRAM, mem_len, status=0;
- s16 nicsr;
- u_long mem_start=0, mem_base[] = DEPCA_RAM_BASE_ADDRESSES;
-
- STOP_DEPCA;
-
- nicsr = inb(DEPCA_NICSR);
- nicsr = ((nicsr & ~SHE & ~RBE & ~IEN) | IM);
- outb(nicsr, DEPCA_NICSR);
-
- if (inw(DEPCA_DATA) != STOP) {
- return -ENXIO;
- }
-
- do {
- strcpy(name, (adapter_name ? adapter_name : ""));
- mem_start = (mem ? mem & 0xf0000 : mem_base[mem_chkd++]);
- DepcaSignature(name, mem_start);
- } while (!mem && mem_base[mem_chkd] && (adapter == unknown));
-
- if ((adapter == unknown) || !mem_start) { /* DEPCA device not found */
- return -ENXIO;
- }
-
- dev->base_addr = ioaddr;
-
- if (mca_slot != -1) {
- printk("%s: %s at 0x%04lx (MCA slot %d)", dev->name, name,
- ioaddr, mca_slot);
- } else if ((ioaddr & 0x0fff) == DEPCA_EISA_IO_PORTS) { /* EISA slot address */
- printk("%s: %s at 0x%04lx (EISA slot %d)",
- dev->name, name, ioaddr, (int)((ioaddr>>12)&0x0f));
- } else { /* ISA port address */
- printk("%s: %s at 0x%04lx", dev->name, name, ioaddr);
- }
-
- printk(", h/w address ");
- status = get_hw_addr(dev);
- if (status != 0) {
- printk(" which has an Ethernet PROM CRC error.\n");
- return -ENXIO;
- }
- for (i=0; i<ETH_ALEN - 1; i++) { /* get the ethernet address */
- printk("%2.2x:", dev->dev_addr[i]);
- }
- printk("%2.2x", dev->dev_addr[i]);
-
- /* Set up the maximum amount of network RAM(kB) */
- netRAM = ((adapter != DEPCA) ? 64 : 48);
- if ((nicsr & _128KB) && (adapter == de422))
- netRAM = 128;
- offset = 0x0000;
-
- /* Shared Memory Base Address */
- if (nicsr & BUF) {
- offset = 0x8000; /* 32kbyte RAM offset*/
- nicsr &= ~BS; /* DEPCA RAM in top 32k */
- netRAM -= 32;
- }
- mem_start += offset; /* (E)ISA start address */
- if ((mem_len = (NUM_RX_DESC*(sizeof(struct depca_rx_desc)+RX_BUFF_SZ) +
- NUM_TX_DESC*(sizeof(struct depca_tx_desc)+TX_BUFF_SZ) +
- sizeof(struct depca_init)))
- > (netRAM<<10)) {
- printk(",\n requests %dkB RAM: only %dkB is available!\n",
- (mem_len >> 10), netRAM);
- return -ENXIO;
- }
-
- printk(",\n has %dkB RAM at 0x%.5lx", netRAM, mem_start);
-
- /* Enable the shadow RAM. */
- if (adapter != DEPCA) {
- nicsr |= SHE;
- outb(nicsr, DEPCA_NICSR);
- }
-
- /* Define the device private memory */
- dev->priv = (void *) kmalloc(sizeof(struct depca_private), GFP_KERNEL);
- if (dev->priv == NULL)
- return -ENOMEM;
- lp = (struct depca_private *)dev->priv;
- memset((char *)dev->priv, 0, sizeof(struct depca_private));
- lp->adapter = adapter;
- lp->mca_slot = mca_slot;
- lp->lock = SPIN_LOCK_UNLOCKED;
- sprintf(lp->adapter_name,"%s (%s)", name, dev->name);
- status = -EBUSY;
- if (!request_region(ioaddr, DEPCA_TOTAL_SIZE, lp->adapter_name)) {
- printk(KERN_ERR "depca: I/O resource 0x%x @ 0x%lx busy\n",
- DEPCA_TOTAL_SIZE, ioaddr);
- goto out_priv;
- }
-
- /* Initialisation Block */
- lp->sh_mem = ioremap(mem_start, mem_len);
- status = -EIO;
- if (lp->sh_mem == NULL) {
- printk(KERN_ERR "depca: cannot remap ISA memory, aborting\n");
- goto out_region;
- }
- lp->device_ram_start = mem_start & LA_MASK;
-
- offset = 0;
- offset += sizeof(struct depca_init);
-
- /* Tx & Rx descriptors (aligned to a quadword boundary) */
- offset = (offset + ALIGN) & ~ALIGN;
- lp->rx_ring = (struct depca_rx_desc *)(lp->sh_mem + offset);
- lp->rx_ring_offset = offset;
-
- offset += (sizeof(struct depca_rx_desc) * NUM_RX_DESC);
- lp->tx_ring = (struct depca_tx_desc *)(lp->sh_mem + offset);
- lp->tx_ring_offset = offset;
-
- offset += (sizeof(struct depca_tx_desc) * NUM_TX_DESC);
-
- lp->buffs_offset = offset;
-
- /* Finish initialising the ring information. */
- lp->rxRingMask = NUM_RX_DESC - 1;
- lp->txRingMask = NUM_TX_DESC - 1;
-
- /* Calculate Tx/Rx RLEN size for the descriptors. */
- for (i=0, j = lp->rxRingMask; j>0; i++) {
- j >>= 1;
- }
- lp->rx_rlen = (s32)(i << 29);
- for (i=0, j = lp->txRingMask; j>0; i++) {
- j >>= 1;
- }
- lp->tx_rlen = (s32)(i << 29);
-
- /* Load the initialisation block */
- depca_init_ring(dev);
-
- /* Initialise the control and status registers */
- LoadCSRs(dev);
-
- /* Enable DEPCA board interrupts for autoprobing */
- nicsr = ((nicsr & ~IM)|IEN);
- outb(nicsr, DEPCA_NICSR);
-
- /* To auto-IRQ we enable the initialization-done and DMA err,
- interrupts. For now we will always get a DMA error. */
- if (dev->irq < 2) {
-#ifndef MODULE
- unsigned char irqnum;
- autoirq_setup(0);
-
- /* Assign the correct irq list */
- switch (lp->adapter) {
- case DEPCA:
- case de100:
- case de101:
- depca_irq = de1xx_irq;
- break;
- case de200:
- case de201:
- case de202:
- case de210:
- case de212:
- depca_irq = de2xx_irq;
- break;
- case de422:
- depca_irq = de422_irq;
- break;
- }
-
- /* Trigger an initialization just for the interrupt. */
- outw(INEA | INIT, DEPCA_DATA);
-
- irqnum = autoirq_report(1);
- status = -ENXIO;
- if (!irqnum) {
- printk(" and failed to detect IRQ line.\n");
- goto out_region;
- } else {
- for (dev->irq=0,i=0; (depca_irq[i]) && (!dev->irq); i++)
- if (irqnum == depca_irq[i]) {
- dev->irq = irqnum;
- printk(" and uses IRQ%d.\n", dev->irq);
- }
-
- status = -ENXIO;
- if (!dev->irq) {
- printk(" but incorrect IRQ line detected.\n");
- goto out_region;
- }
- }
-#endif /* MODULE */
- } else {
- printk(" and assigned IRQ%d.\n", dev->irq);
- }
-
- if (depca_debug > 1) {
- printk(version);
- }
-
- /* The DEPCA-specific entries in the device structure. */
- dev->open = &depca_open;
- dev->hard_start_xmit = &depca_start_xmit;
- dev->stop = &depca_close;
- dev->get_stats = &depca_get_stats;
- dev->set_multicast_list = &set_multicast_list;
- dev->do_ioctl = &depca_ioctl;
- dev->tx_timeout = depca_tx_timeout;
- dev->watchdog_timeo = TX_TIMEOUT;
-
- dev->mem_start = 0;
-
- /* Fill in the generic field of the device structure. */
- ether_setup(dev);
- return 0;
-out_region:
- release_region(ioaddr, DEPCA_TOTAL_SIZE);
-out_priv:
- kfree(dev->priv);
- dev->priv = NULL;
- return status;
-}
-
-\f
-static int
-depca_open(struct net_device *dev)
-{
- struct depca_private *lp = (struct depca_private *)dev->priv;
- u_long ioaddr = dev->base_addr;
- s16 nicsr;
- int status = 0;
-
- STOP_DEPCA;
- nicsr = inb(DEPCA_NICSR);
-
- /* Make sure the shadow RAM is enabled */
- if (lp->adapter != DEPCA) {
- nicsr |= SHE;
- outb(nicsr, DEPCA_NICSR);
- }
-
- /* Re-initialize the DEPCA... */
- depca_init_ring(dev);
- LoadCSRs(dev);
-
- depca_dbg_open(dev);
-
- if (request_irq(dev->irq, &depca_interrupt, 0, lp->adapter_name, dev)) {
- printk("depca_open(): Requested IRQ%d is busy\n",dev->irq);
- status = -EAGAIN;
- } else {
-
- /* Enable DEPCA board interrupts and turn off LED */
- nicsr = ((nicsr & ~IM & ~LED)|IEN);
- outb(nicsr, DEPCA_NICSR);
- outw(CSR0,DEPCA_ADDR);
-
- netif_start_queue(dev);
-
- status = InitRestartDepca(dev);
-
- if (depca_debug > 1){
- printk("CSR0: 0x%4.4x\n",inw(DEPCA_DATA));
- printk("nicsr: 0x%02x\n",inb(DEPCA_NICSR));
- }
- }
- return status;
-}
-
-/* Initialize the lance Rx and Tx descriptor rings. */
-static void
-depca_init_ring(struct net_device *dev)
-{
- struct depca_private *lp = (struct depca_private *)dev->priv;
- u_int i;
- u_long offset;
-
- /* Lock out other processes whilst setting up the hardware */
- netif_stop_queue(dev);
-
- lp->rx_new = lp->tx_new = 0;
- lp->rx_old = lp->tx_old = 0;
-
- /* Initialize the base address and length of each buffer in the ring */
- for (i = 0; i <= lp->rxRingMask; i++) {
- offset = lp->buffs_offset + i*RX_BUFF_SZ;
- writel((lp->device_ram_start + offset) | R_OWN,
- &lp->rx_ring[i].base);
- writew(-RX_BUFF_SZ, &lp->rx_ring[i].buf_length);
- lp->rx_buff[i] = lp->sh_mem + offset;
- }
-
- for (i = 0; i <= lp->txRingMask; i++) {
- offset = lp->buffs_offset + (i + lp->rxRingMask+1)*TX_BUFF_SZ;
- writel((lp->device_ram_start + offset) & 0x00ffffff,
- &lp->tx_ring[i].base);
- lp->tx_buff[i] = lp->sh_mem + offset;
- }
-
- /* Set up the initialization block */
- lp->init_block.rx_ring = (lp->device_ram_start + lp->rx_ring_offset) | lp->rx_rlen;
- lp->init_block.tx_ring = (lp->device_ram_start + lp->tx_ring_offset) | lp->tx_rlen;
-
- SetMulticastFilter(dev);
-
- for (i = 0; i < ETH_ALEN; i++) {
- lp->init_block.phys_addr[i] = dev->dev_addr[i];
- }
-
- lp->init_block.mode = 0x0000; /* Enable the Tx and Rx */
-}
-
-
-static void depca_tx_timeout (struct net_device *dev)
-{
- u_long ioaddr = dev->base_addr;
-
- printk ("%s: transmit timed out, status %04x, resetting.\n",
- dev->name, inw (DEPCA_DATA));
-
- STOP_DEPCA;
- depca_init_ring (dev);
- LoadCSRs (dev);
- dev->trans_start = jiffies;
- netif_wake_queue (dev);
- InitRestartDepca (dev);
-}
-
-
-/*
-** Writes a socket buffer to TX descriptor ring and starts transmission
-*/
-static int depca_start_xmit (struct sk_buff *skb, struct net_device *dev)
-{
- struct depca_private *lp = (struct depca_private *) dev->priv;
- u_long ioaddr = dev->base_addr;
- int status = 0;
-
- /* Transmitter timeout, serious problems. */
- if (skb->len < 1)
- goto out;
-
- netif_stop_queue (dev);
-
- if (TX_BUFFS_AVAIL) { /* Fill in a Tx ring entry */
- status = load_packet (dev, skb);
-
- if (!status) {
- /* Trigger an immediate send demand. */
- outw (CSR0, DEPCA_ADDR);
- outw (INEA | TDMD, DEPCA_DATA);
-
- dev->trans_start = jiffies;
- dev_kfree_skb (skb);
- }
- if (TX_BUFFS_AVAIL)
- netif_start_queue (dev);
- } else
- status = -1;
-
-out:
- return status;
-}
-
-/*
-** The DEPCA interrupt handler.
-*/
-static void depca_interrupt (int irq, void *dev_id, struct pt_regs *regs)
-{
- struct net_device *dev = dev_id;
- struct depca_private *lp;
- s16 csr0, nicsr;
- u_long ioaddr;
-
- if (dev == NULL) {
- printk ("depca_interrupt(): irq %d for unknown device.\n", irq);
- return;
- }
-
- lp = (struct depca_private *) dev->priv;
- ioaddr = dev->base_addr;
-
- spin_lock (&lp->lock);
-
- /* mask the DEPCA board interrupts and turn on the LED */
- nicsr = inb (DEPCA_NICSR);
- nicsr |= (IM | LED);
- outb (nicsr, DEPCA_NICSR);
-
- outw (CSR0, DEPCA_ADDR);
- csr0 = inw (DEPCA_DATA);
-
- /* Acknowledge all of the current interrupt sources ASAP. */
- outw (csr0 & INTE, DEPCA_DATA);
-
- if (csr0 & RINT) /* Rx interrupt (packet arrived) */
- depca_rx (dev);
-
- if (csr0 & TINT) /* Tx interrupt (packet sent) */
- depca_tx (dev);
-
- /* Any resources available? */
- if ((TX_BUFFS_AVAIL >= 0) && netif_queue_stopped(dev)) {
- netif_wake_queue (dev);
- }
-
- /* Unmask the DEPCA board interrupts and turn off the LED */
- nicsr = (nicsr & ~IM & ~LED);
- outb (nicsr, DEPCA_NICSR);
-
- spin_unlock (&lp->lock);
-}
-
-
-static int
-depca_rx(struct net_device *dev)
-{
- struct depca_private *lp = (struct depca_private *)dev->priv;
- int i, entry;
- s32 status;
-
- for (entry=lp->rx_new;
- !(readl(&lp->rx_ring[entry].base) & R_OWN);
- entry=lp->rx_new){
- status = readl(&lp->rx_ring[entry].base) >> 16 ;
- if (status & R_STP) { /* Remember start of frame */
- lp->rx_old = entry;
- }
- if (status & R_ENP) { /* Valid frame status */
- if (status & R_ERR) { /* There was an error. */
- lp->stats.rx_errors++; /* Update the error stats. */
- if (status & R_FRAM) lp->stats.rx_frame_errors++;
- if (status & R_OFLO) lp->stats.rx_over_errors++;
- if (status & R_CRC) lp->stats.rx_crc_errors++;
- if (status & R_BUFF) lp->stats.rx_fifo_errors++;
- } else {
- short len, pkt_len = readw(&lp->rx_ring[entry].msg_length) - 4;
- struct sk_buff *skb;
-
- skb = dev_alloc_skb(pkt_len+2);
- if (skb != NULL) {
- unsigned char *buf;
- skb_reserve(skb,2); /* 16 byte align the IP header */
- buf = skb_put(skb,pkt_len);
- skb->dev = dev;
- if (entry < lp->rx_old) { /* Wrapped buffer */
- len = (lp->rxRingMask - lp->rx_old + 1) * RX_BUFF_SZ;
- memcpy_fromio(buf, lp->rx_buff[lp->rx_old], len);
- memcpy_fromio(buf + len, lp->rx_buff[0], pkt_len-len);
- } else { /* Linear buffer */
- memcpy_fromio(buf, lp->rx_buff[lp->rx_old], pkt_len);
- }
-
- /*
- ** Notify the upper protocol layers that there is another
- ** packet to handle
- */
- skb->protocol=eth_type_trans(skb,dev);
- netif_rx(skb);
-
- /*
- ** Update stats
- */
- dev->last_rx = jiffies;
- lp->stats.rx_packets++;
- lp->stats.rx_bytes += pkt_len;
- for (i=1; i<DEPCA_PKT_STAT_SZ-1; i++) {
- if (pkt_len < (i*DEPCA_PKT_BIN_SZ)) {
- lp->pktStats.bins[i]++;
- i = DEPCA_PKT_STAT_SZ;
- }
- }
- if (buf[0] & 0x01) { /* Multicast/Broadcast */
- if ((*(s16 *)&buf[0] == -1) &&
- (*(s16 *)&buf[2] == -1) &&
- (*(s16 *)&buf[4] == -1)) {
- lp->pktStats.broadcast++;
- } else {
- lp->pktStats.multicast++;
- }
- } else if ((*(s16 *)&buf[0] == *(s16 *)&dev->dev_addr[0]) &&
- (*(s16 *)&buf[2] == *(s16 *)&dev->dev_addr[2]) &&
- (*(s16 *)&buf[4] == *(s16 *)&dev->dev_addr[4])) {
- lp->pktStats.unicast++;
- }
-
- lp->pktStats.bins[0]++; /* Duplicates stats.rx_packets */
- if (lp->pktStats.bins[0] == 0) { /* Reset counters */
- memset((char *)&lp->pktStats, 0, sizeof(lp->pktStats));
- }
- } else {
- printk("%s: Memory squeeze, deferring packet.\n", dev->name);
- lp->stats.rx_dropped++; /* Really, deferred. */
- break;
- }
- }
- /* Change buffer ownership for this last frame, back to the adapter */
- for (; lp->rx_old!=entry; lp->rx_old=(++lp->rx_old)&lp->rxRingMask) {
- writel(readl(&lp->rx_ring[lp->rx_old].base) | R_OWN,
- &lp->rx_ring[lp->rx_old].base);
- }
- writel(readl(&lp->rx_ring[entry].base) | R_OWN, &lp->rx_ring[entry].base);
- }
-
- /*
- ** Update entry information
- */
- lp->rx_new = (++lp->rx_new) & lp->rxRingMask;
- }
-
- return 0;
-}
-
-/*
-** Buffer sent - check for buffer errors.
-*/
-static int
-depca_tx(struct net_device *dev)
-{
- struct depca_private *lp = (struct depca_private *)dev->priv;
- int entry;
- s32 status;
- u_long ioaddr = dev->base_addr;
-
- for (entry = lp->tx_old; entry != lp->tx_new; entry = lp->tx_old) {
- status = readl(&lp->tx_ring[entry].base) >> 16 ;
-
- if (status < 0) { /* Packet not yet sent! */
- break;
- } else if (status & T_ERR) { /* An error occurred. */
- status = readl(&lp->tx_ring[entry].misc);
- lp->stats.tx_errors++;
- if (status & TMD3_RTRY) lp->stats.tx_aborted_errors++;
- if (status & TMD3_LCAR) lp->stats.tx_carrier_errors++;
- if (status & TMD3_LCOL) lp->stats.tx_window_errors++;
- if (status & TMD3_UFLO) lp->stats.tx_fifo_errors++;
- if (status & (TMD3_BUFF | TMD3_UFLO)) {
- /* Trigger an immediate send demand. */
- outw(CSR0, DEPCA_ADDR);
- outw(INEA | TDMD, DEPCA_DATA);
- }
- } else if (status & (T_MORE | T_ONE)) {
- lp->stats.collisions++;
- } else {
- lp->stats.tx_packets++;
- }
-
- /* Update all the pointers */
- lp->tx_old = (++lp->tx_old) & lp->txRingMask;
- }
-
- return 0;
-}
-
-static int
-depca_close(struct net_device *dev)
-{
- struct depca_private *lp = (struct depca_private *)dev->priv;
- s16 nicsr;
- u_long ioaddr = dev->base_addr;
-
- netif_stop_queue(dev);
-
- outw(CSR0, DEPCA_ADDR);
-
- if (depca_debug > 1) {
- printk("%s: Shutting down ethercard, status was %2.2x.\n",
- dev->name, inw(DEPCA_DATA));
- }
-
- /*
- ** We stop the DEPCA here -- it occasionally polls
- ** memory if we don't.
- */
- outw(STOP, DEPCA_DATA);
-
- /*
- ** Give back the ROM in case the user wants to go to DOS
- */
- if (lp->adapter != DEPCA) {
- nicsr = inb(DEPCA_NICSR);
- nicsr &= ~SHE;
- outb(nicsr, DEPCA_NICSR);
- }
-
- /*
- ** Free the associated irq
- */
- free_irq(dev->irq, dev);
- return 0;
-}
-
-static void LoadCSRs(struct net_device *dev)
-{
- struct depca_private *lp = (struct depca_private *)dev->priv;
- u_long ioaddr = dev->base_addr;
-
- outw(CSR1, DEPCA_ADDR); /* initialisation block address LSW */
- outw((u16)lp->device_ram_start, DEPCA_DATA);
- outw(CSR2, DEPCA_ADDR); /* initialisation block address MSW */
- outw((u16)(lp->device_ram_start >> 16), DEPCA_DATA);
- outw(CSR3, DEPCA_ADDR); /* ALE control */
- outw(ACON, DEPCA_DATA);
-
- outw(CSR0, DEPCA_ADDR); /* Point back to CSR0 */
-
- return;
-}
-
-static int InitRestartDepca(struct net_device *dev)
-{
- struct depca_private *lp = (struct depca_private *)dev->priv;
- u_long ioaddr = dev->base_addr;
- int i, status=0;
-
- /* Copy the shadow init_block to shared memory */
- memcpy_toio(lp->sh_mem, &lp->init_block, sizeof(struct depca_init));
-
- outw(CSR0, DEPCA_ADDR); /* point back to CSR0 */
- outw(INIT, DEPCA_DATA); /* initialize DEPCA */
-
- /* wait for lance to complete initialisation */
- for (i=0;(i<100) && !(inw(DEPCA_DATA) & IDON); i++);
-
- if (i!=100) {
- /* clear IDON by writing a "1", enable interrupts and start lance */
- outw(IDON | INEA | STRT, DEPCA_DATA);
- if (depca_debug > 2) {
- printk("%s: DEPCA open after %d ticks, init block 0x%08lx csr0 %4.4x.\n",
- dev->name, i, virt_to_phys(lp->sh_mem), inw(DEPCA_DATA));
- }
- } else {
- printk("%s: DEPCA unopen after %d ticks, init block 0x%08lx csr0 %4.4x.\n",
- dev->name, i, virt_to_phys(lp->sh_mem), inw(DEPCA_DATA));
- status = -1;
- }
-
- return status;
-}
-
-static struct net_device_stats *
-depca_get_stats(struct net_device *dev)
-{
- struct depca_private *lp = (struct depca_private *)dev->priv;
-
- /* Null body since there is no framing error counter */
-
- return &lp->stats;
-}
-
-/*
-** Set or clear the multicast filter for this adaptor.
-*/
-static void
-set_multicast_list(struct net_device *dev)
-{
- struct depca_private *lp = (struct depca_private *)dev->priv;
- u_long ioaddr = dev->base_addr;
-
- if (dev) {
- netif_stop_queue(dev);
- while(lp->tx_old != lp->tx_new); /* Wait for the ring to empty */
-
- STOP_DEPCA; /* Temporarily stop the depca. */
- depca_init_ring(dev); /* Initialize the descriptor rings */
-
- if (dev->flags & IFF_PROMISC) { /* Set promiscuous mode */
- lp->init_block.mode |= PROM;
- } else {
- SetMulticastFilter(dev);
- lp->init_block.mode &= ~PROM; /* Unset promiscuous mode */
- }
-
- LoadCSRs(dev); /* Reload CSR3 */
- InitRestartDepca(dev); /* Resume normal operation. */
- netif_start_queue(dev); /* Unlock the TX ring */
- }
-}
-
-/*
-** Calculate the hash code and update the logical address filter
-** from a list of ethernet multicast addresses.
-** Big endian crc one liner is mine, all mine, ha ha ha ha!
-** LANCE calculates its hash codes big endian.
-*/
-static void SetMulticastFilter(struct net_device *dev)
-{
- struct depca_private *lp = (struct depca_private *)dev->priv;
- struct dev_mc_list *dmi=dev->mc_list;
- char *addrs;
- int i, j, bit, byte;
- u16 hashcode;
- s32 crc, poly = CRC_POLYNOMIAL_BE;
-
- if (dev->flags & IFF_ALLMULTI) { /* Set all multicast bits */
- for (i=0; i<(HASH_TABLE_LEN>>3); i++) {
- lp->init_block.mcast_table[i] = (char)0xff;
- }
- } else {
- for (i=0; i<(HASH_TABLE_LEN>>3); i++){ /* Clear the multicast table */
- lp->init_block.mcast_table[i]=0;
- }
- /* Add multicast addresses */
- for (i=0;i<dev->mc_count;i++) { /* for each address in the list */
- addrs=dmi->dmi_addr;
- dmi=dmi->next;
- if ((*addrs & 0x01) == 1) { /* multicast address? */
- crc = 0xffffffff; /* init CRC for each address */
- for (byte=0;byte<ETH_ALEN;byte++) {/* for each address byte */
- /* process each address bit */
- for (bit = *addrs++,j=0;j<8;j++, bit>>=1) {
- crc = (crc << 1) ^ ((((crc<0?1:0) ^ bit) & 0x01) ? poly : 0);
- }
- }
- hashcode = (crc & 1); /* hashcode is 6 LSb of CRC ... */
- for (j=0;j<5;j++) { /* ... in reverse order. */
- hashcode = (hashcode << 1) | ((crc>>=1) & 1);
- }
-
-
- byte = hashcode >> 3; /* bit[3-5] -> byte in filter */
- bit = 1 << (hashcode & 0x07); /* bit[0-2] -> bit in byte */
- lp->init_block.mcast_table[byte] |= bit;
- }
- }
- }
-
- return;
-}
-
-#ifdef CONFIG_MCA
-/*
-** Microchannel bus I/O device probe
-*/
-static void __init
-mca_probe(struct net_device *dev, u_long ioaddr)
-{
- unsigned char pos[2];
- unsigned char where;
- unsigned long iobase;
- int irq;
- int slot = 0;
-
- /*
- ** See if we've been here before.
- */
- if ((!ioaddr && autoprobed) || (ioaddr && !loading_module)) return;
-
- if (MCA_bus) {
- /*
- ** Search for the adapter. If an address has been given, search
- ** specifically for the card at that address. Otherwise find the
- ** first card in the system.
- */
- while ((dev!=NULL) &&
- ((slot=mca_find_adapter(DE212_ID, slot)) != MCA_NOTFOUND)) {
- pos[0] = mca_read_stored_pos(slot, 2);
- pos[1] = mca_read_stored_pos(slot, 3);
-
- /*
- ** IO of card is handled by bits 1 and 2 of pos0.
- **
- ** bit2 bit1 IO
- ** 0 0 0x2c00
- ** 0 1 0x2c10
- ** 1 0 0x2c20
- ** 1 1 0x2c30
- */
- where = (pos[0] & 6) >> 1;
- iobase = 0x2c00 + (0x10 * where);
-
- if ((ioaddr) && (ioaddr != iobase)) {
- /*
- ** Card was found, but not at the right IO location. Continue
- ** scanning from the next MCA slot up for another card.
- */
- slot++;
- continue;
- }
-
- /*
- ** Found the adapter we were looking for. Now start setting it up.
- **
- ** First work on decoding the IRQ. It's stored in the lower 4 bits
- ** of pos1. Bits are as follows (from the ADF file):
- **
- ** Bits
- ** 3 2 1 0 IRQ
- ** --------------------
- ** 0 0 1 0 5
- ** 0 0 0 1 9
- ** 0 1 0 0 10
- ** 1 0 0 0 11
- **/
- where = pos[1] & 0x0f;
- switch(where) {
- case 1:
- irq = 9;
- break;
- case 2:
- irq = 5;
- break;
- case 4:
- irq = 10;
- break;
- case 8:
- irq = 11;
- break;
- default:
- printk("%s: mca_probe IRQ error. You should never get here (%d).\n", dev->name, where);
- return;
- }
-
- /*
- ** Shared memory address of adapter is stored in bits 3-5 of pos0.
- ** They are mapped as follows:
- **
- ** Bit
- ** 5 4 3 Memory Addresses
- ** 0 0 0 C0000-CFFFF (64K)
- ** 1 0 0 C8000-CFFFF (32K)
- ** 0 0 1 D0000-DFFFF (64K)
- ** 1 0 1 D8000-DFFFF (32K)
- ** 0 1 0 E0000-EFFFF (64K)
- ** 1 1 0 E8000-EFFFF (32K)
- */
- where = (pos[0] & 0x18) >> 3;
- mem = 0xc0000 + (where * 0x10000);
- if (pos[0] & 0x20) {
- mem += 0x8000;
- }
-
- /*
- ** Get everything allocated and initialized... (almost just
- ** like the ISA and EISA probes)
- */
- if (DevicePresent(iobase) != 0) {
- /*
- ** If the MCA configuration says the card should be here,
- ** it really should be here.
- */
- printk(KERN_ERR "%s: MCA reports card at 0x%lx but it is not
-responding.\n", dev->name, iobase);
- }
-
- if (check_region(iobase, DEPCA_TOTAL_SIZE) == 0) {
- if ((dev = alloc_device(dev, iobase)) != NULL) {
- dev->irq = irq;
- if (depca_hw_init(dev, iobase, slot) == 0) {
- /*
- ** Adapter initialized correctly: Name it in
- ** /proc/mca.
- */
- mca_set_adapter_name(slot, "DE210/212 Ethernet Adapter");
- mca_mark_as_used(slot);
- num_depcas++;
- }
- num_eth++;
- }
- } else if (autoprobed) {
- printk(KERN_WARNING "%s: region already allocated at 0x%04lx.\n", dev->name, iobase);
- }
-
- /*
- ** If this is a probe by a module, return after setting up the
- ** given card.
- */
- if (ioaddr) return;
-
- /*
- ** Set up to check the next slot and loop.
- */
- slot++;
- }
- }
-
- return;
-}
-#endif
-
-/*
-** ISA bus I/O device probe
-*/
-static void __init
-isa_probe(struct net_device *dev, u_long ioaddr)
-{
- int i = num_depcas, maxSlots;
- s32 ports[] = DEPCA_IO_PORTS;
-
- if (!ioaddr && autoprobed) return ; /* Been here before ! */
- if (ioaddr > 0x400) return; /* EISA Address */
- if (i >= MAX_NUM_DEPCAS) return; /* Too many ISA adapters */
-
- if (ioaddr == 0) { /* Autoprobing */
- maxSlots = MAX_NUM_DEPCAS;
- } else { /* Probe a specific location */
- ports[i] = ioaddr;
- maxSlots = i + 1;
- }
-
- for (; (i<maxSlots) && (dev!=NULL) && ports[i]; i++) {
- if (check_region(ports[i], DEPCA_TOTAL_SIZE) == 0) {
- if (DevicePresent(ports[i]) == 0) {
- if ((dev = alloc_device(dev, ports[i])) != NULL) {
- if (depca_hw_init(dev, ports[i], -1) == 0) {
- num_depcas++;
- }
- num_eth++;
- }
- }
- } else if (autoprobed) {
- printk("%s: region already allocated at 0x%04x.\n", dev->name, ports[i]);
- }
- }
-
- return;
-}
-
-/*
-** EISA bus I/O device probe. Probe from slot 1 since slot 0 is usually
-** the motherboard. Upto 15 EISA devices are supported.
-*/
-static void __init
-eisa_probe(struct net_device *dev, u_long ioaddr)
-{
- int i, maxSlots;
- u_long iobase;
- char name[DEPCA_STRLEN];
-
- if (!ioaddr && autoprobed) return ; /* Been here before ! */
- if ((ioaddr < 0x400) && (ioaddr > 0)) return; /* ISA Address */
-
- if (ioaddr == 0) { /* Autoprobing */
- iobase = EISA_SLOT_INC; /* Get the first slot address */
- i = 1;
- maxSlots = MAX_EISA_SLOTS;
- } else { /* Probe a specific location */
- iobase = ioaddr;
- i = (ioaddr >> 12);
- maxSlots = i + 1;
- }
- if ((iobase & 0x0fff) == 0) iobase += DEPCA_EISA_IO_PORTS;
-
- for (; (i<maxSlots) && (dev!=NULL); i++, iobase+=EISA_SLOT_INC) {
- if (check_region(iobase, DEPCA_TOTAL_SIZE) == 0) {
- if (EISA_signature(name, EISA_ID)) {
- if (DevicePresent(iobase) == 0) {
- if ((dev = alloc_device(dev, iobase)) != NULL) {
- if (depca_hw_init(dev, iobase, -1) == 0) {
- num_depcas++;
- }
- num_eth++;
- }
- }
- }
- } else if (autoprobed) {
- printk("%s: region already allocated at 0x%04lx.\n", dev->name, iobase);
- }
- }
-
- return;
-}
-
-/*
-** Search the entire 'eth' device list for a fixed probe. If a match isn't
-** found then check for an autoprobe or unused device location. If they
-** are not available then insert a new device structure at the end of
-** the current list.
-*/
-static struct net_device * __init
-alloc_device(struct net_device *dev, u_long iobase)
-{
- struct net_device *adev = NULL;
- int fixed = 0, new_dev = 0;
-
- num_eth = depca_dev_index(dev->name);
- if (loading_module) return dev;
-
- while (1) {
- if (((dev->base_addr == DEPCA_NDA) || (dev->base_addr==0)) && !adev) {
- adev=dev;
- } else if ((dev->priv == NULL) && (dev->base_addr==iobase)) {
- fixed = 1;
- } else {
- if (dev->next == NULL) {
- new_dev = 1;
- } else if (strncmp(dev->next->name, "eth", 3) != 0) {
- new_dev = 1;
- }
- }
- if ((dev->next == NULL) || new_dev || fixed) break;
- dev = dev->next;
- num_eth++;
- }
- if (adev && !fixed) {
- dev = adev;
- num_eth = depca_dev_index(dev->name);
- new_dev = 0;
- }
-
- if (((dev->next == NULL) &&
- ((dev->base_addr != DEPCA_NDA) && (dev->base_addr != 0)) && !fixed) ||
- new_dev) {
- num_eth++; /* New device */
- dev = insert_device(dev, iobase, depca_probe);
- }
-
- return dev;
-}
-
-/*
-** If at end of eth device list and can't use current entry, malloc
-** one up. If memory could not be allocated, print an error message.
-*/
-static struct net_device * __init
-insert_device(struct net_device *dev, u_long iobase, int (*init)(struct net_device *))
-{
- struct net_device *new;
-
- new = (struct net_device *)kmalloc(sizeof(struct net_device), GFP_KERNEL);
- if (new == NULL) {
- printk("eth%d: Device not initialised, insufficient memory\n",num_eth);
- return NULL;
- } else {
- new->next = dev->next;
- dev->next = new;
- dev = dev->next; /* point to the new device */
- if (num_eth > 9999) {
- sprintf(dev->name,"eth????");/* New device name */
- } else {
- sprintf(dev->name,"eth%d", num_eth);/* New device name */
- }
- dev->base_addr = iobase; /* assign the io address */
- dev->init = init; /* initialisation routine */
- }
-
- return dev;
-}
-
-static int __init
-depca_dev_index(char *s)
-{
- int i=0, j=0;
-
- for (;*s; s++) {
- if (isdigit(*s)) {
- j=1;
- i = (i * 10) + (*s - '0');
- } else if (j) break;
- }
-
- return i;
-}
-
-/*
-** Look for a particular board name in the on-board Remote Diagnostics
-** and Boot (readb) ROM. This will also give us a clue to the network RAM
-** base address.
-*/
-static void __init
-DepcaSignature(char *name, u_long paddr)
-{
- u_int i,j,k;
- const char *signatures[] = DEPCA_SIGNATURE;
- void *ptr;
- char tmpstr[16];
-
- /* Copy the first 16 bytes of ROM */
- ptr = ioremap(paddr + 0xc000, 16);
- if (ptr == NULL) {
- printk(KERN_ERR "depca: I/O remap failed at %lx\n", paddr+0xc000);
- adapter = unknown;
- return;
- }
- for (i=0;i<16;i++) {
- tmpstr[i] = readb(ptr + i);
- }
- iounmap(ptr);
-
- /* Check if PROM contains a valid string */
- for (i=0;*signatures[i]!='\0';i++) {
- for (j=0,k=0;j<16 && k<strlen(signatures[i]);j++) {
- if (signatures[i][k] == tmpstr[j]) { /* track signature */
- k++;
- } else { /* lost signature; begin search again */
- k=0;
- }
- }
- if (k == strlen(signatures[i])) break;
- }
-
- /* Check if name string is valid, provided there's no PROM */
- if (*name && (i == unknown)) {
- for (i=0;*signatures[i]!='\0';i++) {
- if (strcmp(name,signatures[i]) == 0) break;
- }
- }
-
- /* Update search results */
- strcpy(name,signatures[i]);
- adapter = i;
-
- return;
-}
-
-/*
-** Look for a special sequence in the Ethernet station address PROM that
-** is common across all DEPCA products. Note that the original DEPCA needs
-** its ROM address counter to be initialized and enabled. Only enable
-** if the first address octet is a 0x08 - this minimises the chances of
-** messing around with some other hardware, but it assumes that this DEPCA
-** card initialized itself correctly.
-**
-** Search the Ethernet address ROM for the signature. Since the ROM address
-** counter can start at an arbitrary point, the search must include the entire
-** probe sequence length plus the (length_of_the_signature - 1).
-** Stop the search IMMEDIATELY after the signature is found so that the
-** PROM address counter is correctly positioned at the start of the
-** ethernet address for later read out.
-*/
-static int __init
-DevicePresent(u_long ioaddr)
-{
- union {
- struct {
- u32 a;
- u32 b;
- } llsig;
- char Sig[sizeof(u32) << 1];
- } dev;
- short sigLength=0;
- s8 data;
- s16 nicsr;
- int i, j, status = 0;
-
- data = inb(DEPCA_PROM); /* clear counter on DEPCA */
- data = inb(DEPCA_PROM); /* read data */
-
- if (data == 0x08) { /* Enable counter on DEPCA */
- nicsr = inb(DEPCA_NICSR);
- nicsr |= AAC;
- outb(nicsr, DEPCA_NICSR);
- }
-
- dev.llsig.a = ETH_PROM_SIG;
- dev.llsig.b = ETH_PROM_SIG;
- sigLength = sizeof(u32) << 1;
-
- for (i=0,j=0;j<sigLength && i<PROBE_LENGTH+sigLength-1;i++) {
- data = inb(DEPCA_PROM);
- if (dev.Sig[j] == data) { /* track signature */
- j++;
- } else { /* lost signature; begin search again */
- if (data == dev.Sig[0]) { /* rare case.... */
- j=1;
- } else {
- j=0;
- }
- }
- }
-
- if (j!=sigLength) {
- status = -ENODEV; /* search failed */
- }
-
- return status;
-}
-
-/*
-** The DE100 and DE101 PROM accesses were made non-standard for some bizarre
-** reason: access the upper half of the PROM with x=0; access the lower half
-** with x=1.
-*/
-static int __init
-get_hw_addr(struct net_device *dev)
-{
- u_long ioaddr = dev->base_addr;
- int i, k, tmp, status = 0;
- u_short j, x, chksum;
-
- x = (((adapter == de100) || (adapter == de101)) ? 1 : 0);
-
- for (i=0,k=0,j=0;j<3;j++) {
- k <<= 1 ;
- if (k > 0xffff) k-=0xffff;
-
- k += (u_char) (tmp = inb(DEPCA_PROM + x));
- dev->dev_addr[i++] = (u_char) tmp;
- k += (u_short) ((tmp = inb(DEPCA_PROM + x)) << 8);
- dev->dev_addr[i++] = (u_char) tmp;
-
- if (k > 0xffff) k-=0xffff;
- }
- if (k == 0xffff) k=0;
-
- chksum = (u_char) inb(DEPCA_PROM + x);
- chksum |= (u_short) (inb(DEPCA_PROM + x) << 8);
- if (k != chksum) status = -1;
-
- return status;
-}
-
-/*
-** Load a packet into the shared memory
-*/
-static int load_packet(struct net_device *dev, struct sk_buff *skb)
-{
- struct depca_private *lp = (struct depca_private *)dev->priv;
- int i, entry, end, len, status = 0;
-
- entry = lp->tx_new; /* Ring around buffer number. */
- end = (entry + (skb->len - 1) / TX_BUFF_SZ) & lp->txRingMask;
- if (!(readl(&lp->tx_ring[end].base) & T_OWN)) {/* Enough room? */
- /*
- ** Caution: the write order is important here... don't set up the
- ** ownership rights until all the other information is in place.
- */
- if (end < entry) { /* wrapped buffer */
- len = (lp->txRingMask - entry + 1) * TX_BUFF_SZ;
- memcpy_toio(lp->tx_buff[entry], skb->data, len);
- memcpy_toio(lp->tx_buff[0], skb->data + len, skb->len - len);
- } else { /* linear buffer */
- memcpy_toio(lp->tx_buff[entry], skb->data, skb->len);
- }
-
- /* set up the buffer descriptors */
- len = (skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len;
- for (i = entry; i != end; i = (++i) & lp->txRingMask) {
- /* clean out flags */
- writel(readl(&lp->tx_ring[i].base) & ~T_FLAGS, &lp->tx_ring[i].base);
- writew(0x0000, &lp->tx_ring[i].misc); /* clears other error flags */
- writew(-TX_BUFF_SZ, &lp->tx_ring[i].length);/* packet length in buffer */
- len -= TX_BUFF_SZ;
- }
- /* clean out flags */
- writel(readl(&lp->tx_ring[end].base) & ~T_FLAGS, &lp->tx_ring[end].base);
- writew(0x0000, &lp->tx_ring[end].misc); /* clears other error flags */
- writew(-len, &lp->tx_ring[end].length); /* packet length in last buff */
-
- /* start of packet */
- writel(readl(&lp->tx_ring[entry].base) | T_STP, &lp->tx_ring[entry].base);
- /* end of packet */
- writel(readl(&lp->tx_ring[end].base) | T_ENP, &lp->tx_ring[end].base);
-
- for (i=end; i!=entry; --i) {
- /* ownership of packet */
- writel(readl(&lp->tx_ring[i].base) | T_OWN, &lp->tx_ring[i].base);
- if (i == 0) i=lp->txRingMask+1;
- }
- writel(readl(&lp->tx_ring[entry].base) | T_OWN, &lp->tx_ring[entry].base);
-
- lp->tx_new = (++end) & lp->txRingMask; /* update current pointers */
- } else {
- status = -1;
- }
-
- return status;
-}
-
-/*
-** Look for a particular board name in the EISA configuration space
-*/
-static int __init
-EISA_signature(char *name, s32 eisa_id)
-{
- u_int i;
- const char *signatures[] = DEPCA_SIGNATURE;
- char ManCode[DEPCA_STRLEN];
- union {
- s32 ID;
- char Id[4];
- } Eisa;
- int status = 0;
-
- *name = '\0';
- Eisa.ID = inl(eisa_id);
-
- ManCode[0]=(((Eisa.Id[0]>>2)&0x1f)+0x40);
- ManCode[1]=(((Eisa.Id[1]&0xe0)>>5)+((Eisa.Id[0]&0x03)<<3)+0x40);
- ManCode[2]=(((Eisa.Id[2]>>4)&0x0f)+0x30);
- ManCode[3]=(( Eisa.Id[2]&0x0f)+0x30);
- ManCode[4]=(((Eisa.Id[3]>>4)&0x0f)+0x30);
- ManCode[5]='\0';
-
- for (i=0;(*signatures[i] != '\0') && (*name == '\0');i++) {
- if (strstr(ManCode, signatures[i]) != NULL) {
- strcpy(name,ManCode);
- status = 1;
- }
- }
-
- return status;
-}
-
-static void depca_dbg_open(struct net_device *dev)
-{
- struct depca_private *lp = (struct depca_private *)dev->priv;
- u_long ioaddr = dev->base_addr;
- struct depca_init *p = &lp->init_block;
- int i;
-
- if (depca_debug > 1){
- /* Do not copy the shadow init block into shared memory */
- /* Debugging should not affect normal operation! */
- /* The shadow init block will get copied across during InitRestartDepca */
- printk("%s: depca open with irq %d\n",dev->name,dev->irq);
- printk("Descriptor head addresses (CPU):\n");
- printk(" 0x%lx 0x%lx\n",(u_long)lp->rx_ring, (u_long)lp->tx_ring);
- printk("Descriptor addresses (CPU):\nRX: ");
- for (i=0;i<lp->rxRingMask;i++){
- if (i < 3) {
- printk("0x%8.8lx ", (long) &lp->rx_ring[i].base);
- }
- }
- printk("...0x%8.8lx\n", (long) &lp->rx_ring[i].base);
- printk("TX: ");
- for (i=0;i<lp->txRingMask;i++){
- if (i < 3) {
- printk("0x%8.8lx ", (long) &lp->tx_ring[i].base);
- }
- }
- printk("...0x%8.8lx\n", (long) &lp->tx_ring[i].base);
- printk("\nDescriptor buffers (Device):\nRX: ");
- for (i=0;i<lp->rxRingMask;i++){
- if (i < 3) {
- printk("0x%8.8x ", readl(&lp->rx_ring[i].base));
- }
- }
- printk("...0x%8.8x\n", readl(&lp->rx_ring[i].base));
- printk("TX: ");
- for (i=0;i<lp->txRingMask;i++){
- if (i < 3) {
- printk("0x%8.8x ", readl(&lp->tx_ring[i].base));
- }
- }
- printk("...0x%8.8x\n", readl(&lp->tx_ring[i].base));
- printk("Initialisation block at 0x%8.8lx(Phys)\n",virt_to_phys(lp->sh_mem));
- printk(" mode: 0x%4.4x\n",p->mode);
- printk(" physical address: ");
- for (i=0;i<ETH_ALEN-1;i++){
- printk("%2.2x:", p->phys_addr[i]);
- }
- printk("%2.2x\n", p->phys_addr[i]);
- printk(" multicast hash table: ");
- for (i=0;i<(HASH_TABLE_LEN >> 3)-1;i++){
- printk("%2.2x:", p->mcast_table[i]);
- }
- printk("%2.2x\n", p->mcast_table[i]);
- printk(" rx_ring at: 0x%8.8x\n", p->rx_ring);
- printk(" tx_ring at: 0x%8.8x\n", p->tx_ring);
- printk("buffers (Phys): 0x%8.8lx\n",virt_to_phys(lp->sh_mem)+lp->buffs_offset);
- printk("Ring size:\nRX: %d Log2(rxRingMask): 0x%8.8x\n",
- (int)lp->rxRingMask + 1,
- lp->rx_rlen);
- printk("TX: %d Log2(txRingMask): 0x%8.8x\n",
- (int)lp->txRingMask + 1,
- lp->tx_rlen);
- outw(CSR2,DEPCA_ADDR);
- printk("CSR2&1: 0x%4.4x",inw(DEPCA_DATA));
- outw(CSR1,DEPCA_ADDR);
- printk("%4.4x\n",inw(DEPCA_DATA));
- outw(CSR3,DEPCA_ADDR);
- printk("CSR3: 0x%4.4x\n",inw(DEPCA_DATA));
- }
-
- return;
-}
-
-/*
-** Perform IOCTL call functions here. Some are privileged operations and the
-** effective uid is checked in those cases.
-** All multicast IOCTLs will not work here and are for testing purposes only.
-*/
-static int depca_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
-{
- struct depca_private *lp = (struct depca_private *)dev->priv;
- struct depca_ioctl *ioc = (struct depca_ioctl *) &rq->ifr_data;
- int i, status = 0;
- u_long ioaddr = dev->base_addr;
- union {
- u8 addr[(HASH_TABLE_LEN * ETH_ALEN)];
- u16 sval[(HASH_TABLE_LEN * ETH_ALEN) >> 1];
- u32 lval[(HASH_TABLE_LEN * ETH_ALEN) >> 2];
- } tmp;
-
- switch(ioc->cmd) {
- case DEPCA_GET_HWADDR: /* Get the hardware address */
- for (i=0; i<ETH_ALEN; i++) {
- tmp.addr[i] = dev->dev_addr[i];
- }
- ioc->len = ETH_ALEN;
- if (copy_to_user(ioc->data, tmp.addr, ioc->len))
- return -EFAULT;
- break;
-
- case DEPCA_SET_HWADDR: /* Set the hardware address */
- if (!capable(CAP_NET_ADMIN)) return -EPERM;
- if (copy_from_user(tmp.addr, ioc->data, ETH_ALEN))
- return -EFAULT;
- for (i=0; i<ETH_ALEN; i++) {
- dev->dev_addr[i] = tmp.addr[i];
- }
- netif_stop_queue(dev);
- while(lp->tx_old != lp->tx_new); /* Wait for the ring to empty */
-
- STOP_DEPCA; /* Temporarily stop the depca. */
- depca_init_ring(dev); /* Initialize the descriptor rings */
- LoadCSRs(dev); /* Reload CSR3 */
- InitRestartDepca(dev); /* Resume normal operation. */
- netif_start_queue(dev); /* Unlock the TX ring */
- break;
-
- case DEPCA_SET_PROM: /* Set Promiscuous Mode */
- if (!capable(CAP_NET_ADMIN)) return -EPERM;
- netif_stop_queue(dev);
- while(lp->tx_old != lp->tx_new); /* Wait for the ring to empty */
-
- STOP_DEPCA; /* Temporarily stop the depca. */
- depca_init_ring(dev); /* Initialize the descriptor rings */
- lp->init_block.mode |= PROM; /* Set promiscuous mode */
-
- LoadCSRs(dev); /* Reload CSR3 */
- InitRestartDepca(dev); /* Resume normal operation. */
- netif_start_queue(dev); /* Unlock the TX ring */
- break;
-
- case DEPCA_CLR_PROM: /* Clear Promiscuous Mode */
- if (!capable(CAP_NET_ADMIN)) return -EPERM;
- netif_stop_queue(dev);
- while(lp->tx_old != lp->tx_new); /* Wait for the ring to empty */
-
- STOP_DEPCA; /* Temporarily stop the depca. */
- depca_init_ring(dev); /* Initialize the descriptor rings */
- lp->init_block.mode &= ~PROM; /* Clear promiscuous mode */
-
- LoadCSRs(dev); /* Reload CSR3 */
- InitRestartDepca(dev); /* Resume normal operation. */
- netif_start_queue(dev); /* Unlock the TX ring */
- break;
-
- case DEPCA_SAY_BOO: /* Say "Boo!" to the kernel log file */
- printk("%s: Boo!\n", dev->name);
- break;
-
- case DEPCA_GET_MCA: /* Get the multicast address table */
- ioc->len = (HASH_TABLE_LEN >> 3);
- if (copy_to_user(ioc->data, lp->init_block.mcast_table, ioc->len))
- return -EFAULT;
- break;
-
- case DEPCA_SET_MCA: /* Set a multicast address */
- if (!capable(CAP_NET_ADMIN)) return -EPERM;
- if (copy_from_user(tmp.addr, ioc->data, ETH_ALEN * ioc->len))
- return -EFAULT;
- set_multicast_list(dev);
- break;
-
- case DEPCA_CLR_MCA: /* Clear all multicast addresses */
- if (!capable(CAP_NET_ADMIN)) return -EPERM;
- set_multicast_list(dev);
- break;
-
- case DEPCA_MCA_EN: /* Enable pass all multicast addressing */
- if (!capable(CAP_NET_ADMIN)) return -EPERM;
- set_multicast_list(dev);
- break;
-
- case DEPCA_GET_STATS: /* Get the driver statistics */
- cli();
- ioc->len = sizeof(lp->pktStats);
- if (copy_to_user(ioc->data, &lp->pktStats, ioc->len))
- status = -EFAULT;
- sti();
- break;
-
- case DEPCA_CLR_STATS: /* Zero out the driver statistics */
- if (!capable(CAP_NET_ADMIN)) return -EPERM;
- cli();
- memset(&lp->pktStats, 0, sizeof(lp->pktStats));
- sti();
- break;
-
- case DEPCA_GET_REG: /* Get the DEPCA Registers */
- i=0;
- tmp.sval[i++] = inw(DEPCA_NICSR);
- outw(CSR0, DEPCA_ADDR); /* status register */
- tmp.sval[i++] = inw(DEPCA_DATA);
- memcpy(&tmp.sval[i], &lp->init_block, sizeof(struct depca_init));
- ioc->len = i+sizeof(struct depca_init);
- if (copy_to_user(ioc->data, tmp.addr, ioc->len))
- return -EFAULT;
- break;
-
- default:
- return -EOPNOTSUPP;
- }
-
- return status;
-}
-
-#ifdef MODULE
-static struct net_device thisDepca;
-static int irq=7; /* EDIT THESE LINE FOR YOUR CONFIGURATION */
-static int io=0x200; /* Or use the irq= io= options to insmod */
-MODULE_PARM(irq, "i");
-MODULE_PARM(io, "i");
-MODULE_PARM_DESC(irq, "DEPCA IRQ number");
-MODULE_PARM_DESC(io, "DEPCA I/O base address");
-
-/* See depca_probe() for autoprobe messages when a module */
-int
-init_module(void)
-{
- thisDepca.irq=irq;
- thisDepca.base_addr=io;
- thisDepca.init = depca_probe;
-
- if (register_netdev(&thisDepca) != 0)
- return -EIO;
-
- return 0;
-}
-
-void
-cleanup_module(void)
-{
- struct depca_private *lp = thisDepca.priv;
- if (lp) {
- iounmap(lp->sh_mem);
-#ifdef CONFIG_MCA
- if(lp->mca_slot != -1)
- mca_mark_as_unused(lp->mca_slot);
-#endif
- kfree(lp);
- thisDepca.priv = NULL;
- }
- thisDepca.irq=0;
-
- unregister_netdev(&thisDepca);
- release_region(thisDepca.base_addr, DEPCA_TOTAL_SIZE);
-}
-#endif /* MODULE */
-
-\f
-/*
- * Local variables:
- * compile-command: "gcc -D__KERNEL__ -I/linux/include -Wall -Wstrict-prototypes -fomit-frame-pointer -fno-strength-reduce -malign-loops=2 -malign-jumps=2 -malign-functions=2 -O2 -m486 -c depca.c"
- *
- * compile-command: "gcc -D__KERNEL__ -DMODULE -I/linux/include -Wall -Wstrict-prototypes -fomit-frame-pointer -fno-strength-reduce -malign-loops=2 -malign-jumps=2 -malign-functions=2 -O2 -m486 -c depca.c"
- * End:
- */
/* enter specified state */
pci_write_config_word(dev, pm + PCI_PM_CTRL, pmcsr);
+ /* Mandatory power management transition delays */
+ /* see PCI PM 1.1 5.6.1 table 18 */
+ if(state == 3 || dev->current_state == 3)
+ {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(HZ/100);
+ }
+ else if(state == 2 || dev->current_state == 2)
+ udelay(200);
dev->current_state = state;
return 0;
1607 Lava Semiconductor Manufacturing Inc
1608 Automated Wagering International
1609 Scimetric Instruments Inc
+1619 FarSite Communications Ltd
+ 0400 FarSync T2P (2 port X.21/V.35/V.24)
+ 0440 FarSync T4P (4 port X.21/V.35/V.24)
1668 Action Tec Electronics Inc
1813 Ambient Technologies Inc
1a08 Sierra semiconductor
retry_erase((erase_busy_t *)arg, MTD_REQ_TIMEOUT);
}
-static void setup_erase_request(client_handle_t handle, eraseq_entry_t *erase)
+static int setup_erase_request(client_handle_t handle, eraseq_entry_t *erase)
{
erase_busy_t *busy;
region_info_t *info;
else {
erase->State = 1;
busy = kmalloc(sizeof(erase_busy_t), GFP_KERNEL);
+ if (!busy)
+ return CS_GENERAL_FAILURE;
busy->erase = erase;
busy->client = handle;
init_timer(&busy->timeout);
retry_erase(busy, 0);
}
}
+ return CS_SUCCESS;
} /* setup_erase_request */
/*======================================================================
======================================================================*/
-static void setup_regions(client_handle_t handle, int attr,
+static int setup_regions(client_handle_t handle, int attr,
memory_handle_t *list)
{
int i, code, has_jedec, has_geo;
code = (attr) ? CISTPL_DEVICE_A : CISTPL_DEVICE;
if (read_tuple(handle, code, &device) != CS_SUCCESS)
- return;
+ return CS_GENERAL_FAILURE;
code = (attr) ? CISTPL_JEDEC_A : CISTPL_JEDEC_C;
has_jedec = (read_tuple(handle, code, &jedec) == CS_SUCCESS);
if (has_jedec && (device.ndev != jedec.nid)) {
if ((device.dev[i].type != CISTPL_DTYPE_NULL) &&
(device.dev[i].size != 0)) {
r = kmalloc(sizeof(*r), GFP_KERNEL);
+ if (!r)
+ return CS_GENERAL_FAILURE;
r->region_magic = REGION_MAGIC;
r->state = 0;
r->dev_info[0] = '\0';
}
offset += device.dev[i].size;
}
+ return CS_SUCCESS;
} /* setup_regions */
/*======================================================================
if ((handle->Attributes & INFO_MASTER_CLIENT) &&
(!(s->state & SOCKET_REGION_INFO))) {
- setup_regions(handle, 0, &s->c_region);
- setup_regions(handle, 1, &s->a_region);
+ if (setup_regions(handle, 0, &s->c_region) != CS_SUCCESS)
+ return CS_GENERAL_FAILURE;
+ if (setup_regions(handle, 1, &s->a_region) != CS_SUCCESS)
+ return CS_GENERAL_FAILURE;
s->state |= SOCKET_REGION_INFO;
}
#include <linux/types.h>
#include <linux/ioport.h>
#include <linux/delay.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/proc_fs.h>
#include <linux/init.h>
* derived from this software without specific prior written permission.
*
* Alternatively, this software may be distributed under the terms of the
- * GNU Public License ("GPL").
+ * GNU General Public License ("GPL").
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* derived from this software without specific prior written permission.
*
* Alternatively, this software may be distributed under the terms of the
- * GNU Public License ("GPL").
+ * GNU General Public License ("GPL").
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* derived from this software without specific prior written permission.
*
* Alternatively, this software may be distributed under the terms of the
- * GNU Public License ("GPL").
+ * GNU General Public License ("GPL").
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* derived from this software without specific prior written permission.
*
* Alternatively, this software may be distributed under the terms of the
- * GNU Public License ("GPL").
+ * GNU General Public License ("GPL").
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* derived from this software without specific prior written permission.
*
* Alternatively, this software may be distributed under the terms of the
- * GNU Public License ("GPL").
+ * GNU General Public License ("GPL").
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* derived from this software without specific prior written permission.
*
* Alternatively, this software may be distributed under the terms of the
- * GNU Public License ("GPL").
+ * GNU General Public License ("GPL").
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* derived from this software without specific prior written permission.
*
* Alternatively, this software may be distributed under the terms of the
- * GNU Public License ("GPL").
+ * GNU General Public License ("GPL").
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* derived from this software without specific prior written permission.
*
* Alternatively, this software may be distributed under the terms of the
- * GNU Public License ("GPL").
+ * GNU General Public License ("GPL").
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* derived from this software without specific prior written permission.
*
* Alternatively, this software may be distributed under the terms of the
- * GNU Public License ("GPL").
+ * GNU General Public License ("GPL").
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* derived from this software without specific prior written permission.
*
* Alternatively, this software may be distributed under the terms of the
- * GNU Public License ("GPL").
+ * GNU General Public License ("GPL").
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
tasklet_init(&woinst->timer.tasklet, emu10k1_waveout_bh, (unsigned long) wave_dev);
wave_dev->woinst = woinst;
emu10k1_waveout_setformat(wave_dev, &woinst->format);
-
}
file->private_data = (void *) wave_dev;
spin_unlock_irqrestore(&woinst->lock, flags);
/* wait for the tasklet (bottom-half) to finish */
- tasklet_unlock_wait(&woinst->timer.tasklet);
+ tasklet_kill(&woinst->timer.tasklet);
kfree(wave_dev->woinst);
}
}
spin_unlock_irqrestore(&wiinst->lock, flags);
- tasklet_unlock_wait(&wiinst->timer.tasklet);
+ tasklet_kill(&wiinst->timer.tasklet);
kfree(wave_dev->wiinst);
}
u32 bytestocopy;
unsigned long flags;
+ if (!wiinst)
+ return;
+
spin_lock_irqsave(&wiinst->lock, flags);
if (!(wiinst->state & WAVE_STATE_STARTED)) {
u32 bytestocopy;
unsigned long flags;
+ if (!woinst)
+ return;
+
spin_lock_irqsave(&woinst->lock, flags);
if (!(woinst->state & WAVE_STATE_STARTED)) {
static void __devinit emu10k1_midi_cleanup(struct emu10k1_card *card)
{
- tasklet_unlock_wait(&card->mpuout->tasklet);
+ tasklet_kill(&card->mpuout->tasklet);
kfree(card->mpuout);
- tasklet_unlock_wait(&card->mpuin->tasklet);
+ tasklet_kill(&card->mpuin->tasklet);
kfree(card->mpuin);
#ifdef EMU10K1_SEQUENCER
if (get_user(val, (int *)arg))
return -EFAULT;
if(val==0) {
- ret = -EINVAL;
+ return -EINVAL;
} else {
ret = 1;
}
--- /dev/null
+// Portions of this file taken from
+// Petko Manolov - Petkan (petkan@dce.bg)
+// from his driver pegasus.c
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/usb.h>
+#include <linux/module.h>
+#include "CDCEther.h"
+
+static const char *version = __FILE__ ": v0.98.4 4 July 2001 Brad Hards and another";
+
+// We will attempt to probe anything that is in the
+// communication device class...
+// We will sort through them later.
+static struct usb_device_id CDCEther_ids[] = {
+ { USB_DEVICE_INFO(2, 0, 0) },
+ { }
+};
+
+//////////////////////////////////////////////////////////////////////////////
+// Callback routines from USB device /////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+static void read_bulk_callback( struct urb *urb )
+{
+ ether_dev_t *ether_dev = urb->context;
+ struct net_device *net;
+ int count = urb->actual_length, res;
+ struct sk_buff *skb;
+
+ // Sanity check
+ if ( !ether_dev || !(ether_dev->flags & CDC_ETHER_RUNNING) ) {
+ dbg("BULK IN callback but driver is not active!");
+ return;
+ }
+
+ net = ether_dev->net;
+ if ( !netif_device_present(net) ) {
+ // Somebody killed our network interface...
+ return;
+ }
+
+ if ( ether_dev->flags & CDC_ETHER_RX_BUSY ) {
+ // Are we already trying to receive a frame???
+ ether_dev->stats.rx_errors++;
+ dbg("ether_dev Rx busy");
+ return;
+ }
+
+ // We are busy, leave us alone!
+ ether_dev->flags |= CDC_ETHER_RX_BUSY;
+
+ switch ( urb->status ) {
+ case USB_ST_NOERROR:
+ break;
+ case USB_ST_NORESPONSE:
+ dbg( "no repsonse in BULK IN" );
+ ether_dev->flags &= ~CDC_ETHER_RX_BUSY;
+ break;
+ default:
+ dbg( "%s: RX status %d", net->name, urb->status );
+ goto goon;
+ }
+
+ // Check to make sure we got some data...
+ if ( !count ) {
+ // We got no data!!!
+ goto goon;
+ }
+
+ // Tell the kernel we want some memory
+ if ( !(skb = dev_alloc_skb(count)) ) {
+ // We got no receive buffer.
+ goto goon;
+ }
+
+ // Here's where it came from
+ skb->dev = net;
+
+ // Now we copy it over
+ eth_copy_and_sum(skb, ether_dev->rx_buff, count, 0);
+
+ // Not sure
+ skb_put(skb, count);
+ // Not sure here either
+ skb->protocol = eth_type_trans(skb, net);
+
+ // Ship it off to the kernel
+ netif_rx(skb);
+
+ // update out statistics
+ ether_dev->stats.rx_packets++;
+ ether_dev->stats.rx_bytes += count;
+
+goon:
+ // Prep the USB to wait for another frame
+ FILL_BULK_URB( ðer_dev->rx_urb, ether_dev->usb,
+ usb_rcvbulkpipe(ether_dev->usb, ether_dev->data_ep_in),
+ ether_dev->rx_buff, ether_dev->wMaxSegmentSize,
+ read_bulk_callback, ether_dev );
+
+ // Give this to the USB subsystem so it can tell us
+ // when more data arrives.
+ if ( (res = usb_submit_urb(ðer_dev->rx_urb)) ) {
+ warn( __FUNCTION__ " failed submint rx_urb %d", res);
+ }
+
+ // We are no longer busy, show us the frames!!!
+ ether_dev->flags &= ~CDC_ETHER_RX_BUSY;
+}
+
+static void write_bulk_callback( struct urb *urb )
+{
+ ether_dev_t *ether_dev = urb->context;
+
+ // Sanity check
+ if ( !ether_dev || !(ether_dev->flags & CDC_ETHER_RUNNING) ) {
+ // We are insane!!!
+ err( "write_bulk_callback: device not running" );
+ return;
+ }
+
+ // Do we still have a valid kernel network device?
+ if ( !netif_device_present(ether_dev->net) ) {
+ // Someone killed our network interface.
+ err( "write_bulk_callback: net device not present" );
+ return;
+ }
+
+ // Hmm... What on Earth could have happened???
+ if ( urb->status ) {
+ info("%s: TX status %d", ether_dev->net->name, urb->status);
+ }
+
+ // Update the network interface and tell it we are
+ // ready for another frame
+ ether_dev->net->trans_start = jiffies;
+ netif_wake_queue( ether_dev->net );
+}
+
+//static void intr_callback( struct urb *urb )
+//{
+// ether_dev_t *ether_dev = urb->context;
+// struct net_device *net;
+// __u8 *d;
+//
+// if ( !ether_dev )
+// return;
+//
+// switch ( urb->status ) {
+// case USB_ST_NOERROR:
+// break;
+// case USB_ST_URB_KILLED:
+// return;
+// default:
+// info("intr status %d", urb->status);
+// }
+//
+// d = urb->transfer_buffer;
+// net = ether_dev->net;
+// if ( d[0] & 0xfc ) {
+// ether_dev->stats.tx_errors++;
+// if ( d[0] & TX_UNDERRUN )
+// ether_dev->stats.tx_fifo_errors++;
+// if ( d[0] & (EXCESSIVE_COL | JABBER_TIMEOUT) )
+// ether_dev->stats.tx_aborted_errors++;
+// if ( d[0] & LATE_COL )
+// ether_dev->stats.tx_window_errors++;
+// if ( d[0] & (NO_CARRIER | LOSS_CARRIER) )
+// ether_dev->stats.tx_carrier_errors++;
+// }
+//}
+
+//////////////////////////////////////////////////////////////////////////////
+// Routines for turning net traffic on and off on the USB side ///////////////
+//////////////////////////////////////////////////////////////////////////////
+
+static inline int enable_net_traffic( ether_dev_t *ether_dev )
+{
+ struct usb_device *usb = ether_dev->usb;
+
+ // Here would be the time to set the data interface to the configuration where
+ // it has two endpoints that use a protocol we can understand.
+
+ if (usb_set_interface( usb,
+ ether_dev->data_bInterfaceNumber,
+ ether_dev->data_bAlternateSetting_with_traffic ) ) {
+ err("usb_set_interface() failed" );
+ err("Attempted to set interface %d", ether_dev->data_bInterfaceNumber);
+ err("To alternate setting %d", ether_dev->data_bAlternateSetting_with_traffic);
+ return -1;
+ }
+ return 0;
+}
+
+static inline void disable_net_traffic( ether_dev_t *ether_dev )
+{
+ // The thing to do is to set the data interface to the alternate setting that has
+ // no endpoints. This is what the spec suggests.
+
+ if (ether_dev->data_interface_altset_num_without_traffic >= 0 ) {
+ if (usb_set_interface( ether_dev->usb,
+ ether_dev->data_bInterfaceNumber,
+ ether_dev->data_bAlternateSetting_without_traffic ) ) {
+ err("usb_set_interface() failed");
+ }
+ } else {
+ // Some devices just may not support this...
+ warn("No way to disable net traffic");
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Callback routines for kernel Ethernet Device //////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+static void CDCEther_tx_timeout( struct net_device *net )
+{
+ ether_dev_t *ether_dev = net->priv;
+
+ // Sanity check
+ if ( !ether_dev ) {
+ // Seems to be a case of insanity here
+ return;
+ }
+
+ // Tell syslog we are hosed.
+ warn("%s: Tx timed out.", net->name);
+
+ // Tear the waiting frame off the list
+ ether_dev->tx_urb.transfer_flags |= USB_ASYNC_UNLINK;
+ usb_unlink_urb( ðer_dev->tx_urb );
+
+ // Update statistics
+ ether_dev->stats.tx_errors++;
+}
+
+static int CDCEther_start_xmit( struct sk_buff *skb, struct net_device *net )
+{
+ ether_dev_t *ether_dev = net->priv;
+ int count;
+ int res;
+
+ // If we are told to transmit an ethernet frame that fits EXACTLY
+ // into an integer number of USB packets, we force it to send one
+ // more byte so the device will get a runt USB packet signalling the
+ // end of the ethernet frame
+ if ( (skb->len) ^ (ether_dev->data_ep_out_size) ) {
+ // It was not an exact multiple
+ // no need to add anything extra
+ count = skb->len;
+ } else {
+ // Add one to make it NOT an exact multiple
+ count = skb->len + 1;
+ }
+
+ // Tell the kernel, "No more frames 'til we are done
+ // with this one.'
+ netif_stop_queue( net );
+
+ // Copy it from kernel memory to OUR memory
+ memcpy(ether_dev->tx_buff, skb->data, skb->len);
+
+ // Fill in the URB for shipping it out.
+ FILL_BULK_URB( ðer_dev->tx_urb, ether_dev->usb,
+ usb_sndbulkpipe(ether_dev->usb, ether_dev->data_ep_out),
+ ether_dev->tx_buff, ether_dev->wMaxSegmentSize,
+ write_bulk_callback, ether_dev );
+
+ // Tell the URB how much it will be transporting today
+ ether_dev->tx_urb.transfer_buffer_length = count;
+
+ // Send the URB on its merry way.
+ if ((res = usb_submit_urb(ðer_dev->tx_urb))) {
+ // Hmm... It didn't go. Tell someone...
+ warn("failed tx_urb %d", res);
+ // update some stats...
+ ether_dev->stats.tx_errors++;
+ // and tell the kernel to give us another.
+ // Maybe we'll get it right next time.
+ netif_start_queue( net );
+ } else {
+ // Okay, it went out.
+ // Update statistics
+ ether_dev->stats.tx_packets++;
+ ether_dev->stats.tx_bytes += skb->len;
+ // And tell the kernel when the last transmit occurred.
+ net->trans_start = jiffies;
+ }
+
+ // We are done with the kernel's memory
+ dev_kfree_skb(skb);
+
+ // We are done here.
+ return 0;
+}
+
+static struct net_device_stats *CDCEther_netdev_stats( struct net_device *net )
+{
+ // Easy enough!
+ return &((ether_dev_t *)net->priv)->stats;
+}
+
+static int CDCEther_open(struct net_device *net)
+{
+ ether_dev_t *ether_dev = (ether_dev_t *)net->priv;
+ int res;
+
+ // We are finally getting used!
+ MOD_INC_USE_COUNT;
+
+ // Turn on the USB and let the packets flow!!!
+ if ( (res = enable_net_traffic( ether_dev )) ) {
+ err( __FUNCTION__ "can't enable_net_traffic() - %d", res );
+ MOD_DEC_USE_COUNT;
+ return -EIO;
+ }
+
+ // Prep a receive URB
+ FILL_BULK_URB( ðer_dev->rx_urb, ether_dev->usb,
+ usb_rcvbulkpipe(ether_dev->usb, ether_dev->data_ep_in),
+ ether_dev->rx_buff, ether_dev->wMaxSegmentSize,
+ read_bulk_callback, ether_dev );
+
+ // Put it out there so the device can send us stuff
+ if ( (res = usb_submit_urb(ðer_dev->rx_urb)) )
+ {
+ // Hmm... Okay...
+ warn( __FUNCTION__ " failed rx_urb %d", res );
+ }
+
+ // Tell the kernel we are ready to start receiving from it
+ netif_start_queue( net );
+
+ // We are up and running.
+ ether_dev->flags |= CDC_ETHER_RUNNING;
+
+ // Let's get ready to move frames!!!
+ return 0;
+}
+
+static int CDCEther_close( struct net_device *net )
+{
+ ether_dev_t *ether_dev = net->priv;
+
+ // We are no longer running.
+ ether_dev->flags &= ~CDC_ETHER_RUNNING;
+
+ // Tell the kernel to stop sending us stuff
+ netif_stop_queue( net );
+
+ // If we are not already unplugged, turn off USB
+ // traffic
+ if ( !(ether_dev->flags & CDC_ETHER_UNPLUG) ) {
+ disable_net_traffic( ether_dev );
+ }
+
+ // We don't need the URBs anymore.
+ usb_unlink_urb( ðer_dev->rx_urb );
+ usb_unlink_urb( ðer_dev->tx_urb );
+ usb_unlink_urb( ðer_dev->intr_urb );
+
+ // We are not being used now.
+ MOD_DEC_USE_COUNT;
+
+ // That's it. I'm done.
+ return 0;
+}
+
+static int CDCEther_ioctl( struct net_device *net, struct ifreq *rq, int cmd )
+{
+ //__u16 *data = (__u16 *)&rq->ifr_data;
+ //ether_dev_t *ether_dev = net->priv;
+
+ // No support here yet.
+ // Do we need support???
+ switch(cmd) {
+ case SIOCDEVPRIVATE:
+ return -EOPNOTSUPP;
+ case SIOCDEVPRIVATE+1:
+ return -EOPNOTSUPP;
+ case SIOCDEVPRIVATE+2:
+ //return 0;
+ return -EOPNOTSUPP;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static void CDCEther_set_multicast( struct net_device *net )
+{
+ ether_dev_t *ether_dev = net->priv;
+
+ // Tell the kernel to stop sending us frames while we get this
+ // all set up.
+ netif_stop_queue(net);
+
+ // Do what we are told.
+ if (net->flags & IFF_PROMISC) {
+ // TODO - Turn on promiscuous mode
+ info( "%s: Promiscuous mode enabled", net->name);
+ } else if (net->flags & IFF_ALLMULTI){
+ // TODO - Here we need to tell the device to block ALL multicast traffic.
+ info("%s: set allmulti", net->name);
+ } else if (net->mc_count > ether_dev->wNumberMCFilters) {
+ // TODO - Here we need to set multicast filters, but
+ // There are more than our limit... Hmm...
+ info("%s: set too many MC filters", net->name);
+ } else {
+ // TODO - Here we are supposed to set SOME of the multicast filters.
+ // I must learn how to do this...
+ //info("%s: set Rx mode", net->name);
+ }
+
+ // Tell the kernel to start giving frames to us again.
+ netif_wake_queue(net);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Routines used to parse out the Functional Descriptors /////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+static int parse_header_functional_descriptor( int *bFunctionLength,
+ int bDescriptorType,
+ int bDescriptorSubtype,
+ unsigned char *data,
+ ether_dev_t *ether_dev,
+ int *requirements )
+{
+ // Check to make sure we haven't seen one of these already.
+ if ( (~*requirements) & REQ_HDR_FUNC_DESCR ) {
+ err( "Multiple Header Functional Descriptors found." );
+ return -1;
+ }
+
+ // Is it the right size???
+ if (*bFunctionLength != 5) {
+ info( "Invalid length in Header Functional Descriptor" );
+ // This is a hack to get around a particular device (NO NAMES)
+ // It has this function length set to the length of the
+ // whole class-specific descriptor
+ *bFunctionLength = 5;
+ }
+
+ // Nothing extremely useful here.
+ // We'll keep it for posterity
+ ether_dev->bcdCDC = data[0] + (data[1] << 8);
+ dbg( "Found Header descriptor, CDC version %x", ether_dev->bcdCDC);
+
+ // We've seen one of these
+ *requirements &= ~REQ_HDR_FUNC_DESCR;
+
+ // It's all good.
+ return 0;
+}
+
+static int parse_union_functional_descriptor( int *bFunctionLength,
+ int bDescriptorType,
+ int bDescriptorSubtype,
+ unsigned char *data,
+ ether_dev_t *ether_dev,
+ int *requirements )
+{
+ // Check to make sure we haven't seen one of these already.
+ if ( (~*requirements) & REQ_UNION_FUNC_DESCR ) {
+ err( "Multiple Union Functional Descriptors found." );
+ return -1;
+ }
+
+ // Is it the right size?
+ if (*bFunctionLength != 5) {
+ // It is NOT the size we expected.
+ err( "Unsupported length in Union Functional Descriptor" );
+ return -1;
+ }
+
+ // Sanity check of sorts
+ if (ether_dev->comm_interface != data[0]) {
+ // This tells us that we are chasing the wrong comm
+ // interface or we are crazy or something else weird.
+ if (ether_dev->comm_interface == data[1]) {
+ info( "Probably broken Union descriptor, fudging data interface" );
+ // We'll need this in a few microseconds,
+ // so guess here, and hope for the best
+ ether_dev->data_interface = data[0];
+ } else {
+ err( "Union Functional Descriptor is broken beyond repair" );
+ return -1;
+ }
+ } else{ // Descriptor is OK
+ // We'll need this in a few microseconds!
+ ether_dev->data_interface = data[1];
+ }
+
+ // We've seen one of these now.
+ *requirements &= ~REQ_UNION_FUNC_DESCR;
+
+ // Done
+ return 0;
+}
+
+static int parse_ethernet_functional_descriptor( int *bFunctionLength,
+ int bDescriptorType,
+ int bDescriptorSubtype,
+ unsigned char *data,
+ ether_dev_t *ether_dev,
+ int *requirements )
+{
+ // Check to make sure we haven't seen one of these already.
+ if ( (~*requirements) & REQ_ETH_FUNC_DESCR ) {
+ err( "Multiple Ethernet Functional Descriptors found." );
+ return -1;
+ }
+
+ // Is it the right size?
+ if (*bFunctionLength != 13) {
+ err( "Invalid length in Ethernet Networking Functional Descriptor" );
+ return -1;
+ }
+
+ // Lots of goodies from this one. They are all important.
+ ether_dev->iMACAddress = data[0];
+ ether_dev->bmEthernetStatistics = data[1] + (data[2] << 8) + (data[3] << 16) + (data[4] << 24);
+ ether_dev->wMaxSegmentSize = data[5] + (data[6] << 8);
+ ether_dev->wNumberMCFilters = (data[7] + (data[8] << 8)) & 0x00007FFF;
+ ether_dev->bNumberPowerFilters = data[9];
+
+ // We've seen one of these now.
+ *requirements &= ~REQ_ETH_FUNC_DESCR;
+
+ // That's all she wrote.
+ return 0;
+}
+
+static int parse_protocol_unit_functional_descriptor( int *bFunctionLength,
+ int bDescriptorType,
+ int bDescriptorSubtype,
+ unsigned char *data,
+ ether_dev_t *ether_dev,
+ int *requirements )
+{
+ // There should only be one type if we are sane
+ if (bDescriptorType != CS_INTERFACE) {
+ info( "Invalid bDescriptorType found." );
+ return -1;
+ }
+
+ // The Subtype tells the tale.
+ switch (bDescriptorSubtype){
+ case 0x00: // Header Functional Descriptor
+ return parse_header_functional_descriptor( bFunctionLength,
+ bDescriptorType,
+ bDescriptorSubtype,
+ data,
+ ether_dev,
+ requirements );
+ break;
+ case 0x06: // Union Functional Descriptor
+ return parse_union_functional_descriptor( bFunctionLength,
+ bDescriptorType,
+ bDescriptorSubtype,
+ data,
+ ether_dev,
+ requirements );
+ break;
+ case 0x0F: // Ethernet Networking Functional Descriptor
+ return parse_ethernet_functional_descriptor( bFunctionLength,
+ bDescriptorType,
+ bDescriptorSubtype,
+ data,
+ ether_dev,
+ requirements );
+ break;
+ default: // We don't support this at this time...
+ // However that doesn't necessarily indicate an error.
+ dbg( "Unexpected header type %x:", bDescriptorSubtype );
+ return 0;
+ }
+ // How did we get here???
+ return -1;
+}
+
+static int parse_ethernet_class_information( unsigned char *data, int length, ether_dev_t *ether_dev )
+{
+ int loc = 0;
+ int rc;
+ int bFunctionLength;
+ int bDescriptorType;
+ int bDescriptorSubtype;
+ int requirements = REQUIREMENTS_TOTAL;
+
+ // As long as there is something here, we will try to parse it
+ while (loc < length) {
+ // Length
+ bFunctionLength = data[loc];
+ loc++;
+
+ // Type
+ bDescriptorType = data[loc];
+ loc++;
+
+ // Subtype
+ bDescriptorSubtype = data[loc];
+ loc++;
+
+ // ship this off to be processed elsewhere.
+ rc = parse_protocol_unit_functional_descriptor( &bFunctionLength,
+ bDescriptorType,
+ bDescriptorSubtype,
+ &data[loc],
+ ether_dev,
+ &requirements );
+ // Did it process okay?
+ if (rc) {
+ // Something was hosed somewhere.
+ // No need to continue;
+ err("Bad descriptor parsing: %x", rc );
+ return -1;
+ }
+ // We have already taken three bytes.
+ loc += (bFunctionLength - 3);
+ }
+ // Check to see if we got everything we need.
+ if (requirements) {
+ // We missed some of the requirements...
+ err( "Not all required functional descriptors present 0x%08X", requirements );
+ return -1;
+ }
+ // We got everything.
+ return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Routine to check for the existence of the Functional Descriptors //////////
+//////////////////////////////////////////////////////////////////////////////
+
+static int find_and_parse_ethernet_class_information( struct usb_device *device, ether_dev_t *ether_dev )
+{
+ struct usb_config_descriptor *conf = NULL;
+ struct usb_interface *comm_intf_group = NULL;
+ struct usb_interface_descriptor *comm_intf = NULL;
+ int rc = -1;
+ // The assumption here is that find_ethernet_comm_interface
+ // and find_valid_configuration
+ // have already filled in the information about where to find
+ // the a valid commication interface.
+
+ conf = &( device->config[ether_dev->configuration_num] );
+ comm_intf_group = &( conf->interface[ether_dev->comm_interface] );
+ comm_intf = &( comm_intf_group->altsetting[ether_dev->comm_interface_altset_num] );
+ // Let's check and see if it has the extra information we need...
+
+ if (comm_intf->extralen > 0) {
+ // This is where the information is SUPPOSED to be.
+ rc = parse_ethernet_class_information( comm_intf->extra, comm_intf->extralen, ether_dev );
+ } else if (conf->extralen > 0) {
+ // This is a hack. The spec says it should be at the interface
+ // location checked above. However I have seen it here also.
+ // This is the same device that requires the functional descriptor hack above
+ warn( "Ethernet information found at device configuration. This is broken." );
+ rc = parse_ethernet_class_information( conf->extra, conf->extralen, ether_dev );
+ } else {
+ // I don't know where else to look.
+ warn( "No ethernet information found." );
+ rc = -1;
+ }
+ return rc;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Routines to verify the data interface /////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+static int get_data_interface_endpoints( struct usb_device *device, ether_dev_t *ether_dev )
+{
+ struct usb_config_descriptor *conf = NULL;
+ struct usb_interface *data_intf_group = NULL;
+ struct usb_interface_descriptor *data_intf = NULL;
+
+ // Walk through and get to the data interface we are checking.
+ conf = &( device->config[ether_dev->configuration_num] );
+ data_intf_group = &( conf->interface[ether_dev->data_interface] );
+ data_intf = &( data_intf_group->altsetting[ether_dev->data_interface_altset_num_with_traffic] );
+
+ // Start out assuming we won't find anything we can use
+ ether_dev->data_ep_in = 0;
+ ether_dev->data_ep_out = 0;
+
+ // If these are not BULK endpoints, we don't want them
+ if ( data_intf->endpoint[0].bmAttributes != 0x02 ) {
+ return -1;
+ } if ( data_intf->endpoint[1].bmAttributes != 0x02 ) {
+ return -1;
+ }
+
+ // Check the first endpoint to see if it is IN or OUT
+ if ( data_intf->endpoint[0].bEndpointAddress & 0x80 ) {
+ // This endpoint is IN
+ ether_dev->data_ep_in = data_intf->endpoint[0].bEndpointAddress & 0x7F;
+ } else {
+ // This endpoint is OUT
+ ether_dev->data_ep_out = data_intf->endpoint[0].bEndpointAddress & 0x7F;
+ ether_dev->data_ep_out_size = data_intf->endpoint[0].wMaxPacketSize;
+ }
+
+ // Check the second endpoint to see if it is IN or OUT
+ if ( data_intf->endpoint[1].bEndpointAddress & 0x80 ) {
+ // This endpoint is IN
+ ether_dev->data_ep_in = data_intf->endpoint[1].bEndpointAddress & 0x7F;
+ } else {
+ // This endpoint is OUT
+ ether_dev->data_ep_out = data_intf->endpoint[1].bEndpointAddress & 0x7F;
+ ether_dev->data_ep_out_size = data_intf->endpoint[1].wMaxPacketSize;
+ }
+
+ // Now make sure we got both an IN and an OUT
+ if (ether_dev->data_ep_in && ether_dev->data_ep_out) {
+ // We did get both, we are in good shape...
+ info( "detected BULK OUT packets of size %d", ether_dev->data_ep_out_size );
+ return 0;
+ }
+ return -1;
+}
+
+static int verify_ethernet_data_interface( struct usb_device *device, ether_dev_t *ether_dev )
+{
+ struct usb_config_descriptor *conf = NULL;
+ struct usb_interface *data_intf_group = NULL;
+ struct usb_interface_descriptor *data_intf = NULL;
+ int rc = -1;
+ int status;
+ int altset_num;
+
+ // The assumption here is that parse_ethernet_class_information()
+ // and find_valid_configuration()
+ // have already filled in the information about where to find
+ // a data interface
+ conf = &( device->config[ether_dev->configuration_num] );
+ data_intf_group = &( conf->interface[ether_dev->data_interface] );
+
+ // start out assuming we won't find what we are looking for.
+ ether_dev->data_interface_altset_num_with_traffic = -1;
+ ether_dev->data_bAlternateSetting_with_traffic = -1;
+ ether_dev->data_interface_altset_num_without_traffic = -1;
+ ether_dev->data_bAlternateSetting_without_traffic = -1;
+
+ // Walk through every possible setting for this interface until
+ // we find what makes us happy.
+ for ( altset_num = 0; altset_num < data_intf_group->num_altsetting; altset_num++ ) {
+ data_intf = &( data_intf_group->altsetting[altset_num] );
+
+ // Is this a data interface we like?
+ if ( ( data_intf->bInterfaceClass == 0x0A )
+ && ( data_intf->bInterfaceSubClass == 0x00 )
+ && ( data_intf->bInterfaceProtocol == 0x00 ) ) {
+ if ( data_intf->bNumEndpoints == 2 ) {
+ // We are required to have one of these.
+ // An interface with 2 endpoints to send Ethernet traffic back and forth
+ // It actually may be possible that the device might only
+ // communicate in a vendor specific manner.
+ // That would not be very nice.
+ // We can add that one later.
+ ether_dev->data_bInterfaceNumber = data_intf->bInterfaceNumber;
+ ether_dev->data_interface_altset_num_with_traffic = altset_num;
+ ether_dev->data_bAlternateSetting_with_traffic = data_intf->bAlternateSetting;
+ status = get_data_interface_endpoints( device, ether_dev );
+ if (!status) {
+ rc = 0;
+ }
+ }
+ if ( data_intf->bNumEndpoints == 0 ) {
+ // According to the spec we are SUPPOSED to have one of these
+ // In fact the device is supposed to come up in this state.
+ // However, I have seen a device that did not have such an interface.
+ // So it must be just optional for our driver...
+ ether_dev->data_bInterfaceNumber = data_intf->bInterfaceNumber;
+ ether_dev->data_interface_altset_num_without_traffic = altset_num;
+ ether_dev->data_bAlternateSetting_without_traffic = data_intf->bAlternateSetting;
+ }
+ }
+ }
+ return rc;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Routine to find a communication interface /////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+static int find_ethernet_comm_interface( struct usb_device *device, ether_dev_t *ether_dev )
+{
+ struct usb_config_descriptor *conf = NULL;
+ struct usb_interface *comm_intf_group = NULL;
+ struct usb_interface_descriptor *comm_intf = NULL;
+ int intf_num;
+ int altset_num;
+ int rc;
+
+ conf = &( device->config[ether_dev->configuration_num] );
+
+ // We need to check and see if any of these interfaces are something we want.
+ // Walk through each interface one at a time
+ for ( intf_num = 0; intf_num < conf->bNumInterfaces; intf_num++ ) {
+ comm_intf_group = &( conf->interface[intf_num] );
+ // Now for each of those interfaces, check every possible
+ // alternate setting.
+ for ( altset_num = 0; altset_num < comm_intf_group->num_altsetting; altset_num++ ) {
+ comm_intf = &( comm_intf_group->altsetting[altset_num] );
+
+ // Is this a communication class of interface of the
+ // ethernet subclass variety.
+ if ( ( comm_intf->bInterfaceClass == 0x02 )
+ && ( comm_intf->bInterfaceSubClass == 0x06 )
+ && ( comm_intf->bInterfaceProtocol == 0x00 ) ) {
+ if ( comm_intf->bNumEndpoints == 1 ) {
+ // Good, we found one, we will try this one
+ // Fill in the structure...
+ ether_dev->comm_interface = intf_num;
+ ether_dev->comm_bInterfaceNumber = comm_intf->bInterfaceNumber;
+ ether_dev->comm_interface_altset_num = altset_num;
+ ether_dev->comm_bAlternateSetting = comm_intf->bAlternateSetting;
+
+ // Look for the Ethernet Functional Descriptors
+ rc = find_and_parse_ethernet_class_information( device, ether_dev );
+ if (rc) {
+ // Nope this was no good after all.
+ continue;
+ }
+
+ // Check that we really can talk to the data
+ // interface
+ // This includes # of endpoints, protocols,
+ // etc.
+ rc = verify_ethernet_data_interface( device, ether_dev );
+ if (rc) {
+ // We got something we didn't like
+ continue;
+ }
+ // This communication interface seems to give us everything
+ // we require. We have all the ethernet info we need.
+ // Let's get out of here and go home right now.
+ return 0;
+ } else {
+ // bNumEndPoints != 1
+ // We found an interface that had the wrong number of
+ // endpoints but would have otherwise been okay
+ } // end bNumEndpoints check.
+ } // end interface specifics check.
+ } // end for altset_num
+ } // end for intf_num
+ return -1;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Routine to go through all configurations and find one that ////////////////
+// is an Ethernet Networking Device //////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+static int find_valid_configuration( struct usb_device *device, ether_dev_t *ether_dev )
+{
+ struct usb_config_descriptor *conf = NULL;
+ int conf_num;
+ int rc;
+
+ // We will try each and every possible configuration
+ for ( conf_num = 0; conf_num < device->descriptor.bNumConfigurations; conf_num++ ) {
+ conf = &( device->config[conf_num] );
+
+ // Our first requirement : 2 interfaces
+ if ( conf->bNumInterfaces != 2 ) {
+ // I currently don't know how to handle devices with any number of interfaces
+ // other than 2.
+ continue;
+ }
+
+ // This one passed our first check, fill in some
+ // useful data
+ ether_dev->configuration_num = conf_num;
+ ether_dev->bConfigurationValue = conf->bConfigurationValue;
+
+ // Now run it through the ringers and see what comes
+ // out the other side.
+ rc = find_ethernet_comm_interface( device, ether_dev );
+
+ // Check if we found an ethernet Communcation Device
+ if ( !rc ) {
+ // We found one.
+ return 0;
+ }
+ }
+ // None of the configurations suited us.
+ return -1;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Routine that checks a given configuration to see if any driver ////////////
+// has claimed any of the devices interfaces /////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+static int check_for_claimed_interfaces( struct usb_config_descriptor *config )
+{
+ struct usb_interface *comm_intf_group;
+ int intf_num;
+
+ // Go through all the interfaces and make sure none are
+ // claimed by anybody else.
+ for ( intf_num = 0; intf_num < config->bNumInterfaces; intf_num++ ) {
+ comm_intf_group = &( config->interface[intf_num] );
+ if ( usb_interface_claimed( comm_intf_group ) ) {
+ // Somebody has beat us to this guy.
+ // We can't change the configuration out from underneath of whoever
+ // is using this device, so we will go ahead and give up.
+ return -1;
+ }
+ }
+ // We made it all the way through.
+ // I guess no one has claimed any of these interfaces.
+ return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Routines to ask for and set the kernel network interface's MAC address ////
+// Used by driver's probe routine ////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+static inline unsigned char hex2dec( unsigned char digit )
+{
+ // Is there a standard way to do this???
+ // I have written this code TOO MANY times.
+ if ( (digit >= '0') && (digit <= '9') ) {
+ return (digit - '0');
+ }
+ if ( (digit >= 'a') && (digit <= 'f') ) {
+ return (digit - 'a' + 10);
+ }
+ if ( (digit >= 'A') && (digit <= 'F') ) {
+ return (digit - 'A' + 10);
+ }
+ return 0;
+}
+
+static void set_ethernet_addr( ether_dev_t *ether_dev )
+{
+ unsigned char mac_addr[6];
+ int i;
+ int len;
+ unsigned char buffer[13];
+
+ // Let's assume we don't get anything...
+ mac_addr[0] = 0x00;
+ mac_addr[1] = 0x00;
+ mac_addr[2] = 0x00;
+ mac_addr[3] = 0x00;
+ mac_addr[4] = 0x00;
+ mac_addr[5] = 0x00;
+
+ // Let's ask the device...
+ len = usb_string(ether_dev->usb, ether_dev->iMACAddress, buffer, 13);
+
+ // Sanity check!
+ if (len != 12) {
+ // You gotta love failing sanity checks
+ err("Attempting to get MAC address returned %d bytes", len);
+ return;
+ }
+
+ // Fill in the mac_addr
+ for (i = 0; i < 6; i++) {
+ mac_addr[i] = ( hex2dec( buffer[2 * i] ) << 4 ) + hex2dec( buffer[2 * i + 1] );
+ }
+
+ // Now copy it over to the kernel's network driver.
+ memcpy( ether_dev->net->dev_addr, mac_addr, sizeof(mac_addr) );
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Routine to print to syslog information about the driver ///////////////////
+// Used by driver's probe routine ////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+void log_device_info(ether_dev_t *ether_dev)
+{
+ int len;
+ int string_num;
+ unsigned char manu[256];
+ unsigned char prod[256];
+ unsigned char sern[256];
+ unsigned char *mac_addr;
+
+ // Default empty strings in case we don't find a real one
+ manu[0] = 0x00;
+ prod[0] = 0x00;
+ sern[0] = 0x00;
+
+ // Try to get the device Manufacturer
+ string_num = ether_dev->usb->descriptor.iManufacturer;
+ if (string_num) {
+ // Put it into its buffer
+ len = usb_string(ether_dev->usb, string_num, manu, 255);
+ // Just to be safe
+ manu[len] = 0x00;
+ }
+
+ // Try to get the device Product Name
+ string_num = ether_dev->usb->descriptor.iProduct;
+ if (string_num) {
+ // Put it into its buffer
+ len = usb_string(ether_dev->usb, string_num, prod, 255);
+ // Just to be safe
+ prod[len] = 0x00;
+ }
+
+ // Try to get the device Serial Number
+ string_num = ether_dev->usb->descriptor.iSerialNumber;
+ if (string_num) {
+ // Put it into its buffer
+ len = usb_string(ether_dev->usb, string_num, sern, 255);
+ // Just to be safe
+ sern[len] = 0x00;
+ }
+
+ // This makes it easier for us to print
+ mac_addr = ether_dev->net->dev_addr;
+
+ // Now send everything we found to the syslog
+ info( "%s: %s %s %s %02X:%02X:%02X:%02X:%02X:%02X",
+ ether_dev->net->name, manu, prod, sern, mac_addr[0],
+ mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4],
+ mac_addr[5] );
+}
+
+/* Forward declaration */
+static struct usb_driver CDCEther_driver ;
+
+//////////////////////////////////////////////////////////////////////////////
+// Module's probe routine ////////////////////////////////////////////////////
+// claims interfaces if they are for an Ethernet CDC /////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+static void * CDCEther_probe( struct usb_device *usb, unsigned int ifnum,
+ const struct usb_device_id *id)
+{
+ struct net_device *net;
+ ether_dev_t *ether_dev;
+ int rc;
+
+ // First we should check the active configuration to see if
+ // any other driver has claimed any of the interfaces.
+ if ( check_for_claimed_interfaces( usb->actconfig ) ) {
+ // Someone has already put there grubby paws on this device.
+ // We don't want it now...
+ return NULL;
+ }
+
+ // We might be finding a device we can use.
+ // We all go ahead and allocate our storage space.
+ // We need to because we have to start filling in the data that
+ // we are going to need later.
+ if(!(ether_dev = kmalloc(sizeof(ether_dev_t), GFP_KERNEL))) {
+ err("out of memory allocating device structure");
+ return NULL;
+ }
+
+ // Zero everything out.
+ memset(ether_dev, 0, sizeof(ether_dev_t));
+
+ // Let's see if we can find a configuration we can use.
+ rc = find_valid_configuration( usb, ether_dev );
+ if (rc) {
+ // Nope we couldn't find one we liked.
+ // This device was not meant for us to control.
+ kfree( ether_dev );
+ return NULL;
+ }
+
+ // Now that we FOUND a configuration. let's try to make the
+ // device go into it.
+ if ( usb_set_configuration( usb, ether_dev->bConfigurationValue ) ) {
+ err("usb_set_configuration() failed");
+ kfree( ether_dev );
+ return NULL;
+ }
+
+ // Now set the communication interface up as required.
+ if (usb_set_interface(usb, ether_dev->comm_bInterfaceNumber, ether_dev->comm_bAlternateSetting)) {
+ err("usb_set_interface() failed");
+ kfree( ether_dev );
+ return NULL;
+ }
+
+ // Only turn traffic on right now if we must...
+ if (ether_dev->data_interface_altset_num_without_traffic >= 0) {
+ // We found an alternate setting for the data
+ // interface that allows us to turn off traffic.
+ // We should use it.
+ if (usb_set_interface( usb,
+ ether_dev->data_bInterfaceNumber,
+ ether_dev->data_bAlternateSetting_without_traffic)) {
+ err("usb_set_interface() failed");
+ kfree( ether_dev );
+ return NULL;
+ }
+ } else {
+ // We didn't find an alternate setting for the data
+ // interface that would let us turn off traffic.
+ // Oh well, let's go ahead and do what we must...
+ if (usb_set_interface( usb,
+ ether_dev->data_bInterfaceNumber,
+ ether_dev->data_bAlternateSetting_with_traffic)) {
+ err("usb_set_interface() failed");
+ kfree( ether_dev );
+ return NULL;
+ }
+ }
+
+ // Now we need to get a kernel Ethernet interface.
+ net = init_etherdev( NULL, 0 );
+ if ( !net ) {
+ // Hmm... The kernel is not sharing today...
+ // Fine, we didn't want it anyway...
+ err( "Unable to initialize ethernet device" );
+ kfree( ether_dev );
+ return NULL;
+ }
+
+ // Now that we have an ethernet device, let's set it up
+ // (And I don't mean "set [it] up the bomb".)
+ net->priv = ether_dev;
+ net->open = CDCEther_open;
+ net->stop = CDCEther_close;
+ net->watchdog_timeo = CDC_ETHER_TX_TIMEOUT;
+ net->tx_timeout = CDCEther_tx_timeout; // TX timeout function
+ net->do_ioctl = CDCEther_ioctl;
+ net->hard_start_xmit = CDCEther_start_xmit;
+ net->set_multicast_list = CDCEther_set_multicast;
+ net->get_stats = CDCEther_netdev_stats;
+ net->mtu = ether_dev->wMaxSegmentSize - 14;
+
+ // We'll keep track of this information for later...
+ ether_dev->usb = usb;
+ ether_dev->net = net;
+
+ // and don't forget the MAC address.
+ set_ethernet_addr( ether_dev );
+
+ // Send a message to syslog about what we are handling
+ log_device_info( ether_dev );
+
+ // I claim this interface to be a CDC Ethernet Networking device
+ usb_driver_claim_interface( &CDCEther_driver,
+ &(usb->config[ether_dev->configuration_num].interface[ether_dev->comm_interface]),
+ ether_dev );
+ // I claim this interface to be a CDC Ethernet Networking device
+ usb_driver_claim_interface( &CDCEther_driver,
+ &(usb->config[ether_dev->configuration_num].interface[ether_dev->data_interface]),
+ ether_dev );
+
+ // Does this REALLY do anything???
+ usb_inc_dev_use( usb );
+
+ // TODO - last minute HACK
+ ether_dev->comm_ep_in = 5;
+
+ // Okay, we are finally done...
+ return NULL;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+// Module's disconnect routine ///////////////////////////////////////////////
+// Called when the driver is unloaded or the device is unplugged /////////////
+// (Whichever happens first assuming the driver suceeded at its probe) ///////
+//////////////////////////////////////////////////////////////////////////////
+
+static void CDCEther_disconnect( struct usb_device *usb, void *ptr )
+{
+ ether_dev_t *ether_dev = ptr;
+
+ // Sanity check!!!
+ if ( !ether_dev || !ether_dev->usb ) {
+ // We failed. We are insane!!!
+ warn("unregistering non-existant device");
+ return;
+ }
+
+ // Make sure we fail the sanity check if we try this again.
+ ether_dev->usb = NULL;
+
+ // It is possible that this function is called before
+ // the "close" function.
+ // This tells the close function we are already disconnected
+ ether_dev->flags |= CDC_ETHER_UNPLUG;
+
+ // We don't need the network device any more
+ unregister_netdev( ether_dev->net );
+
+ // For sanity checks
+ ether_dev->net = NULL;
+
+ // I ask again, does this do anything???
+ usb_dec_dev_use( usb );
+
+ // We are done with this interface
+ usb_driver_release_interface( &CDCEther_driver,
+ &(usb->config[ether_dev->configuration_num].interface[ether_dev->comm_interface]) );
+
+ // We are done with this interface too
+ usb_driver_release_interface( &CDCEther_driver,
+ &(usb->config[ether_dev->configuration_num].interface[ether_dev->data_interface]) );
+
+ // No more tied up kernel memory
+ kfree( ether_dev );
+
+ // This does no good, but it looks nice!
+ ether_dev = NULL;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Driver info ///////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+static struct usb_driver CDCEther_driver = {
+ name: "CDCEther",
+ probe: CDCEther_probe,
+ disconnect: CDCEther_disconnect,
+ id_table: CDCEther_ids,
+};
+
+//////////////////////////////////////////////////////////////////////////////
+// init and exit routines called when driver is installed and uninstalled ////
+//////////////////////////////////////////////////////////////////////////////
+
+int __init CDCEther_init(void)
+{
+ info( "%s", version );
+ return usb_register( &CDCEther_driver );
+}
+
+void __exit CDCEther_exit(void)
+{
+ usb_deregister( &CDCEther_driver );
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Module info ///////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+module_init( CDCEther_init );
+module_exit( CDCEther_exit );
+
+MODULE_AUTHOR("Brad Hards and another");
+MODULE_DESCRIPTION("USB CDC Ethernet driver");
+
+MODULE_DEVICE_TABLE (usb, CDCEther_ids);
+
+//////////////////////////////////////////////////////////////////////////////
+// End of file ///////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
--- /dev/null
+// Portions of this file taken from
+// Petko Manolov - Petkan (petkan@dce.bg)
+// from his driver pegasus.h
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#define CS_INTERFACE 0x24
+
+#define CDC_ETHER_MAX_MTU 1536
+
+#define CDC_ETHER_PRESENT 0x00000001
+#define CDC_ETHER_RUNNING 0x00000002
+#define CDC_ETHER_TX_BUSY 0x00000004
+#define CDC_ETHER_RX_BUSY 0x00000008
+#define CDC_ETHER_UNPLUG 0x00000040
+
+#define CDC_ETHER_TX_TIMEOUT (HZ*10)
+
+#define TX_UNDERRUN 0x80
+#define EXCESSIVE_COL 0x40
+#define LATE_COL 0x20
+#define NO_CARRIER 0x10
+#define LOSS_CARRIER 0x08
+#define JABBER_TIMEOUT 0x04
+
+#define CDC_ETHER_REQT_READ 0xc0
+#define CDC_ETHER_REQT_WRITE 0x40
+#define CDC_ETHER_REQ_GET_REGS 0xf0
+#define CDC_ETHER_REQ_SET_REGS 0xf1
+#define CDC_ETHER_REQ_SET_REG PIPERIDER_REQ_SET_REGS
+#define ALIGN(x) x __attribute__((aligned(L1_CACHE_BYTES)))
+
+typedef struct _ether_dev_t {
+ struct usb_device *usb;
+ struct net_device *net;
+ struct net_device_stats stats;
+ unsigned flags;
+ int configuration_num;
+ int bConfigurationValue;
+ int comm_interface;
+ int comm_bInterfaceNumber;
+ int comm_interface_altset_num;
+ int comm_bAlternateSetting;
+ int comm_ep_in;
+ int data_interface;
+ int data_bInterfaceNumber;
+ int data_interface_altset_num_with_traffic;
+ int data_bAlternateSetting_with_traffic;
+ int data_interface_altset_num_without_traffic;
+ int data_bAlternateSetting_without_traffic;
+ int data_ep_in;
+ int data_ep_out;
+ int data_ep_out_size;
+ __u16 bcdCDC;
+ __u8 iMACAddress;
+ __u32 bmEthernetStatistics;
+ __u16 wMaxSegmentSize;
+ __u16 wNumberMCFilters;
+ __u8 bNumberPowerFilters;
+ int intr_interval;
+ struct urb rx_urb, tx_urb, intr_urb;
+ unsigned char ALIGN(rx_buff[CDC_ETHER_MAX_MTU]);
+ unsigned char ALIGN(tx_buff[CDC_ETHER_MAX_MTU]);
+ unsigned char ALIGN(intr_buff[8]);
+} ether_dev_t;
+
+#define REQ_HDR_FUNC_DESCR 0x0001
+#define REQ_UNION_FUNC_DESCR 0x0002
+#define REQ_ETH_FUNC_DESCR 0x0004
+#define REQUIREMENTS_TOTAL 0x0007
+
+
+
--- /dev/null
+/****************************************************************
+ *
+ * kaweth.c - driver for KL5KUSB101 based USB->Ethernet
+ *
+ * (c) 2000 Interlan Communications
+ * (c) 2000 Stephane Alnet
+ * (C) 2001 Brad Hards
+ *
+ * Original author: The Zapman <zapman@interlan.net>
+ * Inspired by, and much credit goes to Michael Rothwell
+ * <rothwell@interlan.net> for the test equipment, help, and patience
+ * Based off of (and with thanks to) Petko Manolov's pegaus.c driver.
+ * Also many thanks to Joel Silverman and Ed Surprenant at Kawasaki
+ * for providing the firmware and driver resources.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ ****************************************************************/
+
+/* TODO:
+ * Fix in_interrupt() problem
+ * Develop test procedures for USB net interfaces
+ * Run test procedures
+ * Fix bugs from previous two steps
+ * Snoop other OSs for any tricks we're not doing
+ * SMP locking
+ * Reduce arbitrary timeouts
+ * Smart multicast support
+ * Temporary MAC change support
+ * Tunable SOFs parameter - ioctl()?
+ * Ethernet stats collection
+ * Code formatting improvements
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/usb.h>
+#include <linux/types.h>
+#include <asm/semaphore.h>
+
+#define DEBUG
+
+#ifdef DEBUG
+#define kaweth_dbg(format, arg...) printk(KERN_DEBUG __FILE__ ": " format "\n" ,##arg)
+#else
+#define kaweth_dbg(format, arg...) do {} while (0)
+#endif
+#define kaweth_err(format, arg...) printk(KERN_ERR __FILE__ ": " format "\n" ,##arg)
+#define kaweth_info(format, arg...) printk(KERN_INFO __FILE__ ": " format "\n" , ##arg)
+#define kaweth_warn(format, arg...) printk(KERN_WARNING __FILE__ ": " format "\n" , ##arg)
+
+
+#include "kawethfw.h"
+
+#define KAWETH_MTU 1514
+#define KAWETH_BUF_SIZE 1664
+#define KAWETH_TX_TIMEOUT (5 * HZ)
+#define KAWETH_FIRMWARE_BUF_SIZE 4096
+#define KAWETH_CONTROL_TIMEOUT (30 * HZ)
+
+#define KAWETH_STATUS_BROKEN 0x0000001
+#define KAWETH_STATUS_CLOSING 0x0000002
+
+#define KAWETH_PACKET_FILTER_PROMISCUOUS 0x01
+#define KAWETH_PACKET_FILTER_ALL_MULTICAST 0x02
+#define KAWETH_PACKET_FILTER_DIRECTED 0x04
+#define KAWETH_PACKET_FILTER_BROADCAST 0x08
+#define KAWETH_PACKET_FILTER_MULTICAST 0x10
+
+/* Table 7 */
+#define KAWETH_COMMAND_GET_ETHERNET_DESC 0x00
+#define KAWETH_COMMAND_MULTICAST_FILTERS 0x01
+#define KAWETH_COMMAND_SET_PACKET_FILTER 0x02
+#define KAWETH_COMMAND_STATISTICS 0x03
+#define KAWETH_COMMAND_SET_TEMP_MAC 0x06
+#define KAWETH_COMMAND_GET_TEMP_MAC 0x07
+#define KAWETH_COMMAND_SET_URB_SIZE 0x08
+#define KAWETH_COMMAND_SET_SOFS_WAIT 0x09
+#define KAWETH_COMMAND_SCAN 0xFF
+
+#define KAWETH_SOFS_TO_WAIT 0x05
+
+
+MODULE_AUTHOR("Michael Zappe <zapman@interlan.net>, Stephane Alnet <stephane@u-picardie.fr> and Brad Hards <bhards@bigpond.net.au>");
+MODULE_DESCRIPTION("KL5USB101 USB Ethernet driver");
+
+static void *kaweth_probe(
+ struct usb_device *dev, /* the device */
+ unsigned ifnum, /* what interface */
+ const struct usb_device_id *id /* from id_table */
+ );
+static void kaweth_disconnect(struct usb_device *dev, void *ptr);
+int kaweth_internal_control_msg(struct usb_device *usb_dev, unsigned int pipe,
+ devrequest *cmd, void *data, int len,
+ int timeout);
+
+/****************************************************************
+ * usb_device_id
+ ****************************************************************/
+static struct usb_device_id usb_klsi_table[] = {
+ { USB_DEVICE(0x03e8, 0x0008) }, /* AOX Endpoints USB Ethernet */
+ { USB_DEVICE(0x04bb, 0x0901) }, /* I-O DATA USB-ET/T */
+ { USB_DEVICE(0x0506, 0x03e8) }, /* 3Com 3C19250 */
+ { USB_DEVICE(0x0557, 0x2002) }, /* ATEN USB Ethernet */
+ { USB_DEVICE(0x0557, 0x4000) }, /* D-Link DSB-650C */
+ { USB_DEVICE(0x0565, 0x0002) }, /* Peracom Enet */
+ { USB_DEVICE(0x0565, 0x0005) }, /* Peracom Enet2 */
+ { USB_DEVICE(0x05e9, 0x0008) }, /* KLSI KL5KUSB101B */
+ { USB_DEVICE(0x05e9, 0x0009) }, /* KLSI KL5KUSB101B (Board change) */
+ { USB_DEVICE(0x066b, 0x2202) }, /* Linksys USB10T */
+ { USB_DEVICE(0x06e1, 0x0008) }, /* ADS USB-10BT */
+ { USB_DEVICE(0x06e1, 0x0009) }, /* ADS USB-10BT */
+ { USB_DEVICE(0x0707, 0x0100) }, /* SMC 2202USB */
+ { USB_DEVICE(0x07aa, 0x0001) }, /* Correga K.K. */
+ { USB_DEVICE(0x07b8, 0x4000) }, /* D-Link DU-E10 */
+ { USB_DEVICE(0x0846, 0x1001) }, /* NetGear EA-101 */
+ { USB_DEVICE(0x0846, 0x1002) }, /* NetGear EA-101 */
+ { USB_DEVICE(0x085a, 0x0008) }, /* PortGear Ethernet Adapter */
+ { USB_DEVICE(0x085a, 0x0009) }, /* PortGear Ethernet Adapter */
+ { USB_DEVICE(0x087d, 0x5704) }, /* Jaton USB Ethernet Device Adapter */
+ { USB_DEVICE(0x0951, 0x0008) }, /* Kingston Technology USB Ethernet Adapter */
+ { USB_DEVICE(0x095a, 0x3003) }, /* Portsmith Express Ethernet Adapter */
+ { USB_DEVICE(0x10bd, 0x1427) }, /* ASANTE USB To Ethernet Adapter */
+ { USB_DEVICE(0x1342, 0x0204) }, /* Mobility USB-Ethernet Adapter */
+ { USB_DEVICE(0x13d2, 0x0400) }, /* Shark Pocket Adapter */
+ { USB_DEVICE(0x1645, 0x0005) }, /* Entrega E45 */
+ { USB_DEVICE(0x1645, 0x0008) }, /* Entrega USB Ethernet Adapter */
+ { USB_DEVICE(0x1645, 0x8005) }, /* PortGear Ethernet Adapter */
+ { USB_DEVICE(0x2001, 0x4000) }, /* D-link DSB-650C */
+ {} /* Null terminator */
+};
+
+MODULE_DEVICE_TABLE (usb, usb_klsi_table);
+
+/****************************************************************
+ * kaweth_driver
+ ****************************************************************/
+static struct usb_driver kaweth_driver = {
+ name: "kaweth",
+ probe: kaweth_probe,
+ disconnect: kaweth_disconnect,
+ id_table: usb_klsi_table,
+};
+
+typedef __u8 eth_addr_t[6];
+
+/****************************************************************
+ * usb_eth_dev
+ ****************************************************************/
+struct usb_eth_dev {
+ char *name;
+ __u16 vendor;
+ __u16 device;
+ void *pdata;
+};
+
+/****************************************************************
+ * kaweth_ethernet_configuration
+ * Refer Table 8
+ ****************************************************************/
+struct kaweth_ethernet_configuration
+{
+ __u8 size;
+ __u8 reserved1;
+ __u8 reserved2;
+ eth_addr_t hw_addr;
+ __u32 statistics_mask;
+ __u16 segment_size;
+ __u16 max_multicast_filters;
+ __u8 reserved3;
+} __attribute__ ((packed));
+
+/****************************************************************
+ * kaweth_device
+ ****************************************************************/
+struct kaweth_device
+{
+ spinlock_t device_lock;
+
+ __u32 status;
+
+ struct usb_device *dev;
+ struct net_device *net;
+ wait_queue_head_t control_wait;
+
+ struct urb *rx_urb;
+ struct urb *tx_urb;
+
+ __u8 firmware_buf[KAWETH_FIRMWARE_BUF_SIZE];
+ __u8 tx_buf[KAWETH_BUF_SIZE];
+ __u8 rx_buf[KAWETH_BUF_SIZE];
+ __u16 packet_filter_bitmap;
+
+ struct kaweth_ethernet_configuration configuration;
+
+ struct net_device_stats stats;
+} __attribute__ ((packed));
+
+
+/****************************************************************
+ * kaweth_control
+ ****************************************************************/
+static int kaweth_control(struct kaweth_device *kaweth,
+ unsigned int pipe,
+ __u8 request,
+ __u8 requesttype,
+ __u16 value,
+ __u16 index,
+ void *data,
+ __u16 size,
+ int timeout)
+{
+ devrequest *dr;
+
+ kaweth_dbg("kaweth_control()");
+
+ if(in_interrupt()) {
+ kaweth_dbg("in_interrupt()");
+ return -EBUSY;
+ }
+
+ dr = kmalloc(sizeof(devrequest),
+ in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
+
+ if(!dr)
+ {
+ kaweth_dbg("kmalloc() failed");
+ return -ENOMEM;
+ }
+
+ dr->requesttype = requesttype;
+ dr->request = request;
+ dr->value = value;
+ dr->index = index;
+ dr->length = size;
+
+ return kaweth_internal_control_msg(kaweth->dev,
+ pipe,
+ dr,
+ data,
+ size,
+ timeout);
+}
+
+/****************************************************************
+ * kaweth_read_configuration
+ ****************************************************************/
+static int kaweth_read_configuration(struct kaweth_device *kaweth)
+{
+ int retval;
+
+ kaweth_dbg("Reading kaweth configuration");
+
+ retval = kaweth_control(kaweth,
+ usb_rcvctrlpipe(kaweth->dev, 0),
+ KAWETH_COMMAND_GET_ETHERNET_DESC,
+ USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE,
+ 0,
+ 0,
+ (void *)&kaweth->configuration,
+ sizeof(kaweth->configuration),
+ KAWETH_CONTROL_TIMEOUT);
+
+ return retval;
+}
+
+/****************************************************************
+ * kaweth_set_urb_size
+ ****************************************************************/
+static int kaweth_set_urb_size(struct kaweth_device *kaweth, __u16 urb_size)
+{
+ int retval;
+
+ kaweth_dbg("Setting URB size to %d", (unsigned)urb_size);
+
+ retval = kaweth_control(kaweth,
+ usb_sndctrlpipe(kaweth->dev, 0),
+ KAWETH_COMMAND_SET_URB_SIZE,
+ USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
+ urb_size,
+ 0,
+ (void *)&kaweth->firmware_buf,
+ 0,
+ KAWETH_CONTROL_TIMEOUT);
+
+ return retval;
+}
+
+/****************************************************************
+ * kaweth_set_sofs_wait
+ ****************************************************************/
+static int kaweth_set_sofs_wait(struct kaweth_device *kaweth, __u16 sofs_wait)
+{
+ int retval;
+
+ kaweth_dbg("Set SOFS wait to %d", (unsigned)sofs_wait);
+
+ retval = kaweth_control(kaweth,
+ usb_sndctrlpipe(kaweth->dev, 0),
+ KAWETH_COMMAND_SET_SOFS_WAIT,
+ USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
+ sofs_wait,
+ 0,
+ (void *)&kaweth->firmware_buf,
+ 0,
+ KAWETH_CONTROL_TIMEOUT);
+
+ return retval;
+}
+
+/****************************************************************
+ * kaweth_set_receive_filter
+ ****************************************************************/
+static int kaweth_set_receive_filter(struct kaweth_device *kaweth,
+ __u16 receive_filter)
+{
+ int retval;
+
+ kaweth_dbg("Set receive filter to %d", (unsigned)receive_filter);
+
+ retval = kaweth_control(kaweth,
+ usb_sndctrlpipe(kaweth->dev, 0),
+ KAWETH_COMMAND_SET_PACKET_FILTER,
+ USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
+ receive_filter,
+ 0,
+ (void *)&kaweth->firmware_buf,
+ 0,
+ KAWETH_CONTROL_TIMEOUT);
+
+ return retval;
+}
+
+/****************************************************************
+ * kaweth_download_firmware
+ ****************************************************************/
+static int kaweth_download_firmware(struct kaweth_device *kaweth,
+ __u8 *data,
+ __u16 data_len,
+ __u8 interrupt,
+ __u8 type)
+{
+ if(data_len > KAWETH_FIRMWARE_BUF_SIZE) {
+ kaweth_err("Firmware too big: %d", data_len);
+ return -ENOSPC;
+ }
+
+ memcpy(kaweth->firmware_buf, data, data_len);
+
+ kaweth->firmware_buf[2] = (data_len & 0xFF) - 7;
+ kaweth->firmware_buf[3] = data_len >> 8;
+ kaweth->firmware_buf[4] = type;
+ kaweth->firmware_buf[5] = interrupt;
+
+ kaweth_dbg("Downloading firmware at %x to kaweth device at %x",
+ (int)data,
+ (int)kaweth);
+ kaweth_dbg("Firmware length: %d", data_len);
+
+ return kaweth_control(kaweth,
+ usb_sndctrlpipe(kaweth->dev, 0),
+ KAWETH_COMMAND_SCAN,
+ USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
+ 0,
+ 0,
+ (void *)&kaweth->firmware_buf,
+ data_len,
+ KAWETH_CONTROL_TIMEOUT);
+}
+
+/****************************************************************
+ * kaweth_trigger_firmware
+ ****************************************************************/
+static int kaweth_trigger_firmware(struct kaweth_device *kaweth,
+ __u8 interrupt)
+{
+ kaweth->firmware_buf[0] = 0xB6;
+ kaweth->firmware_buf[1] = 0xC3;
+ kaweth->firmware_buf[2] = 0x01;
+ kaweth->firmware_buf[3] = 0x00;
+ kaweth->firmware_buf[4] = 0x06;
+ kaweth->firmware_buf[5] = interrupt;
+ kaweth->firmware_buf[6] = 0x00;
+ kaweth->firmware_buf[7] = 0x00;
+
+ kaweth_dbg("Triggering firmware");
+
+ return kaweth_control(kaweth,
+ usb_sndctrlpipe(kaweth->dev, 0),
+ KAWETH_COMMAND_SCAN,
+ USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
+ 0,
+ 0,
+ (void *)&kaweth->firmware_buf,
+ 8,
+ KAWETH_CONTROL_TIMEOUT);
+}
+
+/****************************************************************
+ * kaweth_reset
+ ****************************************************************/
+static int kaweth_reset(struct kaweth_device *kaweth)
+{
+ int result;
+
+ kaweth_dbg("kaweth_reset(%p)", kaweth);
+ result = kaweth_control(kaweth,
+ usb_sndctrlpipe(kaweth->dev, 0),
+ USB_REQ_SET_CONFIGURATION,
+ 0,
+ kaweth->dev->config[0].bConfigurationValue,
+ 0,
+ NULL,
+ 0,
+ KAWETH_CONTROL_TIMEOUT);
+
+ udelay(10000);
+
+ kaweth_dbg("kaweth_reset() returns %d.",result);
+
+ return result;
+}
+
+static void kaweth_usb_receive(struct urb *);
+
+/****************************************************************
+ * kaweth_resubmit_rx_urb
+ ****************************************************************/
+static inline void kaweth_resubmit_rx_urb(struct kaweth_device *kaweth)
+{
+ int result;
+
+ memset(kaweth->rx_urb, 0, sizeof(*kaweth->rx_urb));
+
+ FILL_BULK_URB(kaweth->rx_urb,
+ kaweth->dev,
+ usb_rcvbulkpipe(kaweth->dev, 1),
+ kaweth->rx_buf,
+ KAWETH_BUF_SIZE,
+ kaweth_usb_receive,
+ kaweth);
+
+ if((result = usb_submit_urb(kaweth->rx_urb))) {
+ kaweth_err("resubmitting rx_urb %d failed", result);
+ }
+}
+
+static void kaweth_async_set_rx_mode(struct kaweth_device *kaweth);
+
+/****************************************************************
+ * kaweth_usb_receive
+ ****************************************************************/
+static void kaweth_usb_receive(struct urb *urb)
+{
+ struct kaweth_device *kaweth = urb->context;
+ struct net_device *net = kaweth->net;
+
+ int count = urb->actual_length;
+ int count2 = urb->transfer_buffer_length;
+
+ __u16 pkt_len = *(__u16 *)kaweth->rx_buf;
+
+ struct sk_buff *skb;
+
+ if(kaweth->status & KAWETH_STATUS_CLOSING) {
+ return;
+ }
+
+ if(urb->status && urb->status != -EREMOTEIO && count != 1) {
+ kaweth_err("%s RX status: %d count: %d packet_len: %d",
+ net->name,
+ urb->status,
+ count,
+ (int)pkt_len);
+ kaweth_resubmit_rx_urb(kaweth);
+ return;
+ }
+
+ if(kaweth->net && (count > 2)) {
+ if(pkt_len > (count - 2)) {
+ kaweth_err("Packet length too long for USB frame (pkt_len: %x, count: %x)",pkt_len, count);
+ kaweth_err("Packet len & 2047: %x", pkt_len & 2047);
+ kaweth_err("Count 2: %x", count2);
+ kaweth_resubmit_rx_urb(kaweth);
+ return;
+ }
+
+ if(!(skb = dev_alloc_skb(pkt_len+2))) {
+ kaweth_resubmit_rx_urb(kaweth);
+ return;
+ }
+
+ skb->dev = net;
+
+ eth_copy_and_sum(skb, kaweth->rx_buf + 2, pkt_len, 0);
+
+ skb_put(skb, pkt_len);
+
+ skb->protocol = eth_type_trans(skb, net);
+
+ netif_rx(skb);
+
+ kaweth->stats.rx_packets++;
+ kaweth->stats.rx_bytes += pkt_len;
+ }
+
+ kaweth_resubmit_rx_urb(kaweth);
+}
+
+/****************************************************************
+ * kaweth_open
+ ****************************************************************/
+static int kaweth_open(struct net_device *net)
+{
+ struct kaweth_device *kaweth = (struct kaweth_device *)net->priv;
+
+ kaweth_dbg("Dev usage: %d", kaweth->dev->refcnt.counter);
+
+ kaweth_dbg("Opening network device.");
+
+ kaweth_resubmit_rx_urb(kaweth);
+
+ netif_start_queue(net);
+
+ MOD_INC_USE_COUNT;
+
+ kaweth_async_set_rx_mode(kaweth);
+ return 0;
+}
+
+/****************************************************************
+ * kaweth_close
+ ****************************************************************/
+static int kaweth_close(struct net_device *net)
+{
+ struct kaweth_device *kaweth = net->priv;
+
+ netif_stop_queue(net);
+
+ kaweth->status |= KAWETH_STATUS_CLOSING;
+
+ usb_unlink_urb(kaweth->rx_urb);
+
+ kaweth->status &= ~KAWETH_STATUS_CLOSING;
+
+ MOD_DEC_USE_COUNT;
+
+ printk("Dev usage: %d", kaweth->dev->refcnt.counter);
+
+ return 0;
+}
+
+/****************************************************************
+ * kaweth_ioctl
+ ****************************************************************/
+static int kaweth_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
+{
+ return -EOPNOTSUPP;
+}
+
+/****************************************************************
+ * kaweth_usb_transmit_complete
+ ****************************************************************/
+static void kaweth_usb_transmit_complete(struct urb *urb)
+{
+ struct kaweth_device *kaweth = urb->context;
+
+ spin_lock(&kaweth->device_lock);
+
+ if (urb->status)
+ kaweth_dbg("%s: TX status %d.", kaweth->net->name, urb->status);
+
+ netif_wake_queue(kaweth->net);
+
+ spin_unlock(&kaweth->device_lock);
+}
+
+/****************************************************************
+ * kaweth_start_xmit
+ ****************************************************************/
+static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net)
+{
+ struct kaweth_device *kaweth = net->priv;
+ int count = skb->len;
+
+ int res;
+
+ spin_lock(&kaweth->device_lock);
+
+ kaweth_async_set_rx_mode(kaweth);
+ netif_stop_queue(net);
+
+ *((__u16 *)kaweth->tx_buf) = skb->len;
+
+ memcpy(kaweth->tx_buf + 2, skb->data, skb->len);
+
+ memset(kaweth->tx_urb, 0, sizeof(*kaweth->tx_urb));
+
+ FILL_BULK_URB(kaweth->tx_urb,
+ kaweth->dev,
+ usb_sndbulkpipe(kaweth->dev, 2),
+ kaweth->tx_buf,
+ count + 2,
+ kaweth_usb_transmit_complete,
+ kaweth);
+
+ if((res = usb_submit_urb(kaweth->tx_urb)))
+ {
+ kaweth_warn("kaweth failed tx_urb %d", res);
+ kaweth->stats.tx_errors++;
+
+ netif_start_queue(net);
+ }
+ else
+ {
+ kaweth->stats.tx_packets++;
+ kaweth->stats.tx_bytes += skb->len;
+ net->trans_start = jiffies;
+ }
+
+ dev_kfree_skb(skb);
+
+ spin_unlock(&kaweth->device_lock);
+
+ return 0;
+}
+
+/****************************************************************
+ * kaweth_set_rx_mode
+ ****************************************************************/
+static void kaweth_set_rx_mode(struct net_device *net)
+{
+ struct kaweth_device *kaweth = net->priv;
+
+ __u16 packet_filter_bitmap = KAWETH_PACKET_FILTER_DIRECTED |
+ KAWETH_PACKET_FILTER_BROADCAST |
+ KAWETH_PACKET_FILTER_MULTICAST;
+
+ kaweth_dbg("Setting Rx mode to %d", packet_filter_bitmap);
+
+ netif_stop_queue(net);
+
+ if (net->flags & IFF_PROMISC) {
+ packet_filter_bitmap |= KAWETH_PACKET_FILTER_PROMISCUOUS;
+ }
+ else if ((net->mc_count) || (net->flags & IFF_ALLMULTI)) {
+ packet_filter_bitmap |= KAWETH_PACKET_FILTER_ALL_MULTICAST;
+ }
+
+ kaweth->packet_filter_bitmap = packet_filter_bitmap;
+ netif_wake_queue(net);
+}
+
+/****************************************************************
+ * kaweth_async_set_rx_mode
+ ****************************************************************/
+static void kaweth_async_set_rx_mode(struct kaweth_device *kaweth)
+{
+ __u16 packet_filter_bitmap = kaweth->packet_filter_bitmap;
+ kaweth->packet_filter_bitmap = 0;
+ if(packet_filter_bitmap == 0) return;
+
+ {
+ int result;
+ result = kaweth_control(kaweth,
+ usb_sndctrlpipe(kaweth->dev, 0),
+ KAWETH_COMMAND_SET_PACKET_FILTER,
+ USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
+ packet_filter_bitmap,
+ 0,
+ (void *)&kaweth->firmware_buf,
+ 0,
+ KAWETH_CONTROL_TIMEOUT);
+
+ if(result < 0) {
+ kaweth_err("Failed to set Rx mode: %d", result);
+ }
+ else {
+ kaweth_dbg("Set Rx mode to %d", packet_filter_bitmap);
+ }
+ }
+}
+
+/****************************************************************
+ * kaweth_netdev_stats
+ ****************************************************************/
+static struct net_device_stats *kaweth_netdev_stats(struct net_device *dev)
+{
+ return &((struct kaweth_device *)dev->priv)->stats;
+}
+
+/****************************************************************
+ * kaweth_tx_timeout
+ ****************************************************************/
+static void kaweth_tx_timeout(struct net_device *net)
+{
+ struct kaweth_device *kaweth = net->priv;
+
+ kaweth_warn("%s: Tx timed out. Resetting.", net->name);
+ kaweth->stats.tx_errors++;
+ net->trans_start = jiffies;
+
+ usb_unlink_urb(kaweth->tx_urb);
+
+ netif_wake_queue(net);
+}
+
+/****************************************************************
+ * kaweth_probe
+ ****************************************************************/
+static void *kaweth_probe(
+ struct usb_device *dev, /* the device */
+ unsigned ifnum, /* what interface */
+ const struct usb_device_id *id /* from id_table */
+ )
+{
+ struct kaweth_device *kaweth;
+ const eth_addr_t bcast_addr = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+ int result = 0;
+
+ kaweth_dbg("Kawasaki Device Probe (Device number:%d): 0x%4.4x:0x%4.4x:0x%4.4x",
+ dev->devnum,
+ (int)dev->descriptor.idVendor,
+ (int)dev->descriptor.idProduct,
+ (int)dev->descriptor.bcdDevice);
+
+ kaweth_dbg("Device at %p", dev);
+
+ kaweth_dbg("Descriptor length: %x type: %x",
+ (int)dev->descriptor.bLength,
+ (int)dev->descriptor.bDescriptorType);
+
+ if(!(kaweth = kmalloc(sizeof(struct kaweth_device), GFP_KERNEL))) {
+ kaweth_dbg("out of memory allocating device structure\n");
+ return NULL;
+ }
+
+ memset(kaweth, 0, sizeof(struct kaweth_device));
+
+ kaweth->dev = dev;
+ kaweth->status = 0;
+ kaweth->net = NULL;
+ kaweth->device_lock = SPIN_LOCK_UNLOCKED;
+
+ kaweth_dbg("Resetting.");
+
+ kaweth_reset(kaweth);
+
+ /*
+ * If high byte of bcdDevice is nonzero, firmware is already
+ * downloaded. Don't try to do it again, or we'll hang the device.
+ */
+
+ if (dev->descriptor.bcdDevice >> 8) {
+ kaweth_info("Firmware present in device.");
+ } else {
+ /* Download the firmware */
+ kaweth_info("Downloading firmware...");
+ if ((result = kaweth_download_firmware(kaweth,
+ kaweth_new_code,
+ len_kaweth_new_code,
+ 100,
+ 2)) < 0) {
+ kaweth_err("Error downloading firmware (%d)", result);
+ kfree(kaweth);
+ return NULL;
+ }
+
+ if ((result = kaweth_download_firmware(kaweth,
+ kaweth_new_code_fix,
+ len_kaweth_new_code_fix,
+ 100,
+ 3)) < 0) {
+ kaweth_err("Error downloading firmware fix (%d)", result);
+ kfree(kaweth);
+ return NULL;
+ }
+
+ if ((result = kaweth_download_firmware(kaweth,
+ kaweth_trigger_code,
+ len_kaweth_trigger_code,
+ 126,
+ 2)) < 0) {
+ kaweth_err("Error downloading trigger code (%d)", result);
+ kfree(kaweth);
+ return NULL;
+ }
+
+ if ((result = kaweth_download_firmware(kaweth,
+ kaweth_trigger_code_fix,
+ len_kaweth_trigger_code_fix,
+ 126,
+ 3)) < 0) {
+ kaweth_err("Error downloading trigger code fix (%d)", result);
+ kfree(kaweth);
+ return NULL;
+ }
+
+
+ if ((result = kaweth_trigger_firmware(kaweth, 126)) < 0) {
+ kaweth_err("Error triggering firmware (%d)", result);
+ kfree(kaweth);
+ return NULL;
+ }
+
+ /* Device will now disappear for a moment... */
+ kaweth_info("Firmware loaded. I'll be back...");
+ return NULL;
+ }
+
+ result = kaweth_read_configuration(kaweth);
+
+ if(result < 0) {
+ kaweth_err("Error reading configuration (%d), no net device created", result);
+ kfree(kaweth);
+ return NULL;
+ }
+
+ kaweth_info("Statistics collection: %x", kaweth->configuration.statistics_mask);
+ kaweth_info("Multicast filter limit: %x", kaweth->configuration.max_multicast_filters & ((1 << 15) - 1));
+ kaweth_info("MTU: %d", kaweth->configuration.segment_size);
+ kaweth_info("Read MAC address %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x",
+ (int)kaweth->configuration.hw_addr[0],
+ (int)kaweth->configuration.hw_addr[1],
+ (int)kaweth->configuration.hw_addr[2],
+ (int)kaweth->configuration.hw_addr[3],
+ (int)kaweth->configuration.hw_addr[4],
+ (int)kaweth->configuration.hw_addr[5]);
+
+ if(!memcmp(&kaweth->configuration.hw_addr,
+ &bcast_addr,
+ sizeof(bcast_addr))) {
+ kaweth_err("Firmware not functioning properly, no net device created");
+ kfree(kaweth);
+ return NULL;
+ }
+
+ if(kaweth_set_urb_size(kaweth, KAWETH_BUF_SIZE) < 0) {
+ kaweth_dbg("Error setting URB size");
+ return kaweth;
+ }
+
+ if(kaweth_set_sofs_wait(kaweth, KAWETH_SOFS_TO_WAIT) < 0) {
+ kaweth_err("Error setting SOFS wait");
+ return kaweth;
+ }
+
+ result = kaweth_set_receive_filter(kaweth,
+ KAWETH_PACKET_FILTER_DIRECTED |
+ KAWETH_PACKET_FILTER_BROADCAST |
+ KAWETH_PACKET_FILTER_MULTICAST);
+
+ if(result < 0) {
+ kaweth_err("Error setting receive filter");
+ return kaweth;
+ }
+
+ kaweth_dbg("Initializing net device.");
+
+ kaweth->tx_urb = usb_alloc_urb(0);
+ kaweth->rx_urb = usb_alloc_urb(0);
+
+ kaweth->net = init_etherdev(0, 0);
+
+ memcpy(kaweth->net->broadcast, &bcast_addr, sizeof(bcast_addr));
+ memcpy(kaweth->net->dev_addr,
+ &kaweth->configuration.hw_addr,
+ sizeof(kaweth->configuration.hw_addr));
+
+ kaweth->net->priv = kaweth;
+ kaweth->net->open = kaweth_open;
+ kaweth->net->stop = kaweth_close;
+
+ kaweth->net->watchdog_timeo = KAWETH_TX_TIMEOUT;
+ kaweth->net->tx_timeout = kaweth_tx_timeout;
+
+ kaweth->net->do_ioctl = kaweth_ioctl;
+ kaweth->net->hard_start_xmit = kaweth_start_xmit;
+ kaweth->net->set_multicast_list = kaweth_set_rx_mode;
+ kaweth->net->get_stats = kaweth_netdev_stats;
+ kaweth->net->mtu = kaweth->configuration.segment_size;
+
+ memset(&kaweth->stats, 0, sizeof(kaweth->stats));
+
+ kaweth_info("kaweth interface created at %s", kaweth->net->name);
+
+ kaweth_dbg("Kaweth probe returning.");
+
+ return kaweth;
+}
+
+/****************************************************************
+ * kaweth_disconnect
+ ****************************************************************/
+static void kaweth_disconnect(struct usb_device *dev, void *ptr)
+{
+ struct kaweth_device *kaweth = ptr;
+
+ kaweth_info("Unregistering");
+
+ if (!kaweth) {
+ kaweth_warn("unregistering non-existant device");
+ return;
+ }
+
+ if(kaweth->net) {
+ if(kaweth->net->flags & IFF_UP) {
+ kaweth_dbg("Closing net device");
+ dev_close(kaweth->net);
+ }
+
+ kaweth_dbg("Unregistering net device");
+ unregister_netdev(kaweth->net);
+ }
+
+ usb_free_urb(kaweth->rx_urb);
+ usb_free_urb(kaweth->tx_urb);
+
+ kfree(kaweth);
+}
+
+
+/*-------------------------------------------------------------------*
+ * completion handler for compatibility wrappers (sync control/bulk) *
+ *-------------------------------------------------------------------*/
+static void usb_api_blocking_completion(urb_t *urb)
+{
+ api_wrapper_data *awd = (api_wrapper_data *)urb->context;
+
+ if (waitqueue_active(awd->wakeup)) {
+ wake_up(awd->wakeup);
+ }
+
+}
+
+/*-------------------------------------------------------------------*
+ * COMPATIBILITY STUFF *
+ *-------------------------------------------------------------------*/
+
+// Starts urb and waits for completion or timeout
+static int usb_start_wait_urb(urb_t *urb, int timeout, int* actual_length)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ DECLARE_WAIT_QUEUE_HEAD(wqh);
+ api_wrapper_data awd;
+ int status;
+
+ awd.wakeup = &wqh;
+ init_waitqueue_head(&wqh);
+ current->state = TASK_INTERRUPTIBLE;
+ add_wait_queue(&wqh, &wait);
+ urb->context = &awd;
+ status = usb_submit_urb(urb);
+ if (status) {
+ // something went wrong
+ usb_free_urb(urb);
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&wqh, &wait);
+ return status;
+ }
+
+ if (urb->status == -EINPROGRESS) {
+ while (timeout && urb->status == -EINPROGRESS)
+ status = timeout = schedule_timeout(timeout);
+ }
+ else {
+ status = 1;
+ }
+
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&wqh, &wait);
+
+ if (!status) {
+ // timeout
+ kaweth_warn("usb_control/bulk_msg: timeout");
+ usb_unlink_urb(urb); // remove urb safely
+ status = -ETIMEDOUT;
+ }
+ else {
+ status = urb->status;
+ }
+
+ if (actual_length) {
+ *actual_length = urb->actual_length;
+ }
+
+ usb_free_urb(urb);
+ return status;
+}
+
+/*-------------------------------------------------------------------*/
+// returns status (negative) or length (positive)
+int kaweth_internal_control_msg(struct usb_device *usb_dev, unsigned int pipe,
+ devrequest *cmd, void *data, int len, int timeout)
+{
+ urb_t *urb;
+ int retv;
+ int length;
+
+ urb = usb_alloc_urb(0);
+ if (!urb)
+ return -ENOMEM;
+
+ FILL_CONTROL_URB(urb, usb_dev, pipe, (unsigned char*)cmd, data,
+ len, (usb_complete_t)usb_api_blocking_completion,0);
+
+ retv = usb_start_wait_urb(urb, timeout, &length);
+ if (retv < 0) {
+ return retv;
+ }
+ else {
+ return length;
+ }
+}
+
+
+/****************************************************************
+ * kaweth_init
+ ****************************************************************/
+int __init kaweth_init(void)
+{
+ kaweth_dbg("Driver loading");
+ return usb_register(&kaweth_driver);
+}
+
+/****************************************************************
+ * kaweth_exit
+ ****************************************************************/
+void __exit kaweth_exit(void)
+{
+ usb_deregister(&kaweth_driver);
+}
+
+module_init(kaweth_init);
+module_exit(kaweth_exit);
+
--- /dev/null
+/******************************************/
+/* NOTE: B6/C3 is data header signature */
+/* 0xAA/0xBB is data length = total */
+/* bytes - 7, 0xCC is type, 0xDD is */
+/* interrupt to use. */
+/******************************************/
+
+/****************************************************************
+ * kaweth_trigger_code
+ ****************************************************************/
+static __u8 kaweth_trigger_code[] =
+{
+ 0xB6, 0xC3, 0xAA, 0xBB, 0xCC, 0xDD,
+ 0xc8, 0x07, 0xa0, 0x00, 0xf0, 0x07, 0x5e, 0x00,
+ 0x06, 0x00, 0xf0, 0x07, 0x0a, 0x00, 0x08, 0x00,
+ 0xf0, 0x09, 0x00, 0x00, 0x02, 0x00, 0xe7, 0x07,
+ 0x36, 0x00, 0x00, 0x00, 0xf0, 0x07, 0x00, 0x00,
+ 0x04, 0x00, 0xe7, 0x07, 0x50, 0xc3, 0x10, 0xc0,
+ 0xf0, 0x09, 0x0e, 0xc0, 0x00, 0x00, 0xe7, 0x87,
+ 0x01, 0x00, 0x0e, 0xc0, 0x97, 0xcf, 0xd7, 0x09,
+ 0x00, 0xc0, 0x17, 0x02, 0xc8, 0x07, 0xa0, 0x00,
+ 0xe7, 0x17, 0x50, 0xc3, 0x10, 0xc0, 0x30, 0xd8,
+ 0x04, 0x00, 0x30, 0x5c, 0x08, 0x00, 0x04, 0x00,
+ 0xb0, 0xc0, 0x06, 0x00, 0xc8, 0x05, 0xe7, 0x05,
+ 0x00, 0xc0, 0xc0, 0xdf, 0x97, 0xcf, 0x49, 0xaf,
+ 0xc0, 0x07, 0x00, 0x00, 0x60, 0xaf, 0x4a, 0xaf,
+ 0x00, 0x0c, 0x0c, 0x00, 0x40, 0xd2, 0x00, 0x1c,
+ 0x0c, 0x00, 0x40, 0xd2, 0x30, 0x00, 0x08, 0x00,
+ 0xf0, 0x07, 0x00, 0x00, 0x04, 0x00, 0xf0, 0x07,
+ 0x86, 0x00, 0x06, 0x00, 0x67, 0xcf, 0x27, 0x0c,
+ 0x02, 0x00, 0x00, 0x00, 0x27, 0x0c, 0x00, 0x00,
+ 0x0e, 0xc0, 0x49, 0xaf, 0x64, 0xaf, 0xc0, 0x07,
+ 0x00, 0x00, 0x4b, 0xaf, 0x4a, 0xaf, 0x5a, 0xcf,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x94, 0x00, 0x05, 0x00,
+ 0x00, 0x00
+};
+/****************************************************************
+ * kaweth_trigger_code_fix
+ ****************************************************************/
+static __u8 kaweth_trigger_code_fix[] =
+{
+ 0xB6, 0xC3, 0xAA, 0xBB, 0xCC, 0xDD,
+ 0x02, 0x00, 0x06, 0x00, 0x18, 0x00, 0x3e, 0x00,
+ 0x80, 0x00, 0x98, 0x00, 0xaa, 0x00,
+ 0x00, 0x00
+};
+
+/****************************************************************
+ * kaweth_new_code
+ ****************************************************************/
+static __u8 kaweth_new_code[] =
+{
+ 0xB6, 0xC3, 0xAA, 0xBB, 0xCC, 0xDD,
+ 0x9f, 0xcf, 0xde, 0x06, 0xe7, 0x57, 0x00, 0x00,
+ 0xc4, 0x06, 0x97, 0xc1, 0xe7, 0x67, 0xff, 0x1f,
+ 0x28, 0xc0, 0xe7, 0x87, 0x00, 0x04, 0x24, 0xc0,
+ 0xe7, 0x67, 0xff, 0xf9, 0x22, 0xc0, 0x97, 0xcf,
+ 0xd7, 0x09, 0x00, 0xc0, 0xe7, 0x09, 0xa2, 0xc0,
+ 0xbe, 0x06, 0x9f, 0xaf, 0x36, 0x00, 0xe7, 0x05,
+ 0x00, 0xc0, 0xa7, 0xcf, 0xbc, 0x06, 0x97, 0xcf,
+ 0xe7, 0x57, 0x00, 0x00, 0xb8, 0x06, 0xa7, 0xa1,
+ 0xb8, 0x06, 0x97, 0xcf, 0xe7, 0x57, 0x00, 0x00,
+ 0x14, 0x08, 0x0a, 0xc0, 0xe7, 0x57, 0x00, 0x00,
+ 0xa4, 0xc0, 0xa7, 0xc0, 0x7a, 0x06, 0x9f, 0xaf,
+ 0x92, 0x07, 0xe7, 0x07, 0x00, 0x00, 0x14, 0x08,
+ 0xe7, 0x57, 0xff, 0xff, 0xba, 0x06, 0x9f, 0xa0,
+ 0x38, 0x00, 0xe7, 0x59, 0xba, 0x06, 0xbe, 0x06,
+ 0x9f, 0xa0, 0x38, 0x00, 0xc8, 0x09, 0xca, 0x06,
+ 0x08, 0x62, 0x9f, 0xa1, 0x36, 0x08, 0xc0, 0x09,
+ 0x76, 0x06, 0x00, 0x60, 0xa7, 0xc0, 0x7a, 0x06,
+ 0x9f, 0xaf, 0xcc, 0x02, 0xe7, 0x57, 0x00, 0x00,
+ 0xb8, 0x06, 0xa7, 0xc1, 0x7a, 0x06, 0x9f, 0xaf,
+ 0x04, 0x00, 0xe7, 0x57, 0x00, 0x00, 0x8e, 0x06,
+ 0x0a, 0xc1, 0xe7, 0x09, 0x20, 0xc0, 0x10, 0x08,
+ 0xe7, 0xd0, 0x10, 0x08, 0xe7, 0x67, 0x40, 0x00,
+ 0x10, 0x08, 0x9f, 0xaf, 0x92, 0x0c, 0xc0, 0x09,
+ 0xd0, 0x06, 0x00, 0x60, 0x05, 0xc4, 0xc0, 0x59,
+ 0xbe, 0x06, 0x02, 0xc0, 0x9f, 0xaf, 0xec, 0x00,
+ 0x9f, 0xaf, 0x34, 0x02, 0xe7, 0x57, 0x00, 0x00,
+ 0xa6, 0x06, 0x9f, 0xa0, 0x7a, 0x02, 0xa7, 0xcf,
+ 0x7a, 0x06, 0x48, 0x02, 0xe7, 0x09, 0xbe, 0x06,
+ 0xd0, 0x06, 0xc8, 0x37, 0x04, 0x00, 0x9f, 0xaf,
+ 0x08, 0x03, 0x97, 0xcf, 0xe7, 0x57, 0x00, 0x00,
+ 0xce, 0x06, 0x97, 0xc0, 0xd7, 0x09, 0x00, 0xc0,
+ 0xc1, 0xdf, 0xc8, 0x09, 0xc6, 0x06, 0x08, 0x62,
+ 0x14, 0xc0, 0x27, 0x04, 0xc6, 0x06, 0x10, 0x94,
+ 0xf0, 0x07, 0x10, 0x08, 0x02, 0x00, 0xc1, 0x07,
+ 0x01, 0x00, 0x70, 0x00, 0x04, 0x00, 0xf0, 0x07,
+ 0x30, 0x01, 0x06, 0x00, 0x50, 0xaf, 0xe7, 0x07,
+ 0xff, 0xff, 0xd0, 0x06, 0xe7, 0x07, 0x00, 0x00,
+ 0xce, 0x06, 0xe7, 0x05, 0x00, 0xc0, 0x97, 0xcf,
+ 0xd7, 0x09, 0x00, 0xc0, 0xc1, 0xdf, 0x48, 0x02,
+ 0xd0, 0x09, 0xc6, 0x06, 0x27, 0x02, 0xc6, 0x06,
+ 0xe7, 0x05, 0x00, 0xc0, 0x97, 0xcf, 0x48, 0x02,
+ 0xc8, 0x37, 0x04, 0x00, 0x00, 0x0c, 0x0c, 0x00,
+ 0x00, 0x60, 0x21, 0xc0, 0xc0, 0x37, 0x3e, 0x00,
+ 0x23, 0xc9, 0xc0, 0x57, 0xb4, 0x05, 0x1b, 0xc8,
+ 0xc0, 0x17, 0x3f, 0x00, 0xc0, 0x67, 0xc0, 0xff,
+ 0x30, 0x00, 0x08, 0x00, 0xf0, 0x07, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x02, 0xc0, 0x17, 0x4c, 0x00,
+ 0x30, 0x00, 0x06, 0x00, 0xf0, 0x07, 0xa0, 0x01,
+ 0x0a, 0x00, 0x48, 0x02, 0xc1, 0x07, 0x02, 0x00,
+ 0xd7, 0x09, 0x00, 0xc0, 0xc1, 0xdf, 0x51, 0xaf,
+ 0xe7, 0x05, 0x00, 0xc0, 0x97, 0xcf, 0x9f, 0xaf,
+ 0x08, 0x03, 0x9f, 0xaf, 0x7a, 0x02, 0x97, 0xcf,
+ 0x9f, 0xaf, 0x7a, 0x02, 0xc9, 0x37, 0x04, 0x00,
+ 0xc1, 0xdf, 0xc8, 0x09, 0xa2, 0x06, 0x50, 0x02,
+ 0x67, 0x02, 0xa2, 0x06, 0xd1, 0x07, 0x00, 0x00,
+ 0x27, 0xd8, 0xaa, 0x06, 0xc0, 0xdf, 0x9f, 0xaf,
+ 0xc4, 0x01, 0x97, 0xcf, 0xe7, 0x57, 0x00, 0x00,
+ 0xd2, 0x06, 0x97, 0xc1, 0xe7, 0x57, 0x01, 0x00,
+ 0xa8, 0x06, 0x97, 0xc0, 0xc8, 0x09, 0xa0, 0x06,
+ 0x08, 0x62, 0x97, 0xc0, 0x00, 0x02, 0xc0, 0x17,
+ 0x0e, 0x00, 0x27, 0x00, 0x34, 0x01, 0x27, 0x0c,
+ 0x0c, 0x00, 0x36, 0x01, 0xe7, 0x07, 0x50, 0xc3,
+ 0x12, 0xc0, 0xe7, 0x07, 0xcc, 0x0b, 0x02, 0x00,
+ 0xe7, 0x07, 0x01, 0x00, 0xa8, 0x06, 0xe7, 0x07,
+ 0x05, 0x00, 0x90, 0xc0, 0x97, 0xcf, 0xc8, 0x09,
+ 0xa4, 0x06, 0x08, 0x62, 0x02, 0xc0, 0x10, 0x64,
+ 0x07, 0xc1, 0xe7, 0x07, 0x00, 0x00, 0x9e, 0x06,
+ 0xe7, 0x07, 0x72, 0x04, 0x24, 0x00, 0x97, 0xcf,
+ 0x27, 0x04, 0xa4, 0x06, 0xc8, 0x17, 0x0e, 0x00,
+ 0x27, 0x02, 0x9e, 0x06, 0xe7, 0x07, 0x80, 0x04,
+ 0x24, 0x00, 0x97, 0xcf, 0xd7, 0x09, 0x00, 0xc0,
+ 0xc1, 0xdf, 0xe7, 0x57, 0x00, 0x00, 0x90, 0x06,
+ 0x13, 0xc1, 0x9f, 0xaf, 0x06, 0x02, 0xe7, 0x57,
+ 0x00, 0x00, 0x9e, 0x06, 0x13, 0xc0, 0xe7, 0x09,
+ 0x9e, 0x06, 0x30, 0x01, 0xe7, 0x07, 0xf2, 0x05,
+ 0x32, 0x01, 0xe7, 0x07, 0x10, 0x00, 0x96, 0xc0,
+ 0xe7, 0x09, 0x9e, 0x06, 0x90, 0x06, 0x04, 0xcf,
+ 0xe7, 0x57, 0x00, 0x00, 0x9e, 0x06, 0x02, 0xc1,
+ 0x9f, 0xaf, 0x06, 0x02, 0xe7, 0x05, 0x00, 0xc0,
+ 0x97, 0xcf, 0xd7, 0x09, 0x00, 0xc0, 0xc1, 0xdf,
+ 0x08, 0x92, 0xe7, 0x57, 0x02, 0x00, 0xaa, 0x06,
+ 0x02, 0xc3, 0xc8, 0x09, 0xa4, 0x06, 0x27, 0x02,
+ 0xa6, 0x06, 0x08, 0x62, 0x03, 0xc1, 0xe7, 0x05,
+ 0x00, 0xc0, 0x97, 0xcf, 0x27, 0x04, 0xa4, 0x06,
+ 0xe7, 0x05, 0x00, 0xc0, 0xf0, 0x07, 0x40, 0x00,
+ 0x08, 0x00, 0xf0, 0x07, 0x00, 0x00, 0x04, 0x00,
+ 0x00, 0x02, 0xc0, 0x17, 0x0c, 0x00, 0x30, 0x00,
+ 0x06, 0x00, 0xf0, 0x07, 0x46, 0x01, 0x0a, 0x00,
+ 0xc8, 0x17, 0x04, 0x00, 0xc1, 0x07, 0x02, 0x00,
+ 0x51, 0xaf, 0x97, 0xcf, 0xe7, 0x57, 0x00, 0x00,
+ 0x96, 0x06, 0x97, 0xc0, 0xc1, 0xdf, 0xc8, 0x09,
+ 0x96, 0x06, 0x27, 0x04, 0x96, 0x06, 0x27, 0x52,
+ 0x98, 0x06, 0x03, 0xc1, 0xe7, 0x07, 0x96, 0x06,
+ 0x98, 0x06, 0xc0, 0xdf, 0x17, 0x02, 0xc8, 0x17,
+ 0x0e, 0x00, 0x9f, 0xaf, 0xba, 0x03, 0xc8, 0x05,
+ 0x00, 0x60, 0x03, 0xc0, 0x9f, 0xaf, 0x24, 0x03,
+ 0x97, 0xcf, 0x9f, 0xaf, 0x08, 0x03, 0x97, 0xcf,
+ 0x57, 0x02, 0xc9, 0x07, 0xa4, 0x06, 0xd7, 0x09,
+ 0x00, 0xc0, 0xc1, 0xdf, 0x08, 0x62, 0x1b, 0xc0,
+ 0x50, 0x04, 0x11, 0x02, 0xe7, 0x05, 0x00, 0xc0,
+ 0xc9, 0x05, 0x97, 0xcf, 0x97, 0x02, 0xca, 0x09,
+ 0xd6, 0x06, 0xf2, 0x17, 0x01, 0x00, 0x04, 0x00,
+ 0xf2, 0x27, 0x00, 0x00, 0x06, 0x00, 0xca, 0x17,
+ 0x2c, 0x00, 0xf8, 0x77, 0x01, 0x00, 0x0e, 0x00,
+ 0x06, 0xc0, 0xca, 0xd9, 0xf8, 0x57, 0xff, 0x00,
+ 0x0e, 0x00, 0x01, 0xc1, 0xca, 0xd9, 0x22, 0x1c,
+ 0x0c, 0x00, 0xe2, 0x27, 0x00, 0x00, 0xe2, 0x17,
+ 0x01, 0x00, 0xe2, 0x27, 0x00, 0x00, 0xca, 0x05,
+ 0x00, 0x0c, 0x0c, 0x00, 0xc0, 0x17, 0x41, 0x00,
+ 0xc0, 0x67, 0xc0, 0xff, 0x30, 0x00, 0x08, 0x00,
+ 0x00, 0x02, 0xc0, 0x17, 0x0c, 0x00, 0x30, 0x00,
+ 0x06, 0x00, 0xf0, 0x07, 0xda, 0x00, 0x0a, 0x00,
+ 0xf0, 0x07, 0x00, 0x00, 0x04, 0x00, 0x00, 0x0c,
+ 0x08, 0x00, 0x40, 0xd1, 0x01, 0x00, 0xc0, 0x19,
+ 0xce, 0x06, 0xc0, 0x59, 0xc2, 0x06, 0x04, 0xc9,
+ 0x49, 0xaf, 0x9f, 0xaf, 0xec, 0x00, 0x4a, 0xaf,
+ 0x67, 0x10, 0xce, 0x06, 0xc8, 0x17, 0x04, 0x00,
+ 0xc1, 0x07, 0x01, 0x00, 0xd7, 0x09, 0x00, 0xc0,
+ 0xc1, 0xdf, 0x50, 0xaf, 0xe7, 0x05, 0x00, 0xc0,
+ 0x97, 0xcf, 0xc0, 0x07, 0x01, 0x00, 0xc1, 0x09,
+ 0xac, 0x06, 0xc1, 0x77, 0x01, 0x00, 0x97, 0xc1,
+ 0xd8, 0x77, 0x01, 0x00, 0x12, 0xc0, 0xc9, 0x07,
+ 0x6a, 0x06, 0x9f, 0xaf, 0x08, 0x04, 0x04, 0xc1,
+ 0xc1, 0x77, 0x08, 0x00, 0x13, 0xc0, 0x97, 0xcf,
+ 0xc1, 0x77, 0x02, 0x00, 0x97, 0xc1, 0xc1, 0x77,
+ 0x10, 0x00, 0x0c, 0xc0, 0x9f, 0xaf, 0x2c, 0x04,
+ 0x97, 0xcf, 0xc1, 0x77, 0x04, 0x00, 0x06, 0xc0,
+ 0xc9, 0x07, 0x70, 0x06, 0x9f, 0xaf, 0x08, 0x04,
+ 0x97, 0xc0, 0x00, 0xcf, 0x00, 0x90, 0x97, 0xcf,
+ 0x50, 0x54, 0x97, 0xc1, 0x70, 0x5c, 0x02, 0x00,
+ 0x02, 0x00, 0x97, 0xc1, 0x70, 0x5c, 0x04, 0x00,
+ 0x04, 0x00, 0x97, 0xcf, 0x80, 0x01, 0xc0, 0x00,
+ 0x60, 0x00, 0x30, 0x00, 0x18, 0x00, 0x0c, 0x00,
+ 0x06, 0x00, 0x00, 0x00, 0xcb, 0x09, 0xb2, 0x06,
+ 0xcc, 0x09, 0xb4, 0x06, 0x0b, 0x53, 0x11, 0xc0,
+ 0xc9, 0x02, 0xca, 0x07, 0x1c, 0x04, 0x9f, 0xaf,
+ 0x08, 0x04, 0x97, 0xc0, 0x0a, 0xc8, 0x82, 0x08,
+ 0x0a, 0xcf, 0x82, 0x08, 0x9f, 0xaf, 0x08, 0x04,
+ 0x97, 0xc0, 0x05, 0xc2, 0x89, 0x30, 0x82, 0x60,
+ 0x78, 0xc1, 0x00, 0x90, 0x97, 0xcf, 0x89, 0x10,
+ 0x09, 0x53, 0x79, 0xc2, 0x89, 0x30, 0x82, 0x08,
+ 0x7a, 0xcf, 0xc0, 0xdf, 0x97, 0xcf, 0xc0, 0xdf,
+ 0x97, 0xcf, 0xe7, 0x09, 0x96, 0xc0, 0x92, 0x06,
+ 0xe7, 0x09, 0x98, 0xc0, 0x94, 0x06, 0x0f, 0xcf,
+ 0xe7, 0x09, 0x96, 0xc0, 0x92, 0x06, 0xe7, 0x09,
+ 0x98, 0xc0, 0x94, 0x06, 0xe7, 0x09, 0x9e, 0x06,
+ 0x30, 0x01, 0xe7, 0x07, 0xf2, 0x05, 0x32, 0x01,
+ 0xe7, 0x07, 0x10, 0x00, 0x96, 0xc0, 0xd7, 0x09,
+ 0x00, 0xc0, 0x17, 0x02, 0xc8, 0x09, 0x90, 0x06,
+ 0xc8, 0x37, 0x0e, 0x00, 0xe7, 0x77, 0x2a, 0x00,
+ 0x92, 0x06, 0x30, 0xc0, 0x97, 0x02, 0xca, 0x09,
+ 0xd6, 0x06, 0xe7, 0x77, 0x20, 0x00, 0x92, 0x06,
+ 0x0e, 0xc0, 0xf2, 0x17, 0x01, 0x00, 0x10, 0x00,
+ 0xf2, 0x27, 0x00, 0x00, 0x12, 0x00, 0xe7, 0x77,
+ 0x0a, 0x00, 0x92, 0x06, 0xca, 0x05, 0x1e, 0xc0,
+ 0x97, 0x02, 0xca, 0x09, 0xd6, 0x06, 0xf2, 0x17,
+ 0x01, 0x00, 0x0c, 0x00, 0xf2, 0x27, 0x00, 0x00,
+ 0x0e, 0x00, 0xe7, 0x77, 0x02, 0x00, 0x92, 0x06,
+ 0x07, 0xc0, 0xf2, 0x17, 0x01, 0x00, 0x44, 0x00,
+ 0xf2, 0x27, 0x00, 0x00, 0x46, 0x00, 0x06, 0xcf,
+ 0xf2, 0x17, 0x01, 0x00, 0x60, 0x00, 0xf2, 0x27,
+ 0x00, 0x00, 0x62, 0x00, 0xca, 0x05, 0x9f, 0xaf,
+ 0x08, 0x03, 0x0f, 0xcf, 0x57, 0x02, 0x09, 0x02,
+ 0xf1, 0x09, 0x94, 0x06, 0x0c, 0x00, 0xf1, 0xda,
+ 0x0c, 0x00, 0xc8, 0x09, 0x98, 0x06, 0x50, 0x02,
+ 0x67, 0x02, 0x98, 0x06, 0xd1, 0x07, 0x00, 0x00,
+ 0xc9, 0x05, 0xe7, 0x09, 0x9e, 0x06, 0x90, 0x06,
+ 0xe7, 0x57, 0x00, 0x00, 0x90, 0x06, 0x02, 0xc0,
+ 0x9f, 0xaf, 0x06, 0x02, 0xc8, 0x05, 0xe7, 0x05,
+ 0x00, 0xc0, 0xc0, 0xdf, 0x97, 0xcf, 0xd7, 0x09,
+ 0x00, 0xc0, 0x17, 0x00, 0x17, 0x02, 0x97, 0x02,
+ 0xc0, 0x09, 0x92, 0xc0, 0xe7, 0x07, 0x04, 0x00,
+ 0x90, 0xc0, 0xca, 0x09, 0xd6, 0x06, 0xe7, 0x07,
+ 0x00, 0x00, 0xa8, 0x06, 0xe7, 0x07, 0x6a, 0x04,
+ 0x02, 0x00, 0xc0, 0x77, 0x02, 0x00, 0x08, 0xc0,
+ 0xf2, 0x17, 0x01, 0x00, 0x50, 0x00, 0xf2, 0x27,
+ 0x00, 0x00, 0x52, 0x00, 0x9f, 0xcf, 0x24, 0x06,
+ 0xc0, 0x77, 0x10, 0x00, 0x06, 0xc0, 0xf2, 0x17,
+ 0x01, 0x00, 0x58, 0x00, 0xf2, 0x27, 0x00, 0x00,
+ 0x5a, 0x00, 0xc0, 0x77, 0x80, 0x00, 0x06, 0xc0,
+ 0xf2, 0x17, 0x01, 0x00, 0x70, 0x00, 0xf2, 0x27,
+ 0x00, 0x00, 0x72, 0x00, 0xc0, 0x77, 0x08, 0x00,
+ 0x1d, 0xc1, 0xf2, 0x17, 0x01, 0x00, 0x08, 0x00,
+ 0xf2, 0x27, 0x00, 0x00, 0x0a, 0x00, 0xc0, 0x77,
+ 0x00, 0x02, 0x06, 0xc0, 0xf2, 0x17, 0x01, 0x00,
+ 0x64, 0x00, 0xf2, 0x27, 0x00, 0x00, 0x66, 0x00,
+ 0xc0, 0x77, 0x40, 0x00, 0x06, 0xc0, 0xf2, 0x17,
+ 0x01, 0x00, 0x5c, 0x00, 0xf2, 0x27, 0x00, 0x00,
+ 0x5e, 0x00, 0xc0, 0x77, 0x01, 0x00, 0x01, 0xc0,
+ 0x1b, 0xcf, 0x1a, 0xcf, 0xf2, 0x17, 0x01, 0x00,
+ 0x00, 0x00, 0xf2, 0x27, 0x00, 0x00, 0x02, 0x00,
+ 0xc8, 0x09, 0x34, 0x01, 0xca, 0x17, 0x14, 0x00,
+ 0xd8, 0x77, 0x01, 0x00, 0x05, 0xc0, 0xca, 0xd9,
+ 0xd8, 0x57, 0xff, 0x00, 0x01, 0xc0, 0xca, 0xd9,
+ 0xe2, 0x19, 0x94, 0xc0, 0xe2, 0x27, 0x00, 0x00,
+ 0xe2, 0x17, 0x01, 0x00, 0xe2, 0x27, 0x00, 0x00,
+ 0x9f, 0xaf, 0x40, 0x06, 0x9f, 0xaf, 0xc4, 0x01,
+ 0xe7, 0x57, 0x00, 0x00, 0xd2, 0x06, 0x9f, 0xa1,
+ 0x0e, 0x0a, 0xca, 0x05, 0xc8, 0x05, 0xc0, 0x05,
+ 0xe7, 0x05, 0x00, 0xc0, 0xc0, 0xdf, 0x97, 0xcf,
+ 0xc8, 0x09, 0xa0, 0x06, 0x08, 0x62, 0x97, 0xc0,
+ 0x27, 0x04, 0xa0, 0x06, 0x27, 0x52, 0xa2, 0x06,
+ 0x03, 0xc1, 0xe7, 0x07, 0xa0, 0x06, 0xa2, 0x06,
+ 0x9f, 0xaf, 0x08, 0x03, 0xe7, 0x57, 0x00, 0x00,
+ 0xaa, 0x06, 0x02, 0xc0, 0x27, 0xda, 0xaa, 0x06,
+ 0x97, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0xff, 0xff, 0xfb, 0x13, 0xe7, 0x57,
+ 0x00, 0x80, 0xb2, 0x00, 0x06, 0xc2, 0xe7, 0x07,
+ 0xee, 0x0b, 0x12, 0x00, 0xe7, 0x07, 0x34, 0x0c,
+ 0xb2, 0x00, 0xe7, 0x07, 0xc6, 0x07, 0xf2, 0x02,
+ 0xc8, 0x09, 0xb4, 0x00, 0xf8, 0x07, 0x02, 0x00,
+ 0x0d, 0x00, 0xd7, 0x09, 0x0e, 0xc0, 0xe7, 0x07,
+ 0x00, 0x00, 0x0e, 0xc0, 0xc8, 0x09, 0xde, 0x00,
+ 0xc8, 0x17, 0x09, 0x00, 0xc9, 0x07, 0xda, 0x06,
+ 0xc0, 0x07, 0x04, 0x00, 0x68, 0x0a, 0x00, 0xda,
+ 0x7d, 0xc1, 0xe7, 0x09, 0xc0, 0x00, 0x7c, 0x06,
+ 0xe7, 0x09, 0xbe, 0x00, 0x78, 0x06, 0xe7, 0x09,
+ 0x10, 0x00, 0xbc, 0x06, 0xc8, 0x07, 0xd6, 0x07,
+ 0x9f, 0xaf, 0xae, 0x07, 0x9f, 0xaf, 0x00, 0x0a,
+ 0xc8, 0x09, 0xde, 0x00, 0x00, 0x0e, 0x0f, 0x00,
+ 0x41, 0x90, 0x9f, 0xde, 0x06, 0x00, 0x44, 0xaf,
+ 0x27, 0x00, 0xb2, 0x06, 0x27, 0x00, 0xb4, 0x06,
+ 0x27, 0x00, 0xb6, 0x06, 0xc0, 0x07, 0x74, 0x00,
+ 0x44, 0xaf, 0x27, 0x00, 0xd6, 0x06, 0x08, 0x00,
+ 0x00, 0x90, 0xc1, 0x07, 0x3a, 0x00, 0x20, 0x00,
+ 0x01, 0xda, 0x7d, 0xc1, 0x9f, 0xaf, 0xba, 0x09,
+ 0xc0, 0x07, 0x44, 0x00, 0x48, 0xaf, 0x27, 0x00,
+ 0x7a, 0x06, 0x9f, 0xaf, 0x96, 0x0a, 0xe7, 0x07,
+ 0x01, 0x00, 0xc0, 0x06, 0xe7, 0x05, 0x0e, 0xc0,
+ 0x97, 0xcf, 0x49, 0xaf, 0xe7, 0x87, 0x43, 0x00,
+ 0x0e, 0xc0, 0xe7, 0x07, 0xff, 0xff, 0xbe, 0x06,
+ 0x9f, 0xaf, 0xae, 0x0a, 0xc0, 0x07, 0x01, 0x00,
+ 0x60, 0xaf, 0x4a, 0xaf, 0x97, 0xcf, 0x00, 0x08,
+ 0x09, 0x08, 0x11, 0x08, 0x00, 0xda, 0x7c, 0xc1,
+ 0x97, 0xcf, 0x67, 0x04, 0xcc, 0x02, 0xc0, 0xdf,
+ 0x51, 0x94, 0xb1, 0xaf, 0x06, 0x00, 0xc1, 0xdf,
+ 0xc9, 0x09, 0xcc, 0x02, 0x49, 0x62, 0x75, 0xc1,
+ 0xc0, 0xdf, 0xa7, 0xcf, 0xd6, 0x02, 0x0e, 0x00,
+ 0x24, 0x00, 0x80, 0x04, 0x22, 0x00, 0x4e, 0x05,
+ 0xd0, 0x00, 0x0e, 0x0a, 0xaa, 0x00, 0x30, 0x08,
+ 0xbe, 0x00, 0x4a, 0x0a, 0x10, 0x00, 0x20, 0x00,
+ 0x04, 0x00, 0x6e, 0x04, 0x02, 0x00, 0x6a, 0x04,
+ 0x06, 0x00, 0x00, 0x00, 0x24, 0xc0, 0x04, 0x04,
+ 0x28, 0xc0, 0xfe, 0xfb, 0x1e, 0xc0, 0x00, 0x04,
+ 0x22, 0xc0, 0xff, 0xf4, 0xc0, 0x00, 0x90, 0x09,
+ 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x56, 0x08,
+ 0x60, 0x08, 0xd0, 0x08, 0xda, 0x08, 0x00, 0x09,
+ 0x04, 0x09, 0x08, 0x09, 0x32, 0x09, 0x42, 0x09,
+ 0x50, 0x09, 0x52, 0x09, 0x5a, 0x09, 0x5a, 0x09,
+ 0x27, 0x02, 0xca, 0x06, 0x97, 0xcf, 0xe7, 0x07,
+ 0x00, 0x00, 0xca, 0x06, 0x0a, 0x0e, 0x01, 0x00,
+ 0xca, 0x57, 0x0e, 0x00, 0x9f, 0xc3, 0x5a, 0x09,
+ 0xca, 0x37, 0x00, 0x00, 0x9f, 0xc2, 0x5a, 0x09,
+ 0x0a, 0xd2, 0xb2, 0xcf, 0x16, 0x08, 0xc8, 0x09,
+ 0xde, 0x00, 0x07, 0x06, 0x9f, 0xcf, 0x6c, 0x09,
+ 0x17, 0x02, 0xc8, 0x09, 0xde, 0x00, 0x00, 0x0e,
+ 0x0f, 0x00, 0x41, 0x90, 0x9f, 0xde, 0x06, 0x00,
+ 0xc8, 0x05, 0x30, 0x50, 0x06, 0x00, 0x9f, 0xc8,
+ 0x5a, 0x09, 0x27, 0x0c, 0x02, 0x00, 0xb0, 0x06,
+ 0xc0, 0x09, 0xb2, 0x06, 0x27, 0x00, 0xb4, 0x06,
+ 0xe7, 0x07, 0x00, 0x00, 0xae, 0x06, 0x27, 0x00,
+ 0x80, 0x06, 0x00, 0x1c, 0x06, 0x00, 0x27, 0x00,
+ 0xb6, 0x06, 0x41, 0x90, 0x67, 0x50, 0xb0, 0x06,
+ 0x0d, 0xc0, 0x67, 0x00, 0x7e, 0x06, 0x27, 0x0c,
+ 0x06, 0x00, 0x82, 0x06, 0xe7, 0x07, 0xbc, 0x08,
+ 0x84, 0x06, 0xc8, 0x07, 0x7e, 0x06, 0x41, 0x90,
+ 0x51, 0xaf, 0x97, 0xcf, 0x9f, 0xaf, 0x48, 0x0c,
+ 0xe7, 0x09, 0xb6, 0x06, 0xb4, 0x06, 0xe7, 0x09,
+ 0xb0, 0x06, 0xae, 0x06, 0x59, 0xaf, 0x97, 0xcf,
+ 0x27, 0x0c, 0x02, 0x00, 0xac, 0x06, 0x59, 0xaf,
+ 0x97, 0xcf, 0x09, 0x0c, 0x02, 0x00, 0x09, 0xda,
+ 0x49, 0xd2, 0xc9, 0x19, 0xd6, 0x06, 0xc8, 0x07,
+ 0x7e, 0x06, 0xe0, 0x07, 0x00, 0x00, 0x60, 0x02,
+ 0xe0, 0x07, 0x04, 0x00, 0xd0, 0x07, 0xcc, 0x08,
+ 0x48, 0xdb, 0x41, 0x90, 0x50, 0xaf, 0x97, 0xcf,
+ 0x59, 0xaf, 0x97, 0xcf, 0x59, 0xaf, 0x97, 0xcf,
+ 0xf0, 0x57, 0x06, 0x00, 0x06, 0x00, 0x25, 0xc1,
+ 0xe7, 0x07, 0x70, 0x06, 0x80, 0x06, 0x41, 0x90,
+ 0x67, 0x00, 0x7e, 0x06, 0x27, 0x0c, 0x06, 0x00,
+ 0x82, 0x06, 0xe7, 0x07, 0x8c, 0x09, 0x84, 0x06,
+ 0xc8, 0x07, 0x7e, 0x06, 0x41, 0x90, 0x51, 0xaf,
+ 0x97, 0xcf, 0x07, 0x0c, 0x06, 0x00, 0xc7, 0x57,
+ 0x06, 0x00, 0x0f, 0xc1, 0xc8, 0x07, 0x70, 0x06,
+ 0x15, 0xcf, 0x00, 0x0c, 0x02, 0x00, 0x00, 0xda,
+ 0x40, 0xd1, 0x27, 0x00, 0xc2, 0x06, 0x1e, 0xcf,
+ 0x1d, 0xcf, 0x27, 0x0c, 0x02, 0x00, 0xcc, 0x06,
+ 0x19, 0xcf, 0x27, 0x02, 0x20, 0x01, 0xe7, 0x07,
+ 0x08, 0x00, 0x22, 0x01, 0xe7, 0x07, 0x13, 0x00,
+ 0xb0, 0xc0, 0x97, 0xcf, 0x41, 0x90, 0x67, 0x00,
+ 0x7e, 0x06, 0xe7, 0x01, 0x82, 0x06, 0x27, 0x02,
+ 0x80, 0x06, 0xe7, 0x07, 0x8c, 0x09, 0x84, 0x06,
+ 0xc8, 0x07, 0x7e, 0x06, 0xc1, 0x07, 0x00, 0x80,
+ 0x50, 0xaf, 0x97, 0xcf, 0x59, 0xaf, 0x97, 0xcf,
+ 0x00, 0x60, 0x05, 0xc0, 0xe7, 0x07, 0x00, 0x00,
+ 0xc4, 0x06, 0xa7, 0xcf, 0x7c, 0x06, 0x9f, 0xaf,
+ 0x00, 0x0a, 0xe7, 0x07, 0x01, 0x00, 0xc4, 0x06,
+ 0x49, 0xaf, 0xd7, 0x09, 0x00, 0xc0, 0x07, 0xaf,
+ 0xe7, 0x05, 0x00, 0xc0, 0x4a, 0xaf, 0xa7, 0xcf,
+ 0x7c, 0x06, 0xc0, 0x07, 0xfe, 0x7f, 0x44, 0xaf,
+ 0x40, 0x00, 0xc0, 0x37, 0x00, 0x01, 0x41, 0x90,
+ 0xc0, 0x37, 0x08, 0x00, 0xdf, 0xde, 0x50, 0x06,
+ 0xc0, 0x57, 0x10, 0x00, 0x02, 0xc2, 0xc0, 0x07,
+ 0x10, 0x00, 0x27, 0x00, 0x9a, 0x06, 0x41, 0x90,
+ 0x9f, 0xde, 0x40, 0x06, 0x44, 0xaf, 0x27, 0x00,
+ 0x9c, 0x06, 0xc0, 0x09, 0x9a, 0x06, 0x41, 0x90,
+ 0x00, 0xd2, 0x00, 0xd8, 0x9f, 0xde, 0x08, 0x00,
+ 0x44, 0xaf, 0x27, 0x00, 0xc8, 0x06, 0x97, 0xcf,
+ 0xe7, 0x87, 0x00, 0x84, 0x28, 0xc0, 0xe7, 0x67,
+ 0xff, 0xfb, 0x24, 0xc0, 0x97, 0xcf, 0xe7, 0x87,
+ 0x01, 0x00, 0xd2, 0x06, 0xe7, 0x57, 0x00, 0x00,
+ 0xa8, 0x06, 0x97, 0xc1, 0x9f, 0xaf, 0x00, 0x0a,
+ 0xe7, 0x87, 0x00, 0x06, 0x22, 0xc0, 0xe7, 0x07,
+ 0x00, 0x00, 0x90, 0xc0, 0xe7, 0x67, 0xfe, 0xff,
+ 0x3e, 0xc0, 0xe7, 0x07, 0x26, 0x00, 0x0a, 0xc0,
+ 0xe7, 0x87, 0x01, 0x00, 0x3e, 0xc0, 0xe7, 0x07,
+ 0xff, 0xff, 0xbe, 0x06, 0x9f, 0xaf, 0x10, 0x0b,
+ 0x97, 0xcf, 0x17, 0x00, 0xa7, 0xaf, 0x78, 0x06,
+ 0xc0, 0x05, 0x27, 0x00, 0x76, 0x06, 0xe7, 0x87,
+ 0x01, 0x00, 0xd2, 0x06, 0x9f, 0xaf, 0x00, 0x0a,
+ 0xe7, 0x07, 0x0c, 0x00, 0x40, 0xc0, 0x9f, 0xaf,
+ 0x10, 0x0b, 0x00, 0x90, 0x27, 0x00, 0xa6, 0x06,
+ 0x27, 0x00, 0xaa, 0x06, 0xe7, 0x09, 0xb2, 0x06,
+ 0xb4, 0x06, 0x27, 0x00, 0xae, 0x06, 0x27, 0x00,
+ 0xac, 0x06, 0x9f, 0xaf, 0xae, 0x0a, 0xc0, 0x07,
+ 0x00, 0x00, 0x27, 0x00, 0xb2, 0x02, 0x27, 0x00,
+ 0xb4, 0x02, 0x27, 0x00, 0x8e, 0x06, 0xc0, 0x07,
+ 0x06, 0x00, 0xc8, 0x09, 0xde, 0x00, 0xc8, 0x17,
+ 0x03, 0x00, 0xc9, 0x07, 0x70, 0x06, 0x29, 0x0a,
+ 0x00, 0xda, 0x7d, 0xc1, 0x97, 0xcf, 0xd7, 0x09,
+ 0x00, 0xc0, 0xc1, 0xdf, 0x00, 0x90, 0x27, 0x00,
+ 0x96, 0x06, 0xe7, 0x07, 0x96, 0x06, 0x98, 0x06,
+ 0x27, 0x00, 0xa0, 0x06, 0xe7, 0x07, 0xa0, 0x06,
+ 0xa2, 0x06, 0x27, 0x00, 0xa6, 0x06, 0x27, 0x00,
+ 0x90, 0x06, 0x27, 0x00, 0x9e, 0x06, 0xc8, 0x09,
+ 0x9c, 0x06, 0xc1, 0x09, 0x9a, 0x06, 0xc9, 0x07,
+ 0xa4, 0x06, 0x11, 0x02, 0x09, 0x02, 0xc8, 0x17,
+ 0x40, 0x06, 0x01, 0xda, 0x7a, 0xc1, 0x51, 0x94,
+ 0xc8, 0x09, 0xc8, 0x06, 0xc9, 0x07, 0xc6, 0x06,
+ 0xc1, 0x09, 0x9a, 0x06, 0x11, 0x02, 0x09, 0x02,
+ 0xc8, 0x17, 0x08, 0x00, 0x01, 0xda, 0x7a, 0xc1,
+ 0x51, 0x94, 0xe7, 0x05, 0x00, 0xc0, 0x97, 0xcf,
+ 0xe7, 0x57, 0x00, 0x00, 0x76, 0x06, 0x97, 0xc0,
+ 0x9f, 0xaf, 0x04, 0x00, 0xe7, 0x09, 0xbe, 0x06,
+ 0xba, 0x06, 0xe7, 0x57, 0xff, 0xff, 0xba, 0x06,
+ 0x04, 0xc1, 0xe7, 0x07, 0x10, 0x0b, 0xb8, 0x06,
+ 0x97, 0xcf, 0xe7, 0x17, 0x32, 0x00, 0xba, 0x06,
+ 0xe7, 0x67, 0xff, 0x07, 0xba, 0x06, 0xe7, 0x07,
+ 0x46, 0x0b, 0xb8, 0x06, 0x97, 0xcf, 0xe7, 0x57,
+ 0x00, 0x00, 0xc0, 0x06, 0x23, 0xc0, 0xe7, 0x07,
+ 0x04, 0x00, 0x90, 0xc0, 0xe7, 0x07, 0x00, 0x80,
+ 0x80, 0xc0, 0xe7, 0x07, 0x00, 0x00, 0x80, 0xc0,
+ 0xe7, 0x07, 0x00, 0x80, 0x80, 0xc0, 0xc0, 0x07,
+ 0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0xc0, 0x07,
+ 0x00, 0x00, 0xe7, 0x07, 0x00, 0x00, 0x80, 0xc0,
+ 0xe7, 0x07, 0x00, 0x80, 0x80, 0xc0, 0xe7, 0x07,
+ 0x00, 0x80, 0x40, 0xc0, 0xc0, 0x07, 0x00, 0x00,
+ 0xe7, 0x07, 0x00, 0x00, 0x40, 0xc0, 0xe7, 0x07,
+ 0x00, 0x00, 0x80, 0xc0, 0xe7, 0x07, 0x04, 0x00,
+ 0x90, 0xc0, 0xe7, 0x07, 0x00, 0x02, 0x40, 0xc0,
+ 0xe7, 0x07, 0x0c, 0x02, 0x40, 0xc0, 0xe7, 0x07,
+ 0x00, 0x00, 0xc0, 0x06, 0xe7, 0x07, 0x00, 0x00,
+ 0xb8, 0x06, 0xe7, 0x07, 0x00, 0x00, 0xd2, 0x06,
+ 0xd7, 0x09, 0x00, 0xc0, 0xc1, 0xdf, 0x9f, 0xaf,
+ 0x34, 0x02, 0xe7, 0x05, 0x00, 0xc0, 0x9f, 0xaf,
+ 0xc4, 0x01, 0x97, 0xcf, 0xd7, 0x09, 0x00, 0xc0,
+ 0x17, 0x00, 0x17, 0x02, 0x97, 0x02, 0xe7, 0x57,
+ 0x00, 0x00, 0xa8, 0x06, 0x06, 0xc0, 0xc0, 0x09,
+ 0x92, 0xc0, 0xc0, 0x77, 0x09, 0x02, 0x9f, 0xc1,
+ 0x5c, 0x05, 0x9f, 0xcf, 0x32, 0x06, 0xd7, 0x09,
+ 0x0e, 0xc0, 0xe7, 0x07, 0x00, 0x00, 0x0e, 0xc0,
+ 0x9f, 0xaf, 0x02, 0x0c, 0xe7, 0x05, 0x0e, 0xc0,
+ 0x97, 0xcf, 0xd7, 0x09, 0x00, 0xc0, 0x17, 0x02,
+ 0xc8, 0x09, 0xb0, 0xc0, 0xe7, 0x67, 0xfe, 0x7f,
+ 0xb0, 0xc0, 0xc8, 0x77, 0x00, 0x20, 0x9f, 0xc1,
+ 0x64, 0xeb, 0xe7, 0x57, 0x00, 0x00, 0xc8, 0x02,
+ 0x9f, 0xc1, 0x80, 0xeb, 0xc8, 0x99, 0xca, 0x02,
+ 0xc8, 0x67, 0x04, 0x00, 0x9f, 0xc1, 0x96, 0xeb,
+ 0x9f, 0xcf, 0x4c, 0xeb, 0xe7, 0x07, 0x00, 0x00,
+ 0xa6, 0xc0, 0xe7, 0x09, 0xb0, 0xc0, 0xc8, 0x02,
+ 0xe7, 0x07, 0x03, 0x00, 0xb0, 0xc0, 0x97, 0xcf,
+ 0xc0, 0x09, 0xb0, 0x06, 0xc0, 0x37, 0x01, 0x00,
+ 0x97, 0xc9, 0xc9, 0x09, 0xb2, 0x06, 0x02, 0x00,
+ 0x41, 0x90, 0x48, 0x02, 0xc9, 0x17, 0x06, 0x00,
+ 0x9f, 0xaf, 0x08, 0x04, 0x9f, 0xa2, 0x72, 0x0c,
+ 0x02, 0xda, 0x77, 0xc1, 0x41, 0x60, 0x71, 0xc1,
+ 0x97, 0xcf, 0x17, 0x02, 0x57, 0x02, 0x43, 0x04,
+ 0x21, 0x04, 0xe0, 0x00, 0x43, 0x04, 0x21, 0x04,
+ 0xe0, 0x00, 0x43, 0x04, 0x21, 0x04, 0xe0, 0x00,
+ 0xc1, 0x07, 0x01, 0x00, 0xc9, 0x05, 0xc8, 0x05,
+ 0x97, 0xcf, 0xe7, 0x07, 0x01, 0x00, 0x8e, 0x06,
+ 0xc8, 0x07, 0x86, 0x06, 0xe7, 0x07, 0x00, 0x00,
+ 0x86, 0x06, 0xe7, 0x07, 0x10, 0x08, 0x88, 0x06,
+ 0xe7, 0x07, 0x04, 0x00, 0x8a, 0x06, 0xe7, 0x07,
+ 0xbc, 0x0c, 0x8c, 0x06, 0xc1, 0x07, 0x03, 0x80,
+ 0x50, 0xaf, 0x97, 0xcf, 0xe7, 0x07, 0x00, 0x00,
+ 0x8e, 0x06, 0x97, 0xcf,
+ 0x00, 0x00
+};
+
+/****************************************************************
+ * kaweth_new_code_fix
+ ****************************************************************/
+static __u8 kaweth_new_code_fix[] =
+{
+ 0xB6, 0xC3, 0xAA, 0xBB, 0xCC, 0xDD,
+ 0x02, 0x00, 0x08, 0x00, 0x28, 0x00, 0x2c, 0x00,
+ 0x34, 0x00, 0x3c, 0x00, 0x40, 0x00, 0x48, 0x00,
+ 0x54, 0x00, 0x58, 0x00, 0x5e, 0x00, 0x64, 0x00,
+ 0x68, 0x00, 0x6e, 0x00, 0x6c, 0x00, 0x72, 0x00,
+ 0x76, 0x00, 0x7c, 0x00, 0x80, 0x00, 0x86, 0x00,
+ 0x8a, 0x00, 0x90, 0x00, 0x94, 0x00, 0x98, 0x00,
+ 0x9e, 0x00, 0xa6, 0x00, 0xaa, 0x00, 0xb0, 0x00,
+ 0xb4, 0x00, 0xb8, 0x00, 0xc0, 0x00, 0xc6, 0x00,
+ 0xca, 0x00, 0xd0, 0x00, 0xd4, 0x00, 0xd8, 0x00,
+ 0xe0, 0x00, 0xde, 0x00, 0xe8, 0x00, 0xf0, 0x00,
+ 0xfc, 0x00, 0x04, 0x01, 0x0a, 0x01, 0x18, 0x01,
+ 0x22, 0x01, 0x28, 0x01, 0x3a, 0x01, 0x3e, 0x01,
+ 0x7e, 0x01, 0x98, 0x01, 0x9c, 0x01, 0xa2, 0x01,
+ 0xac, 0x01, 0xb2, 0x01, 0xba, 0x01, 0xc0, 0x01,
+ 0xc8, 0x01, 0xd0, 0x01, 0xd6, 0x01, 0xf4, 0x01,
+ 0xfc, 0x01, 0x08, 0x02, 0x16, 0x02, 0x1a, 0x02,
+ 0x22, 0x02, 0x2a, 0x02, 0x2e, 0x02, 0x3e, 0x02,
+ 0x44, 0x02, 0x4a, 0x02, 0x50, 0x02, 0x64, 0x02,
+ 0x62, 0x02, 0x6c, 0x02, 0x72, 0x02, 0x86, 0x02,
+ 0x8c, 0x02, 0x90, 0x02, 0x9e, 0x02, 0xbc, 0x02,
+ 0xd0, 0x02, 0xd8, 0x02, 0xdc, 0x02, 0xe0, 0x02,
+ 0xe8, 0x02, 0xe6, 0x02, 0xf4, 0x02, 0xfe, 0x02,
+ 0x04, 0x03, 0x0c, 0x03, 0x28, 0x03, 0x7c, 0x03,
+ 0x90, 0x03, 0x94, 0x03, 0x9c, 0x03, 0xa2, 0x03,
+ 0xc0, 0x03, 0xd0, 0x03, 0xd4, 0x03, 0xee, 0x03,
+ 0xfa, 0x03, 0xfe, 0x03, 0x2e, 0x04, 0x32, 0x04,
+ 0x3c, 0x04, 0x40, 0x04, 0x4e, 0x04, 0x76, 0x04,
+ 0x7c, 0x04, 0x84, 0x04, 0x8a, 0x04, 0x8e, 0x04,
+ 0xa6, 0x04, 0xb0, 0x04, 0xb8, 0x04, 0xbe, 0x04,
+ 0xd2, 0x04, 0xdc, 0x04, 0xee, 0x04, 0x10, 0x05,
+ 0x1a, 0x05, 0x24, 0x05, 0x2a, 0x05, 0x36, 0x05,
+ 0x34, 0x05, 0x3c, 0x05, 0x42, 0x05, 0x64, 0x05,
+ 0x6a, 0x05, 0x6e, 0x05, 0x86, 0x05, 0x22, 0x06,
+ 0x26, 0x06, 0x2c, 0x06, 0x30, 0x06, 0x42, 0x06,
+ 0x4a, 0x06, 0x4e, 0x06, 0x56, 0x06, 0x54, 0x06,
+ 0x5a, 0x06, 0x60, 0x06, 0x66, 0x06, 0xe8, 0x06,
+ 0xee, 0x06, 0xf4, 0x06, 0x16, 0x07, 0x26, 0x07,
+ 0x2c, 0x07, 0x32, 0x07, 0x36, 0x07, 0x3a, 0x07,
+ 0x3e, 0x07, 0x52, 0x07, 0x56, 0x07, 0x5a, 0x07,
+ 0x64, 0x07, 0x76, 0x07, 0x7a, 0x07, 0x80, 0x07,
+ 0x84, 0x07, 0x8a, 0x07, 0x9e, 0x07, 0xa2, 0x07,
+ 0xda, 0x07, 0xde, 0x07, 0xe2, 0x07, 0xe6, 0x07,
+ 0xea, 0x07, 0xee, 0x07, 0xf2, 0x07, 0xf6, 0x07,
+ 0x0e, 0x08, 0x16, 0x08, 0x18, 0x08, 0x1a, 0x08,
+ 0x1c, 0x08, 0x1e, 0x08, 0x20, 0x08, 0x22, 0x08,
+ 0x24, 0x08, 0x26, 0x08, 0x28, 0x08, 0x2a, 0x08,
+ 0x2c, 0x08, 0x2e, 0x08, 0x32, 0x08, 0x3a, 0x08,
+ 0x46, 0x08, 0x4e, 0x08, 0x54, 0x08, 0x5e, 0x08,
+ 0x78, 0x08, 0x7e, 0x08, 0x82, 0x08, 0x86, 0x08,
+ 0x8c, 0x08, 0x90, 0x08, 0x98, 0x08, 0x9e, 0x08,
+ 0xa4, 0x08, 0xaa, 0x08, 0xb0, 0x08, 0xae, 0x08,
+ 0xb4, 0x08, 0xbe, 0x08, 0xc4, 0x08, 0xc2, 0x08,
+ 0xca, 0x08, 0xc8, 0x08, 0xd4, 0x08, 0xe4, 0x08,
+ 0xe8, 0x08, 0xf6, 0x08, 0x14, 0x09, 0x12, 0x09,
+ 0x1a, 0x09, 0x20, 0x09, 0x26, 0x09, 0x24, 0x09,
+ 0x2a, 0x09, 0x3e, 0x09, 0x4c, 0x09, 0x56, 0x09,
+ 0x70, 0x09, 0x74, 0x09, 0x78, 0x09, 0x7e, 0x09,
+ 0x7c, 0x09, 0x82, 0x09, 0x98, 0x09, 0x9c, 0x09,
+ 0xa0, 0x09, 0xa6, 0x09, 0xb8, 0x09, 0xdc, 0x09,
+ 0xe8, 0x09, 0xec, 0x09, 0xfc, 0x09, 0x12, 0x0a,
+ 0x18, 0x0a, 0x1e, 0x0a, 0x42, 0x0a, 0x46, 0x0a,
+ 0x4e, 0x0a, 0x54, 0x0a, 0x5a, 0x0a, 0x5e, 0x0a,
+ 0x68, 0x0a, 0x6e, 0x0a, 0x72, 0x0a, 0x78, 0x0a,
+ 0x76, 0x0a, 0x7c, 0x0a, 0x80, 0x0a, 0x84, 0x0a,
+ 0x94, 0x0a, 0xa4, 0x0a, 0xb8, 0x0a, 0xbe, 0x0a,
+ 0xbc, 0x0a, 0xc2, 0x0a, 0xc8, 0x0a, 0xc6, 0x0a,
+ 0xcc, 0x0a, 0xd0, 0x0a, 0xd4, 0x0a, 0xd8, 0x0a,
+ 0xdc, 0x0a, 0xe0, 0x0a, 0xf2, 0x0a, 0xf6, 0x0a,
+ 0xfa, 0x0a, 0x14, 0x0b, 0x1a, 0x0b, 0x20, 0x0b,
+ 0x1e, 0x0b, 0x26, 0x0b, 0x2e, 0x0b, 0x2c, 0x0b,
+ 0x36, 0x0b, 0x3c, 0x0b, 0x42, 0x0b, 0x40, 0x0b,
+ 0x4a, 0x0b, 0xaa, 0x0b, 0xb0, 0x0b, 0xb6, 0x0b,
+ 0xc0, 0x0b, 0xc8, 0x0b, 0xda, 0x0b, 0xe8, 0x0b,
+ 0xec, 0x0b, 0xfa, 0x0b, 0x4a, 0x0c, 0x54, 0x0c,
+ 0x62, 0x0c, 0x66, 0x0c, 0x96, 0x0c, 0x9a, 0x0c,
+ 0xa0, 0x0c, 0xa6, 0x0c, 0xa4, 0x0c, 0xac, 0x0c,
+ 0xb2, 0x0c, 0xb0, 0x0c, 0xc0, 0x0c,
+ 0x00, 0x00
+};
+
+
+const int len_kaweth_trigger_code = sizeof(kaweth_trigger_code);
+const int len_kaweth_trigger_code_fix = sizeof(kaweth_trigger_code_fix);
+const int len_kaweth_new_code = sizeof(kaweth_new_code);
+const int len_kaweth_new_code_fix = sizeof(kaweth_new_code_fix);
/*
* linux/drivers/video/acornfb.c
*
- * Copyright (C) 1998-2000 Russell King
+ * Copyright (C) 1998-2001 Russell King
*
* 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
#include <asm/hardware.h>
#include <asm/io.h>
#include <asm/irq.h>
+#include <asm/mach-types.h>
#include <asm/uaccess.h>
#include <video/fbcon.h>
#include "acornfb.h"
+/*
+ * VIDC machines can't do 16 or 32BPP modes.
+ */
+#ifdef HAS_VIDC
+#undef FBCON_HAS_CFB16
+#undef FBCON_HAS_CFB32
+#endif
+
/*
* Default resolution.
* NOTE that it has to be supported in the table towards
* 25.175 3 25.175
* 36.000 3 36.000
*/
-static struct pixclock {
+struct pixclock {
u_long min_clock;
u_long max_clock;
u_int vidc_ctl;
u_int vid_ctl;
-} pixclocks[] = {
+};
+
+static struct pixclock arc_clocks[] = {
/* we allow +/-1% on these */
{ 123750, 126250, VIDC_CTRL_DIV3, VID_CTL_24MHz }, /* 8.000MHz */
{ 82500, 84167, VIDC_CTRL_DIV2, VID_CTL_24MHz }, /* 12.000MHz */
{ 61875, 63125, VIDC_CTRL_DIV1_5, VID_CTL_24MHz }, /* 16.000MHz */
{ 41250, 42083, VIDC_CTRL_DIV1, VID_CTL_24MHz }, /* 24.000MHz */
+};
+
#ifdef CONFIG_ARCH_A5K
+static struct pixclock a5k_clocks[] = {
{ 117974, 120357, VIDC_CTRL_DIV3, VID_CTL_25MHz }, /* 8.392MHz */
{ 78649, 80238, VIDC_CTRL_DIV2, VID_CTL_25MHz }, /* 12.588MHz */
{ 58987, 60178, VIDC_CTRL_DIV1_5, VID_CTL_25MHz }, /* 16.588MHz */
{ 55000, 56111, VIDC_CTRL_DIV2, VID_CTL_36MHz }, /* 18.000MHz */
{ 39325, 40119, VIDC_CTRL_DIV1, VID_CTL_25MHz }, /* 25.175MHz */
{ 27500, 28055, VIDC_CTRL_DIV1, VID_CTL_36MHz }, /* 36.000MHz */
-#endif
- { 0, }
};
+#endif
static struct pixclock *
acornfb_valid_pixrate(u_long pixclock)
{
u_int i;
- for (i = 0; pixclocks[i].min_clock; i++)
- if (pixclock > pixclocks[i].min_clock &&
- pixclock < pixclocks[i].max_clock)
- return pixclocks + i;
+ for (i = 0; i < ARRAY_SIZE(arc_clocks); i++)
+ if (pixclock > arc_clocks[i].min_clock &&
+ pixclock < arc_clocks[i].max_clock)
+ return arc_clocks + i;
+
+#ifdef CONFIG_ARCH_A5K
+ if (machine_is_a5k()) {
+ for (i = 0; i < ARRAY_SIZE(a5k_clocks); i++)
+ if (pixclock > a5k_clocks[i].min_clock &&
+ pixclock < a5k_clocks[i].max_clock)
+ return a5k_clocks + i;
+ }
+#endif
return NULL;
}
break;
}
- if (!(var->sync & FB_SYNC_HOR_HIGH_ACT))
- vid_ctl |= VID_CTL_HS_NHSYNC;
+ if (var->sync & FB_SYNC_COMP_HIGH_ACT) /* should be FB_SYNC_COMP */
+ vidc_ctl |= VIDC_CTRL_CSYNC;
+ else {
+ if (!(var->sync & FB_SYNC_HOR_HIGH_ACT))
+ vid_ctl |= VID_CTL_HS_NHSYNC;
- if (!(var->sync & FB_SYNC_VERT_HIGH_ACT))
- vid_ctl |= VID_CTL_VS_NVSYNC;
+ if (!(var->sync & FB_SYNC_VERT_HIGH_ACT))
+ vid_ctl |= VID_CTL_VS_NVSYNC;
+ }
sync_len = var->hsync_len;
display_start = sync_len + var->left_margin;
vidc.v_display_end = display_end - 1;
vidc.v_border_end = vidc.v_display_end;
-#ifdef CONFIG_ARCH_A5K
- __raw_writeb(vid_ctl, IOEB_VID_CTL);
-#endif
+ if (machine_is_a5k())
+ __raw_writeb(vid_ctl, IOEB_VID_CTL);
+
if (memcmp(¤t_vidc, &vidc, sizeof(vidc))) {
current_vidc = vidc;
pal = acornfb_palette_encode(regno, red, green, blue, trans);
current_par.palette[regno] = pal;
-#ifdef HAS_VIDC20
- if (regno < 16) {
- switch (bpp) {
-#ifdef FBCON_HAS_CFB16
- case 16:
- current_par.cmap.cfb16[regno] =
- regno | regno << 5 | regno << 10;
- break;
-#endif
#ifdef FBCON_HAS_CFB32
- case 32:
- current_par.cmap.cfb32[regno] =
+ if (bpp == 32 && regno < 16) {
+ current_par.cmap.cfb32[regno] =
regno | regno << 8 | regno << 16;
- break;
-#endif
- default:
- break;
- }
}
-
+#endif
#ifdef FBCON_HAS_CFB16
- if (bpp == 16) {
+ if (bpp == 16 && regno < 16) {
int i;
+ current_par.cmap.cfb16[regno] =
+ regno | regno << 5 | regno << 10;
+
pal.p = 0;
vidc_writel(0x10000000);
for (i = 0; i < 256; i += 1) {
/* Palette register pointer auto-increments */
}
} else
-#endif
#endif
acornfb_palette_write(regno, pal);
}
static int
-acornfb_decode_var(struct fb_var_screeninfo *var, int con, int *visual)
+acornfb_decode_var(struct fb_var_screeninfo *var, int con)
{
int err;
+#if defined(HAS_VIDC20)
+ var->red.offset = 0;
+ var->red.length = 8;
+ var->green = var->red;
+ var->blue = var->red;
+ var->transp.offset = 0;
+ var->transp.length = 4;
+#elif defined(HAS_VIDC)
+ var->red.length = 4;
+ var->green = var->red;
+ var->blue = var->red;
+ var->transp.length = 1;
+#endif
+
switch (var->bits_per_pixel) {
#ifdef FBCON_HAS_MFB
case 1:
- *visual = FB_VISUAL_MONO10;
break;
#endif
-#ifdef FBCON_HAS_CFB8
- case 8:
-#ifdef HAS_VIDC
- *visual = FB_VISUAL_STATIC_PSEUDOCOLOR;
-#else
- *visual = FB_VISUAL_PSEUDOCOLOR;
-#endif
+#ifdef FBCON_HAS_CFB2
+ case 2:
break;
#endif
#ifdef FBCON_HAS_CFB4
case 4:
- *visual = FB_VISUAL_PSEUDOCOLOR;
break;
#endif
-#ifdef FBCON_HAS_CFB2
- case 2:
- *visual = FB_VISUAL_PSEUDOCOLOR;
+#ifdef FBCON_HAS_CFB8
+ case 8:
break;
#endif
-#ifdef HAS_VIDC20
#ifdef FBCON_HAS_CFB16
case 16:
- *visual = FB_VISUAL_DIRECTCOLOR;
+ var->red.offset = 0;
+ var->red.length = 5;
+ var->green.offset = 5;
+ var->green.length = 5;
+ var->blue.offset = 10;
+ var->blue.length = 5;
+ var->transp.offset = 15;
+ var->transp.length = 1;
break;
#endif
#ifdef FBCON_HAS_CFB32
case 32:
- *visual = FB_VISUAL_TRUECOLOR;
+ var->red.offset = 0;
+ var->red.length = 8;
+ var->green.offset = 8;
+ var->green.length = 8;
+ var->blue.offset = 16;
+ var->blue.length = 8;
+ var->transp.offset = 24;
+ var->transp.length = 4;
break;
-#endif
#endif
default:
return -EINVAL;
}
- if (!acornfb_valid_pixrate(var->pixclock))
+ /*
+ * Check to see if the pixel rate is valid.
+ */
+ if (!var->pixclock || !acornfb_valid_pixrate(var->pixclock))
return -EINVAL;
/*
* Validate the timing against the
* monitor hardware.
*/
- err = acornfb_validate_timing(var, &fb_info.monspecs);
- if (err)
- return err;
-
-#if defined(HAS_VIDC20)
- switch (var->bits_per_pixel) {
- case 1: case 2: case 4: case 8:
- var->red.offset = 0;
- var->red.length = 8;
- var->green = var->red;
- var->blue = var->red;
- var->transp.offset = 0;
- var->transp.length = 4;
- break;
-
- case 16:
- var->red.offset = 0;
- var->red.length = 5;
- var->green.offset = 5;
- var->green.length = 5;
- var->blue.offset = 10;
- var->blue.length = 5;
- var->transp.offset = 15;
- var->transp.length = 1;
- break;
-
- case 32:
- var->red.offset = 0;
- var->red.length = 8;
- var->green.offset = 8;
- var->green.length = 8;
- var->blue.offset = 16;
- var->blue.length = 8;
- var->transp.offset = 24;
- var->transp.length = 4;
- break;
- }
-#elif defined(HAS_VIDC)
- var->red.length = 4;
- var->green = var->red;
- var->blue = var->red;
- var->transp.length = 1;
-#endif
- return 0;
+ return acornfb_validate_timing(var, &fb_info.monspecs);
}
static int
acornfb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
{
struct display *display;
- int err, chgvar = 0, visual;
+ int err, chgvar = 0;
if (con >= 0)
display = fb_display + con;
else
display = &global_disp;
- err = acornfb_decode_var(var, con, &visual);
+ err = acornfb_decode_var(var, con);
if (err)
return err;
if (var->activate & FB_ACTIVATE_ALL)
global_disp.var = display->var;
- display->screen_base = (char *)current_par.screen_base;
- display->visual = visual;
- display->type = FB_TYPE_PACKED_PIXELS;
- display->type_aux = 0;
- display->ypanstep = 1;
- display->ywrapstep = 1;
- display->line_length =
- display->next_line = (var->xres * var->bits_per_pixel) / 8;
- display->can_soft_blank = visual == FB_VISUAL_PSEUDOCOLOR ? 1 : 0;
- display->inverse = 0;
-
switch (display->var.bits_per_pixel) {
#ifdef FBCON_HAS_MFB
case 1:
current_par.palette_size = 2;
display->dispsw = &fbcon_mfb;
+ display->visual = FB_VISUAL_MONO10;
break;
#endif
#ifdef FBCON_HAS_CFB2
case 2:
current_par.palette_size = 4;
display->dispsw = &fbcon_cfb2;
+ display->visual = FB_VISUAL_PSEUDOCOLOR;
break;
#endif
#ifdef FBCON_HAS_CFB4
case 4:
current_par.palette_size = 16;
display->dispsw = &fbcon_cfb4;
+ display->visual = FB_VISUAL_PSEUDOCOLOR;
break;
#endif
#ifdef FBCON_HAS_CFB8
case 8:
current_par.palette_size = VIDC_PALETTE_SIZE;
display->dispsw = &fbcon_cfb8;
+#ifdef HAS_VIDC
+ display->visual = FB_VISUAL_STATIC_PSEUDOCOLOR;
+#else
+ display->visual = FB_VISUAL_PSEUDOCOLOR;
+#endif
break;
#endif
#ifdef FBCON_HAS_CFB16
current_par.palette_size = 32;
display->dispsw = &fbcon_cfb16;
display->dispsw_data = current_par.cmap.cfb16;
+ display->visual = FB_VISUAL_DIRECTCOLOR;
break;
#endif
#ifdef FBCON_HAS_CFB32
current_par.palette_size = VIDC_PALETTE_SIZE;
display->dispsw = &fbcon_cfb32;
display->dispsw_data = current_par.cmap.cfb32;
+ display->visual = FB_VISUAL_TRUECOLOR;
break;
#endif
default:
break;
}
+ display->screen_base = (char *)current_par.screen_base;
+ display->type = FB_TYPE_PACKED_PIXELS;
+ display->type_aux = 0;
+ display->ypanstep = 1;
+ display->ywrapstep = 1;
+ display->line_length =
+ display->next_line = (var->xres * var->bits_per_pixel) / 8;
+ display->can_soft_blank = display->visual == FB_VISUAL_PSEUDOCOLOR ? 1 : 0;
+ display->inverse = 0;
+
if (chgvar && info && info->changevar)
info->changevar(con);
union palette p;
int i, bpp = fb_display[current_par.currcon].var.bits_per_pixel;
- if (bpp != 16) {
- for (i = 0; i < current_par.palette_size; i++) {
- if (blank)
- p = acornfb_palette_encode(i, 0, 0, 0, 0);
- else
- p = current_par.palette[i];
-
- acornfb_palette_write(i, p);
- }
- }
#ifdef FBCON_HAS_CFB16
- else {
+ if (bpp == 16) {
p.p = 0;
for (i = 0; i < 256; i++) {
}
acornfb_palette_write(i, current_par.palette[i]);
}
- }
+ } else
#endif
+ {
+ for (i = 0; i < current_par.palette_size; i++) {
+ if (blank)
+ p = acornfb_palette_encode(i, 0, 0, 0, 0);
+ else
+ p = current_par.palette[i];
+
+ acornfb_palette_write(i, p);
+ }
+ }
}
/*
#define VID_CTL_25MHz (1)
#define VID_CTL_36MHz (2)
+#define VIDC_CTRL_CSYNC (1 << 7)
#define VIDC_CTRL_INTERLACE (1 << 6)
#define VIDC_CTRL_FIFO_0_4 (0 << 4)
#define VIDC_CTRL_FIFO_1_5 (1 << 4)
*/
/*#define CFB16_IS_CFB15*/
-/*
- * This is the offset of the PCI space in physical memory
- */
-#ifdef CONFIG_FOOTBRIDGE
-#define PCI_PHYS_OFFSET 0x80000000
-#else
-#define PCI_PHYS_OFFSET 0x00000000
-#endif
-
static char *CyberRegs;
#include "cyber2000fb.h"
case 2: /* vsync off */
cyber2000_grphw(0x16, 0x04);
break;
- case 1: /* just software blanking of screen */
+ case 1: /* soft blank */
cyber2000_grphw(0x16, 0x00);
- for (i = 0; i < 256; i++) {
+ for (i = 0; i < NR_PALETTE; i++) {
cyber2000_outb(i, 0x3c8);
cyber2000_outb(0, 0x3c9);
cyber2000_outb(0, 0x3c9);
cyber2000_outb(0, 0x3c9);
}
break;
- default: /* case 0, or anything else: unblank */
+ default: /* unblank */
cyber2000_grphw(0x16, 0x00);
- for (i = 0; i < 256; i++) {
+ for (i = 0; i < NR_PALETTE; i++) {
cyber2000_outb(i, 0x3c8);
cyber2000_outb(cfb->palette[i].red, 0x3c9);
cyber2000_outb(cfb->palette[i].green, 0x3c9);
cyber2000_outb(0x01, 0x3cf);
/*
- * MCLK on the NetWinder is fixed at 75MHz
+ * MCLK on the NetWinder and the Shark is fixed at 75MHz
*/
cfb->mclk_mult = 0xdb;
cfb->mclk_div = 0x54;
}
static struct cfb_info * __devinit
-cyberpro_alloc_fb_info(struct pci_dev *dev, const struct pci_device_id *id)
+cyberpro_alloc_fb_info(struct pci_dev *dev, const struct pci_device_id *id, char *name)
{
struct cfb_info *cfb;
else
cfb->divisors[3] = 8;
- sprintf(cfb->fb.fix.id, "CyberPro%4X", id->device);
+ strcpy(cfb->fb.fix.id, name);
cfb->fb.fix.type = FB_TYPE_PACKED_PIXELS;
cfb->fb.fix.type_aux = 0;
mmio_base = pci_resource_start(dev, 0) + MMIO_OFFSET;
- cfb->fb.fix.mmio_start = mmio_base + PCI_PHYS_OFFSET;
+ cfb->fb.fix.mmio_start = mmio_base;
cfb->fb.fix.mmio_len = MMIO_SIZE;
- if (!request_mem_region(mmio_base, MMIO_SIZE, "memory mapped I/O")) {
- printk("%s: memory mapped IO in use\n", cfb->fb.fix.id);
- return -EBUSY;
- }
-
CyberRegs = ioremap(mmio_base, MMIO_SIZE);
if (!CyberRegs) {
printk("%s: unable to map memory mapped IO\n",
if (cfb && CyberRegs) {
iounmap(CyberRegs);
CyberRegs = NULL;
-
- release_mem_region(cfb->fb.fix.mmio_start - PCI_PHYS_OFFSET,
- cfb->fb.fix.mmio_len);
}
}
smem_base = pci_resource_start(dev, 0);
- cfb->fb.fix.smem_start = smem_base + PCI_PHYS_OFFSET;
+ cfb->fb.fix.smem_start = smem_base;
cfb->fb.fix.smem_len = smem_len;
- if (!request_mem_region(smem_base, smem_len, "frame buffer")) {
- printk("%s: frame buffer in use\n",
- cfb->fb.fix.id);
- return -EBUSY;
- }
-
cfb->fb.screen_base = ioremap(smem_base, smem_len);
if (!cfb->fb.screen_base) {
printk("%s: unable to map screen memory\n",
if (cfb && cfb->fb.screen_base) {
iounmap(cfb->fb.screen_base);
cfb->fb.screen_base = NULL;
-
- release_mem_region(cfb->fb.fix.smem_start - PCI_PHYS_OFFSET,
- cfb->fb.fix.smem_len);
}
}
struct cfb_info *cfb;
u_int h_sync, v_sync;
u_long smem_size;
+ char name[16];
int err;
+ sprintf(name, "CyberPro%4X", id->device);
+
err = pci_enable_device(dev);
if (err)
return err;
+ err = pci_request_regions(dev, name);
+ if (err)
+ return err;
+
err = -ENOMEM;
- cfb = cyberpro_alloc_fb_info(dev, id);
+ cfb = cyberpro_alloc_fb_info(dev, id, name);
if (!cfb)
goto failed;
cyberpro_unmap_mmio(cfb);
cyberpro_free_fb_info(cfb);
+release:
+ pci_release_regions(dev);
+
return err;
}
pci_set_drvdata(dev, NULL);
if (cfb == int_cfb_info)
int_cfb_info = NULL;
+
+ pci_release_regions(dev);
}
}
/*
- * linux/drivers/video/sa1100fb.c -- StrongARM 1100 LCD Controller Frame Buffer Device
+ * linux/drivers/video/sa1100fb.c
*
* Copyright (C) 1999 Eric A. Thomas
- *
+ * Based on acornfb.c Copyright (C) Russell King.
+ *
* 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.
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
*
- */
-
-
-/*
- * Code Status:
+ * StrongARM 1100 LCD Controller Frame Buffer Driver
+ *
+ * Please direct your questions and comments on this driver to the following
+ * email address:
+ *
+ * linux-arm-kernel@lists.arm.linux.org.uk
+ *
+ * Clean patches should be sent to the ARM Linux Patch System. Please see the
+ * following web page for more information:
+ *
+ * http://www.arm.linux.org.uk/developer/patches/info.shtml
+ *
+ * Thank you.
+ *
+ * Known problems:
+ * - With the Neponset plugged into an Assabet, LCD powerdown
+ * doesn't work (LCD stays powered up). Therefore we shouldn't
+ * blank the screen.
+ * - We don't limit the CPU clock rate nor the mode selection
+ * according to the available SDRAM bandwidth.
+ *
+ *
+ * Code Status:
* 1999/04/01:
- * Driver appears to be working for Brutus 320x200x8bpp mode. Other
- * resolutions are working, but only the 8bpp mode is supported.
- * Changes need to be made to the palette encode and decode routines
- * to support 4 and 16 bpp modes.
- * Driver is not designed to be a module. The FrameBuffer is statically
- * allocated since dynamic allocation of a 300k buffer cannot be
- * guaranteed.
- *
+ * - Driver appears to be working for Brutus 320x200x8bpp mode. Other
+ * resolutions are working, but only the 8bpp mode is supported.
+ * Changes need to be made to the palette encode and decode routines
+ * to support 4 and 16 bpp modes.
+ * Driver is not designed to be a module. The FrameBuffer is statically
+ * allocated since dynamic allocation of a 300k buffer cannot be
+ * guaranteed.
+ *
* 1999/06/17:
- * FrameBuffer memory is now allocated at run-time when the
- * driver is initialized.
+ * - FrameBuffer memory is now allocated at run-time when the
+ * driver is initialized.
+ *
+ * 2000/04/10: Nicolas Pitre <nico@cam.org>
+ * - Big cleanup for dynamic selection of machine type at run time.
+ *
+ * 2000/07/19: Jamey Hicks <jamey@crl.dec.com>
+ * - Support for Bitsy aka Compaq iPAQ H3600 added.
*
- * 2000/04/10:
- * Big cleanup for dynamic selection of machine type at run time.
- * Nicolas Pitre <nico@cam.org>
- *
- * 2000/07/19:
- * Support for Bitsy aka Compaq iPAQ H3600 added.
- * Jamey Hicks <jamey@crl.dec.com>
- *
- * 2000/08/07:
- * Resolved an issue caused by a change made to the Assabet's PLD
- * earlier this year which broke the framebuffer driver for newer
- * Phase 4 Assabets. Some other parameters were changed to optimize for
- * the Sharp display.
- * Tak-Shing Chan <tchan.rd@idthk.com>
- * Jeff Sutherland <jsutherland@accelent.com>
- *
- * 2000/08/09:
- * XP860 support added
- * Kunihiko IMAI <imai@vasara.co.jp>
+ * 2000/08/07: Tak-Shing Chan <tchan.rd@idthk.com>
+ * Jeff Sutherland <jsutherland@accelent.com>
+ * - Resolved an issue caused by a change made to the Assabet's PLD
+ * earlier this year which broke the framebuffer driver for newer
+ * Phase 4 Assabets. Some other parameters were changed to optimize
+ * for the Sharp display.
*
- * 2000/08/19:
- * Allows standard options to be passed on the kernel command line
- * for most common passive displays.
- * Mark Huang <mhuang@livetoy.com>
+ * 2000/08/09: Kunihiko IMAI <imai@vasara.co.jp>
+ * - XP860 support added
+ *
+ * 2000/08/19: Mark Huang <mhuang@livetoy.com>
+ * - Allows standard options to be passed on the kernel command line
+ * for most common passive displays.
*
* 2000/08/29:
- * s/save_flags_cli/local_irq_save/
- * remove unneeded extra save_flags_cli in
- * sa1100fb_enable_lcd_controller
+ * - s/save_flags_cli/local_irq_save/
+ * - remove unneeded extra save_flags_cli in sa1100fb_enable_lcd_controller
+ *
+ * 2000/10/10: Erik Mouw <J.A.K.Mouw@its.tudelft.nl>
+ * - Updated LART stuff. Fixed some minor bugs.
+ *
+ * 2000/10/30: Murphy Chen <murphy@mail.dialogue.com.tw>
+ * - Pangolin support added
+ *
+ * 2000/10/31: Roman Jordan <jor@hoeft-wessel.de>
+ * - Huw Webpanel support added
+ *
+ * 2000/11/23: Eric Peng <ericpeng@coventive.com>
+ * - Freebird add
+ *
+ * 2001/02/07: Jamey Hicks <jamey.hicks@compaq.com>
+ * Cliff Brake <cbrake@accelent.com>
+ * - Added PM callback
+ *
+ * 2001/05/26: <rmk@arm.linux.org.uk>
+ * - Fix 16bpp so that (a) we use the right colours rather than some
+ * totally random colour depending on what was in page 0, and (b)
+ * we don't de-reference a NULL pointer.
+ * - remove duplicated implementation of consistent_alloc()
+ * - convert dma address types to dma_addr_t
+ * - remove unused 'montype' stuff
+ * - remove redundant zero inits of init_var after the initial
+ * memzero.
+ * - remove allow_modeset (acornfb idea does not belong here)
+ *
+ * 2001/05/28: <rmk@arm.linux.org.uk>
+ * - massive cleanup - move machine dependent data into structures
+ * - I've left various #warnings in - if you see one, and know
+ * the hardware concerned, please get in contact with me.
+ *
+ * 2001/05/31: <rmk@arm.linux.org.uk>
+ * - Fix LCCR1 HSW value, fix all machine type specifications to
+ * keep values in line. (Please check your machine type specs)
+ *
+ * 2001/06/10: <rmk@arm.linux.org.uk>
+ * - Fiddle with the LCD controller from task context only; mainly
+ * so that we can run with interrupts on, and sleep.
+ * - Convert #warnings into #errors. No pain, no gain. ;)
+ *
+ * 2001/06/14: <rmk@arm.linux.org.uk>
+ * - Make the palette BPS value for 12bpp come out correctly.
+ * - Take notice of "greyscale" on any colour depth.
+ * - Make truecolor visuals use the RGB channel encoding information.
+ *
+ * 2001/07/02: <rmk@arm.linux.org.uk>
+ * - Fix colourmap problems.
+ *
+ * 2001/07/13: <abraham@2d3d.co.za>
+ * - Added support for the ICP LCD-Kit01 on LART. This LCD is
+ * manufactured by Prime View, model no V16C6448AB
+ *
+ * 2001/07/23: <rmk@arm.linux.org.uk>
+ * - Hand merge version from handhelds.org CVS tree. See patch
+ * notes for 595/1 for more information.
+ * - Drop 12bpp (it's 16bpp with different colour register mappings).
+ * - This hardware can not do direct colour. Therefore we don't
+ * support it.
+ *
+ * 2001/07/27: <rmk@arm.linux.org.uk>
+ * - Halve YRES on dual scan LCDs.
*/
#include <linux/config.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/string.h>
-#include <linux/ctype.h>
-#include <linux/mm.h>
-#include <linux/tty.h>
+#include <linux/interrupt.h>
#include <linux/slab.h>
-#include <linux/init.h>
#include <linux/fb.h>
#include <linux/delay.h>
-#include <linux/wrapper.h>
+#include <linux/pm.h>
+#include <linux/init.h>
+#include <linux/cpufreq.h>
#include <asm/hardware.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/mach-types.h>
#include <asm/uaccess.h>
-#include <asm/proc/pgtable.h>
#include <video/fbcon.h>
#include <video/fbcon-mfb.h>
#include <video/fbcon-cfb8.h>
#include <video/fbcon-cfb16.h>
+/*
+ * enable this if your panel appears to have broken
+ */
+#undef CHECK_COMPAT
/*
- * Debug macros
+ * debugging?
+ */
+#define DEBUG 0
+/*
+ * Complain if VAR is out of range.
*/
-//#define DEBUG
-#ifdef DEBUG
-# define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ## args)
+#define DEBUG_VAR 1
+
+#undef ASSABET_PAL_VIDEO
+
+#include "sa1100fb.h"
+
+void (*sa1100fb_blank_helper)(int blank);
+EXPORT_SYMBOL(sa1100fb_blank_helper);
+
+
+#ifdef CHECK_COMPAT
+static void
+sa1100fb_check_shadow(struct sa1100fb_lcd_reg *new_regs,
+ struct fb_var_screeninfo *var, u_int pcd)
+{
+ struct sa1100fb_lcd_reg shadow;
+ int different = 0;
+
+ /*
+ * These machines are good machines!
+ */
+ if (machine_is_assabet() || machine_is_bitsy())
+ return;
+
+ /*
+ * The following ones are bad, bad, bad.
+ * Please make yours good!
+ */
+ if (machine_is_pangolin()) {
+ DPRINTK("Configuring Pangolin LCD\n");
+ shadow.lccr0 =
+ LCCR0_LEN + LCCR0_Color + LCCR0_LDM +
+ LCCR0_BAM + LCCR0_ERM + LCCR0_Act +
+ LCCR0_LtlEnd + LCCR0_DMADel(0);
+ shadow.lccr1 =
+ LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(64) +
+ LCCR1_BegLnDel(160) + LCCR1_EndLnDel(24);
+ shadow.lccr2 =
+ LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(7) +
+ LCCR2_BegFrmDel(7) + LCCR2_EndFrmDel(1);
+ shadow.lccr3 =
+ LCCR3_PixClkDiv(pcd) + LCCR3_HorSnchH +
+ LCCR3_VrtSnchH + LCCR3_PixFlEdg + LCCR3_OutEnH;
+
+ DPRINTK("pcd = %x, PixCldDiv(pcd)=%x\n",
+ pcd, LCCR3_PixClkDiv(pcd));
+ }
+ if (machine_is_freebird()) {
+ DPRINTK("Configuring Freebird LCD\n");
+#if 1
+ shadow.lccr0 = 0x00000038;
+ shadow.lccr1 = 0x010108e0;
+ shadow.lccr2 = 0x0000053f;
+ shadow.lccr3 = 0x00000c20;
#else
-# define DPRINTK(fmt, args...)
+ shadow.lccr0 =
+ LCCR0_LEN + LCCR0_Color + LCCR0_Sngl +
+ LCCR0_LDM + LCCR0_BAM + LCCR0_ERM + LCCR0_Pas +
+ LCCR0_LtlEnd + LCCR0_DMADel(0);
+ /* Check ,Chester */
+ shadow.lccr1 =
+ LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(5) +
+ LCCR1_BegLnDel(61) + LCCR1_EndLnDel(9);
+ /* Check ,Chester */
+ shadow.lccr2 =
+ LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(1) +
+ LCCR2_BegFrmDel(3) + LCCR2_EndFrmDel(0);
+ /* Check ,Chester */
+ shadow.lccr3 =
+ LCCR3_OutEnH + LCCR3_PixFlEdg + LCCR3_VrtSnchH +
+ LCCR3_HorSnchH + LCCR3_ACBsCntOff +
+ LCCR3_ACBsDiv(2) + LCCR3_PixClkDiv(pcd);
#endif
+ }
+ if (machine_is_brutus()) {
+ DPRINTK("Configuring Brutus LCD\n");
+ shadow.lccr0 =
+ LCCR0_LEN + LCCR0_Color + LCCR0_Sngl + LCCR0_Pas +
+ LCCR0_LtlEnd + LCCR0_LDM + LCCR0_BAM + LCCR0_ERM +
+ LCCR0_DMADel(0);
+ shadow.lccr1 =
+ LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(3) +
+ LCCR1_BegLnDel(41) + LCCR1_EndLnDel(101);
+ shadow.lccr2 =
+ LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(1) +
+ LCCR2_BegFrmDel(0) + LCCR2_EndFrmDel(0);
+ shadow.lccr3 =
+ LCCR3_OutEnH + LCCR3_PixRsEdg + LCCR3_VrtSnchH +
+ LCCR3_HorSnchH + LCCR3_ACBsCntOff +
+ LCCR3_ACBsDiv(2) + LCCR3_PixClkDiv(44);
+ }
+ if (machine_is_huw_webpanel()) {
+ DPRINTK("Configuring HuW LCD\n");
+ shadow.lccr0 = LCCR0_LEN + LCCR0_Dual + LCCR0_LDM;
+ shadow.lccr1 = LCCR1_DisWdth(var->xres) +
+ LCCR1_HorSnchWdth(3) +
+ LCCR1_BegLnDel(41) + LCCR1_EndLnDel(101);
+ shadow.lccr2 = 239 + LCCR2_VrtSnchWdth(1);
+ shadow.lccr3 = 8 + LCCR3_OutEnH +
+ LCCR3_PixRsEdg + LCCR3_VrtSnchH +
+ LCCR3_HorSnchH + LCCR3_ACBsCntOff + LCCR3_ACBsDiv(2);
+ }
+#ifdef CONFIG_SA1100_CERF
+ if (machine_is_cerf()) {
+ DPRINTK("Configuring Cerf LCD\n");
+#if defined (CONFIG_CERF_LCD_72_A)
+ shadow.lccr0 =
+ LCCR0_LEN + LCCR0_Color + LCCR0_Dual +
+ LCCR0_LDM + LCCR0_BAM + LCCR0_ERM + LCCR0_Pas +
+ LCCR0_LtlEnd + LCCR0_DMADel(0);
+ shadow.lccr1 =
+ LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(5) +
+ LCCR1_BegLnDel(61) + LCCR1_EndLnDel(9);
+ shadow.lccr2 =
+ LCCR2_DisHght(var->yres / 2) + LCCR2_VrtSnchWdth(1) +
+ LCCR2_BegFrmDel(3) + LCCR2_EndFrmDel(0);
+ shadow.lccr3 =
+ LCCR3_OutEnH + LCCR3_PixRsEdg + LCCR3_VrtSnchH +
+ LCCR3_HorSnchH + LCCR3_ACBsCntOff +
+ LCCR3_ACBsDiv(2) + LCCR3_PixClkDiv(38);
+#elif defined (CONFIG_CERF_LCD_57_A)
+ shadow.lccr0 =
+ LCCR0_LEN + LCCR0_Color + LCCR0_Sngl +
+ LCCR0_LDM + LCCR0_BAM + LCCR0_ERM + LCCR0_Pas +
+ LCCR0_LtlEnd + LCCR0_DMADel(0);
+ shadow.lccr1 =
+ LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(5) +
+ LCCR1_BegLnDel(61) + LCCR1_EndLnDel(9);
+ shadow.lccr2 =
+ LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(1) +
+ LCCR2_BegFrmDel(3) + LCCR2_EndFrmDel(0);
+ shadow.lccr3 =
+ LCCR3_OutEnH + LCCR3_PixRsEdg + LCCR3_VrtSnchH +
+ LCCR3_HorSnchH + LCCR3_ACBsCntOff +
+ LCCR3_ACBsDiv(2) + LCCR3_PixClkDiv(38);
+#elif defined (CONFIG_CERF_LCD_38_A)
+ shadow.lccr0 =
+ LCCR0_LEN + LCCR0_Color + LCCR0_Sngl +
+ LCCR0_LDM + LCCR0_BAM + LCCR0_ERM + LCCR0_Pas +
+ LCCR0_LtlEnd + LCCR0_DMADel(0);
+ shadow.lccr1 =
+ LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(5) +
+ LCCR1_BegLnDel(61) + LCCR1_EndLnDel(9);
+ shadow.lccr2 =
+ LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(1) +
+ LCCR2_BegFrmDel(3) + LCCR2_EndFrmDel(0);
+ shadow.lccr3 =
+ LCCR3_OutEnH + LCCR3_PixRsEdg + LCCR3_VrtSnchH +
+ LCCR3_HorSnchH + LCCR3_ACBsCntOff +
+ LCCR3_ACBsDiv(2) + LCCR3_PixClkDiv(38);
+#else
+#error "Must have a CerfBoard LCD form factor selected"
+#endif
+ }
+#endif
+ if (machine_is_lart()) {
+ DPRINTK("Configuring LART LCD\n");
+#if defined LART_GREY_LCD
+ shadow.lccr0 =
+ LCCR0_LEN + LCCR0_Mono + LCCR0_Sngl + LCCR0_Pas +
+ LCCR0_LtlEnd + LCCR0_LDM + LCCR0_BAM + LCCR0_ERM +
+ LCCR0_DMADel(0);
+ shadow.lccr1 =
+ LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(1) +
+ LCCR1_BegLnDel(4) + LCCR1_EndLnDel(2);
+ shadow.lccr2 =
+ LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(1) +
+ LCCR2_BegFrmDel(0) + LCCR2_EndFrmDel(0);
+ shadow.lccr3 =
+ LCCR3_PixClkDiv(34) + LCCR3_ACBsDiv(512) +
+ LCCR3_ACBsCntOff + LCCR3_HorSnchH + LCCR3_VrtSnchH;
+#endif
+#if defined LART_COLOR_LCD
+ shadow.lccr0 =
+ LCCR0_LEN + LCCR0_Color + LCCR0_Sngl + LCCR0_Act +
+ LCCR0_LtlEnd + LCCR0_LDM + LCCR0_BAM + LCCR0_ERM +
+ LCCR0_DMADel(0);
+ shadow.lccr1 =
+ LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(2) +
+ LCCR1_BegLnDel(69) + LCCR1_EndLnDel(8);
+ shadow.lccr2 =
+ LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(3) +
+ LCCR2_BegFrmDel(14) + LCCR2_EndFrmDel(4);
+ shadow.lccr3 =
+ LCCR3_PixClkDiv(34) + LCCR3_ACBsDiv(512) +
+ LCCR3_ACBsCntOff + LCCR3_HorSnchL + LCCR3_VrtSnchL +
+ LCCR3_PixFlEdg;
+#endif
+#if defined LART_VIDEO_OUT
+ shadow.lccr0 =
+ LCCR0_LEN + LCCR0_Color + LCCR0_Sngl + LCCR0_Act +
+ LCCR0_LtlEnd + LCCR0_LDM + LCCR0_BAM + LCCR0_ERM +
+ LCCR0_DMADel(0);
+ shadow.lccr1 =
+ LCCR1_DisWdth(640) + LCCR1_HorSnchWdth(95) +
+ LCCR1_BegLnDel(40) + LCCR1_EndLnDel(24);
+ shadow.lccr2 =
+ LCCR2_DisHght(480) + LCCR2_VrtSnchWdth(2) +
+ LCCR2_BegFrmDel(32) + LCCR2_EndFrmDel(11);
+ shadow.lccr3 =
+ LCCR3_PixClkDiv(8) + LCCR3_ACBsDiv(512) +
+ LCCR3_ACBsCntOff + LCCR3_HorSnchH + LCCR3_VrtSnchH +
+ LCCR3_PixFlEdg + LCCR3_OutEnL;
+#endif
+ }
+ if (machine_is_graphicsclient()) {
+ DPRINTK("Configuring GraphicsClient LCD\n");
+ shadow.lccr0 =
+ LCCR0_LEN + LCCR0_Color + LCCR0_Sngl + LCCR0_Act;
+ shadow.lccr1 =
+ LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(9) +
+ LCCR1_EndLnDel(54) + LCCR1_BegLnDel(54);
+ shadow.lccr2 =
+ LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(9) +
+ LCCR2_EndFrmDel(32) + LCCR2_BegFrmDel(24);
+ shadow.lccr3 =
+ LCCR3_PixClkDiv(10) + LCCR3_ACBsDiv(2) +
+ LCCR3_ACBsCntOff + LCCR3_HorSnchL + LCCR3_VrtSnchL;
+ }
+ if (machine_is_omnimeter()) {
+ DPRINTK("Configuring OMNI LCD\n");
+ shadow.lccr0 = LCCR0_LEN | LCCR0_CMS | LCCR0_DPD;
+ shadow.lccr1 =
+ LCCR1_BegLnDel(10) + LCCR1_EndLnDel(10) +
+ LCCR1_HorSnchWdth(1) + LCCR1_DisWdth(var->xres);
+ shadow.lccr2 = LCCR2_DisHght(var->yres);
+ shadow.lccr3 =
+ LCCR3_ACBsDiv(0xFF) + LCCR3_PixClkDiv(44);
+//jca (GetPCD(25) << LCD3_V_PCD);
+ }
+ if (machine_is_xp860()) {
+ DPRINTK("Configuring XP860 LCD\n");
+ shadow.lccr0 =
+ LCCR0_LEN + LCCR0_Color + LCCR0_Sngl + LCCR0_Act +
+ LCCR0_LtlEnd + LCCR0_LDM + LCCR0_ERM + LCCR0_DMADel(0);
+ shadow.lccr1 =
+ LCCR1_DisWdth(var->xres) +
+ LCCR1_HorSnchWdth(var->hsync_len) +
+ LCCR1_BegLnDel(var->left_margin) +
+ LCCR1_EndLnDel(var->right_margin);
+ shadow.lccr2 =
+ LCCR2_DisHght(var->yres) +
+ LCCR2_VrtSnchWdth(var->vsync_len) +
+ LCCR2_BegFrmDel(var->upper_margin) +
+ LCCR2_EndFrmDel(var->lower_margin);
+ shadow.lccr3 =
+ LCCR3_PixClkDiv(6) + LCCR3_HorSnchL + LCCR3_VrtSnchL;
+ }
+ /*
+ * Ok, since we're calculating these values, we want to know
+ * if the calculation is correct. If you see any of these
+ * messages _PLEASE_ report the incident to me for diagnosis,
+ * including details about what was happening when the
+ * messages appeared. --rmk, 30 March 2001
+ */
+ if (shadow.lccr0 != new_regs->lccr0) {
+ printk(KERN_ERR "LCCR1 mismatch: 0x%08x != 0x%08x\n",
+ shadow.lccr1, new_regs->lccr1);
+ different = 1;
+ }
+ if (shadow.lccr1 != new_regs->lccr1) {
+ printk(KERN_ERR "LCCR1 mismatch: 0x%08x != 0x%08x\n",
+ shadow.lccr1, new_regs->lccr1);
+ different = 1;
+ }
+ if (shadow.lccr2 != new_regs->lccr2) {
+ printk(KERN_ERR "LCCR2 mismatch: 0x%08x != 0x%08x\n",
+ shadow.lccr2, new_regs->lccr2);
+ different = 1;
+ }
+ if (shadow.lccr3 != new_regs->lccr3) {
+ printk(KERN_ERR "LCCR3 mismatch: 0x%08x != 0x%08x\n",
+ shadow.lccr3, new_regs->lccr3);
+ different = 1;
+ }
+ if (different) {
+ printk(KERN_ERR "var: xres=%d hslen=%d lm=%d rm=%d\n",
+ var->xres, var->hsync_len,
+ var->left_margin, var->right_margin);
+ printk(KERN_ERR "var: yres=%d vslen=%d um=%d bm=%d\n",
+ var->yres, var->vsync_len,
+ var->upper_margin, var->lower_margin);
+
+ printk(KERN_ERR "Please report this to Russell King "
+ "<rmk@arm.linux.org.uk>\n");
+ }
-/* Memory size macros for determining required FrameBuffer size */
-#define MAX_PALETTE_NUM_ENTRIES 256
-#define MAX_PALETTE_MEM_SIZE (MAX_PALETTE_NUM_ENTRIES * 2)
-#define MAX_PIXEL_MEM_SIZE \
- ((current_par.max_xres * current_par.max_yres * current_par.max_bpp)/8)
-#define MAX_FRAMEBUFFER_MEM_SIZE \
- (MAX_PIXEL_MEM_SIZE + MAX_PALETTE_MEM_SIZE + 32)
-#define ALLOCATED_FB_MEM_SIZE \
- (PAGE_ALIGN(MAX_FRAMEBUFFER_MEM_SIZE + PAGE_SIZE * 2))
+ DPRINTK("olccr0 = 0x%08x\n", shadow.lccr0);
+ DPRINTK("olccr1 = 0x%08x\n", shadow.lccr1);
+ DPRINTK("olccr2 = 0x%08x\n", shadow.lccr2);
+ DPRINTK("olccr3 = 0x%08x\n", shadow.lccr3);
+}
+#else
+#define sa1100fb_check_shadow(regs,var,pcd)
+#endif
-#define SA1100_PALETTE_MEM_SIZE(bpp) (((bpp)==8?256:16)*2)
-#define SA1100_PALETTE_MODE_VAL(bpp) (((bpp) & 0x018) << 9)
-/* Minimum X and Y resolutions */
-#define MIN_XRES 64
-#define MIN_YRES 64
-/* Possible controller_state modes */
-#define LCD_MODE_DISABLED 0 // Controller is disabled and Disable Done received
-#define LCD_MODE_DISABLE_BEFORE_ENABLE 1 // Re-enable after Disable Done IRQ is received
-#define LCD_MODE_ENABLED 2 // Controller is enabled
+/*
+ * IMHO this looks wrong. In 8BPP, length should be 8.
+ */
+static struct sa1100fb_rgb rgb_8 = {
+ red: { offset: 0, length: 4, },
+ green: { offset: 0, length: 4, },
+ blue: { offset: 0, length: 4, },
+ transp: { offset: 0, length: 0, },
+};
-#define SA1100_NAME "SA1100"
-#define NR_MONTYPES 1
+static struct sa1100fb_rgb def_rgb_16 = {
+ red: { offset: 11, length: 5, },
+ green: { offset: 5, length: 6, },
+ blue: { offset: 0, length: 5, },
+ transp: { offset: 0, length: 0, },
+};
-static inline void
-sa1100fb_assabet_set_truecolor(u_int is_true_color)
-{
#ifdef CONFIG_SA1100_ASSABET
-#if 1
- // phase 4 or newer Assabet's
- if (is_true_color)
- BCR_set(BCR_LCD_12RGB);
- else
- BCR_clear(BCR_LCD_12RGB);
+static struct sa1100fb_mach_info assabet_info __initdata = {
+#ifdef ASSABET_PAL_VIDEO
+ pixclock: 67797, bpp: 16,
+ xres: 640, yres: 512,
+
+ hsync_len: 64, vsync_len: 6,
+ left_margin: 125, upper_margin: 70,
+ right_margin: 115, lower_margin: 36,
+
+ sync: 0,
+
+ lccr0: LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
+ lccr3: LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(512),
#else
- // older Assabet's
- if (is_true_color)
- BCR_clear(BCR_LCD_12RGB);
- else
- BCR_set(BCR_LCD_12RGB);
+ pixclock: 171521, bpp: 16,
+ xres: 320, yres: 240,
+
+ hsync_len: 5, vsync_len: 1,
+ left_margin: 61, upper_margin: 3,
+ right_margin: 9, lower_margin: 0,
+
+ sync: FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+
+ lccr0: LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
+ lccr3: LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
#endif
+};
#endif
-}
-static u_char *VideoMemRegion;
-static u_char *VideoMemRegion_phys;
-
-/* Local LCD controller parameters */
-/* These can be reduced by making better use of fb_var_screeninfo parameters. */
-/* Several duplicates exist in the two structures. */
-struct sa1100fb_par {
- u_char *p_screen_base;
- u_char *v_screen_base;
- u_short *p_palette_base;
- u_short *v_palette_base;
- unsigned long screen_size;
- unsigned int palette_size;
- unsigned int max_xres;
- unsigned int max_yres;
- unsigned int xres;
- unsigned int yres;
- unsigned int xres_virtual;
- unsigned int yres_virtual;
- unsigned int max_bpp;
- unsigned int bits_per_pixel;
- signed int montype;
- unsigned int currcon;
- unsigned int visual;
- unsigned int allow_modeset : 1;
- unsigned int active_lcd : 1;
- unsigned int inv_4bpp : 1;
- volatile u_char controller_state;
+#ifdef CONFIG_SA1100_BITSY
+static struct sa1100fb_mach_info bitsy_info __initdata = {
+#ifdef CONFIG_IPAQ_H3100
+ pixclock: 0, bpp: 4,
+ xres: 320, yres: 240,
+
+ hsync_len: 26, vsync_len: 41,
+ left_margin: 4, upper_margin: 0,
+ right_margin: 4, lower_margin: 0,
+
+ sync: FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ cmap_greyscale: 1, cmap_static: 1,
+ cmap_inverse: 1,
+
+ lccr0: LCCR0_Mono | LCCR0_4PixMono | LCCR0_Sngl | LCCR0_Pas,
+ lccr3: LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
+#error FIXME
+ /*
+ * Sorry, this should have read:
+ * FIXME: please get rid of the PCD and PixClkDiv definitions
+ * in favour of pixclock. --rmk
+ */
+#else
+ pixclock: 5722222, bpp: 16,
+ xres: 320, yres: 240,
+
+ hsync_len: 3, vsync_len: 3,
+ left_margin: 12, upper_margin: 10,
+ right_margin: 17, lower_margin: 1,
+
+ sync: 0,
+
+ lccr0: LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
+ lccr3: LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2),
+#endif
};
-/* Shadows for LCD controller registers */
-struct sa1100fb_lcd_reg {
- Address dbar1;
- Address dbar2;
- Word lccr0;
- Word lccr1;
- Word lccr2;
- Word lccr3;
+static struct sa1100fb_rgb bitsy_rgb_16 = {
+ red: { offset: 12, length: 4, },
+ green: { offset: 7, length: 4, },
+ blue: { offset: 1, length: 4, },
+ transp: { offset: 0, length: 0, },
};
+#endif
-/* Fake monspecs to fill in fbinfo structure */
-static struct fb_monspecs monspecs __initdata = {
- 30000, 70000, 50, 65, 0 /* Generic */
+#ifdef CONFIG_SA1100_BRUTUS
+static struct sa1100fb_mach_info brutus_info __initdata = {
+ pixclock: 0, bpp: 8,
+ xres: 320, yres: 240,
+
+ hsync_len: 3, vsync_len: 1,
+ left_margin: 41, upper_margin: 0,
+ right_margin: 101, lower_margin: 0,
+
+ sync: FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+
+ lccr0: LCCR0_Color | LCCR0_Sngl | LCCR0_Pas,
+ lccr3: LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2) |
+ LCCR3_PixClkDiv(44),
};
+#endif
-static struct display global_disp; /* Initial (default) Display Settings */
-static struct fb_info fb_info;
-static struct sa1100fb_par current_par;
-static struct fb_var_screeninfo __initdata init_var = {};
-static struct sa1100fb_lcd_reg lcd_shadow;
-
-
-static int sa1100fb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info);
-static int sa1100fb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info);
-static int sa1100fb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info);
-static int sa1100fb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info);
-static int sa1100fb_set_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info);
-
-static int sa1100fb_switch(int con, struct fb_info *info);
-static void sa1100fb_blank(int blank, struct fb_info *info);
-static int sa1100fb_map_video_memory(void);
-static int sa1100fb_activate_var(struct fb_var_screeninfo *var);
-static void sa1100fb_enable_lcd_controller(void);
-static void sa1100fb_disable_lcd_controller(void);
+#ifdef CONFIG_SA1100_CERF
+static struct sa1100fb_mach_info cerf_info __initdata = {
+ pixclock: 171521, bpp: 8,
+#if defined(CONFIG_CERF_LCD_72_A)
+ xres: 640, yres: 480,
+ lccr0: LCCR0_Color | LCCR0_Dual | LCCR0_Pas,
+ lccr3: LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2) |
+ LCCR3_PixClkDiv(38),
+#elif defined(CONFIG_CERF_LCD_57_A)
+ xres: 320, yres: 240,
+ lccr0: LCCR0_Color | LCCR0_Sngl | LCCR0_Pas,
+ lccr3: LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2) |
+ LCCR3_PixClkDiv(38),
+#elif defined(CONFIG_CERF_LCD_38_A)
+ xres: 240, yres: 320,
+ lccr0: LCCR0_Color | LCCR0_Sngl | LCCR0_Pas,
+ lccr3: LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2) |
+ LCCR3_PixClkDiv(38),
+#else
+#error "Must have a CerfBoard LCD form factor selected"
+#endif
+
+ hsync_len: 5, vsync_len: 1,
+ left_margin: 61, upper_margin: 3,
+ right_margin: 9, lower_margin: 0,
+
+ sync: FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
-static struct fb_ops sa1100fb_ops = {
- owner: THIS_MODULE,
- fb_get_fix: sa1100fb_get_fix,
- fb_get_var: sa1100fb_get_var,
- fb_set_var: sa1100fb_set_var,
- fb_get_cmap: sa1100fb_get_cmap,
- fb_set_cmap: sa1100fb_set_cmap,
};
+#endif
+#ifdef CONFIG_SA1100_FREEBIRD
+#warning Please check this carefully
+static struct sa1100fb_mach_info freebird_info __initdata = {
+ pixclock: 171521, bpp: 16,
+ xres: 240, yres: 320,
-/*
- * sa1100fb_palette_write:
- * Write palette data to the LCD frame buffer's palette area
- */
-static inline void
-sa1100fb_palette_write(u_int regno, u_short pal)
+ hsync_len: 3, vsync_len: 2,
+ left_margin: 2, upper_margin: 0,
+ right_margin: 2, lower_margin: 0,
+
+ sync: FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+
+ lccr0: LCCR0_Color | LCCR0_Sngl | LCCR0_Pas,
+ lccr3: LCCR3_OutEnH | LCCR3_PixFlEdg | LCCR3_ACBsDiv(2),
+};
+
+static struct sa1100fb_rgb freebird_rgb_16 = {
+ red: { offset: 8, length: 4, },
+ green: { offset: 4, length: 4, },
+ blue: { offset: 0, length: 4, },
+ transp: { offset: 12, length: 4, },
+};
+#endif
+
+#ifdef CONFIG_SA1100_GRAPHICSCLIENT
+static struct sa1100fb_mach_info graphicsclient_info __initdata = {
+ pixclock: 0, bpp: 8,
+ xres: 640, yres: 480,
+
+ hsync_len: 9, vsync_len: 9,
+ left_margin: 54, upper_margin: 24,
+ right_margin: 54, lower_margin: 32,
+
+ sync: 0,
+
+ lccr0: LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
+ lccr3: LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2) |
+ LCCR3_PixClkDiv(10),
+};
+#endif
+
+#ifdef CONFIG_SA1100_HUW_WEBPANEL
+static struct sa1100fb_mach_info huw_webpanel_info __initdata = {
+ pixclock: 0, bpp: 8,
+ xres: 640, yres: 480,
+
+ hsync_len: 3, vsync_len: 1,
+ left_margin: 41, upper_margin: 0,
+ right_margin: 101, lower_margin: 0,
+
+ sync: FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+
+ lccr0: LCCR0_Color | LCCR0_Dual | LCCR0_Pas,
+ lccr3: LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2) | 8,
+#error FIXME
+ /*
+ * FIXME: please get rid of the '| 8' in preference to an
+ * LCCR3_PixClkDiv() version. --rmk
+ */
+};
+#endif
+
+#ifdef LART_GREY_LCD
+static struct sa1100fb_mach_info lart_grey_info __initdata = {
+ pixclock: 150000, bpp: 4,
+ xres: 320, yres: 240,
+
+ hsync_len: 1, vsync_len: 1,
+ left_margin: 4, upper_margin: 0,
+ right_margin: 2, lower_margin: 0,
+
+ cmap_greyscale: 1,
+ sync: FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+
+ lccr0: LCCR0_Mono | LCCR0_Sngl | LCCR0_Pas | LCCR0_4PixMono,
+ lccr3: LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(512),
+};
+#endif
+#ifdef LART_COLOR_LCD
+static struct sa1100fb_mach_info lart_color_info __initdata = {
+ pixclock: 150000, bpp: 16,
+ xres: 320, yres: 240,
+
+ hsync_len: 2, vsync_len: 3,
+ left_margin: 69, upper_margin: 14,
+ right_margin: 8, lower_margin: 4,
+
+ sync: 0,
+
+ lccr0: LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
+ lccr3: LCCR3_OutEnH | LCCR3_PixFlEdg | LCCR3_ACBsDiv(512),
+};
+#endif
+#ifdef LART_VIDEO_OUT
+static struct sa1100fb_mach_info lart_video_info __initdata = {
+ pixclock: 39721, bpp: 16,
+ xres: 640, yres: 480,
+
+ hsync_len: 95, vsync_len: 2,
+ left_margin: 40, upper_margin: 32,
+ right_margin: 24, lower_margin: 11,
+
+ sync: FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+
+ lccr0: LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
+ lccr3: LCCR3_OutEnL | LCCR3_PixFlEdg | LCCR3_ACBsDiv(512),
+};
+#endif
+
+#ifdef LART_KIT01_LCD
+static struct sa1100fb_mach_info lart_kit01_info __initdata =
{
- current_par.v_palette_base[regno] = (regno ? pal : pal |
- SA1100_PALETTE_MODE_VAL(current_par.bits_per_pixel));
-}
+ pixclock: 63291, bpp: 16,
+ xres: 640, yres: 480,
+
+ hsync_len: 64, vsync_len: 3,
+ left_margin: 122, upper_margin: 45,
+ right_margin: 10, lower_margin: 10,
+
+ sync: 0,
+
+ lccr0: LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
+ lccr3: LCCR3_OutEnH | LCCR3_PixFlEdg
+};
+#endif
+
+#ifdef CONFIG_SA1100_OMNIMETER
+static struct sa1100fb_mach_info omnimeter_info __initdata = {
+ pixclock: 0, bpp: 4,
+ xres: 480, yres: 320,
+
+ hsync_len: 1, vsync_len: 1,
+ left_margin: 10, upper_margin: 0,
+ right_margin: 10, lower_margin: 0,
+
+ cmap_greyscale: 1,
+ sync: FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+
+ lccr0: LCCR0_Mono | LCCR0_Sngl | LCCR0_Pas | LCCR0_8PixMono,
+ lccr3: LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(255) |
+ LCCR3_PixClkDiv(44),
+#error FIXME: fix pixclock, ACBsDiv
+ /*
+ * FIXME: I think ACBsDiv is wrong above - should it be 512 (disabled)?
+ * - rmk
+ */
+};
+#endif
+
+#ifdef CONFIG_SA1100_PANGOLIN
+static struct sa1100fb_mach_info pangolin_info __initdata = {
+ pixclock: 341521, bpp: 16,
+ xres: 800, yres: 600,
+
+ hsync_len: 64, vsync_len: 7,
+ left_margin: 160, upper_margin: 7,
+ right_margin: 24, lower_margin: 1,
+
+ sync: FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+
+ lccr0: LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
+ lccr3: LCCR3_OutEnH | LCCR3_PixFlEdg,
+};
+#endif
+
+#ifdef CONFIG_SA1100_XP860
+static struct sa1100fb_mach_info xp860_info __initdata = {
+ pixclock: 0, bpp: 8,
+ xres: 1024, yres: 768,
+
+ hsync_len: 3, vsync_len: 3,
+ left_margin: 3, upper_margin: 2,
+ right_margin: 2, lower_margin: 1,
+
+ sync: 0,
+ lccr0: LCCR0_Color | LCCR0_Sngl | LCCR0_Act,
+ lccr3: LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_PixClkDiv(6),
+};
+#endif
-static inline u_short
-sa1100fb_palette_encode(u_int regno, u_int red, u_int green, u_int blue, u_int trans)
+static struct sa1100fb_mach_info * __init
+sa1100fb_get_machine_info(struct sa1100fb_info *fbi)
{
- u_int pal;
+ struct sa1100fb_mach_info *inf = NULL;
- if(current_par.bits_per_pixel == 4){
- /*
- * RGB -> luminance is defined to be
- * Y = 0.299 * R + 0.587 * G + 0.114 * B
- */
- pal = (19595 * red + 38470 * green + 7471 * blue) >> 28;
- if( current_par.inv_4bpp )
- pal = 15 - pal;
+ /*
+ * R G B T
+ * default {11,5}, { 5,6}, { 0,5}, { 0,0}
+ * bitsy {12,4}, { 7,4}, { 1,4}, { 0,0}
+ * freebird { 8,4}, { 4,4}, { 0,4}, {12,4}
+ */
+#ifdef CONFIG_SA1100_ASSABET
+ if (machine_is_assabet()) {
+ inf = &assabet_info;
+ }
+#endif
+#ifdef CONFIG_SA1100_BITSY
+ if (machine_is_bitsy()) {
+ inf = &bitsy_info;
+ fbi->rgb[RGB_16] = &bitsy_rgb_16;
+ }
+#endif
+#ifdef CONFIG_SA1100_BRUTUS
+ if (machine_is_brutus()) {
+ inf = &brutus_info;
+ }
+#endif
+#ifdef CONFIG_SA1100_CERF
+ if (machine_is_cerf()) {
+ inf = &cerf_info;
+ }
+#endif
+#ifdef CONFIG_SA1100_FREEBIRD
+ if (machine_is_freebird()) {
+ inf = &freebird_info;
+ fbi->rgb[RGB_16] = &freebird_rgb16;
+ }
+#endif
+#ifdef CONFIG_SA1100_GRAPHICSCLIENT
+ if (machine_is_graphicsclient()) {
+ inf = &graphicsclient_info;
+ }
+#endif
+#ifdef CONFIG_SA1100_HUW_WEBPANEL
+ if (machine_is_huw_webpanel()) {
+ inf = &huw_webpanel_info;
+ }
+#endif
+#ifdef CONFIG_SA1100_LART
+ if (machine_is_lart()) {
+#ifdef LART_GREY_LCD
+ inf = &lart_grey_info;
+#endif
+#ifdef LART_COLOR_LCD
+ inf = &lart_color_info;
+#endif
+#ifdef LART_VIDEO_OUT
+ inf = &lart_video_info;
+#endif
+#ifdef LART_KIT01_LCD
+ inf = &lart_kit01_info;
+#endif
+ }
+#endif
+#ifdef CONFIG_SA1100_OMNIMETER
+ if (machine_is_omnimeter()) {
+ inf = &omnimeter_info;
+ }
+#endif
+#ifdef CONFIG_SA1100_PANGOLIN
+ if (machine_is_pangolin()) {
+ inf = &pangolin_info;
}
- else{
- pal = ((red >> 4) & 0xf00);
- pal |= ((green >> 8) & 0x0f0);
- pal |= ((blue >> 12) & 0x00f);
+#endif
+#ifdef CONFIG_SA1100_XP860
+ if (machine_is_xp860()) {
+ inf = &xp860_info;
}
+#endif
+ return inf;
+}
+
+static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_info *);
+static void set_ctrlr_state(struct sa1100fb_info *fbi, u_int state);
- return pal;
+static inline void sa1100fb_schedule_task(struct sa1100fb_info *fbi, u_int state)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+ /*
+ * We need to handle two requests being made at the same time.
+ * There are two important cases:
+ * 1. When we are changing VT (C_REENABLE) while unblanking (C_ENABLE)
+ * We must perform the unblanking, which will do our REENABLE for us.
+ * 2. When we are blanking, but immediately unblank before we have
+ * blanked. We do the "REENABLE" thing here as well, just to be sure.
+ */
+ if (fbi->task_state == C_ENABLE && state == C_REENABLE)
+ state = (u_int) -1;
+ if (fbi->task_state == C_DISABLE && state == C_ENABLE)
+ state = C_REENABLE;
+
+ if (state != (u_int)-1) {
+ fbi->task_state = state;
+ schedule_task(&fbi->task);
+ }
+ local_irq_restore(flags);
}
-
-static inline u_short
-sa1100fb_palette_read(u_int regno)
+
+/*
+ * Get the VAR structure pointer for the specified console
+ */
+static inline struct fb_var_screeninfo *get_con_var(struct fb_info *info, int con)
{
- return (current_par.v_palette_base[regno] & 0x0FFF);
+ struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
+ return (con == fbi->currcon || con == -1) ? &fbi->fb.var : &fb_display[con].var;
}
+/*
+ * Get the DISPLAY structure pointer for the specified console
+ */
+static inline struct display *get_con_display(struct fb_info *info, int con)
+{
+ struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
+ return (con < 0) ? fbi->fb.disp : &fb_display[con];
+}
-static void
-sa1100fb_palette_decode(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *trans)
+/*
+ * Get the CMAP pointer for the specified console
+ */
+static inline struct fb_cmap *get_con_cmap(struct fb_info *info, int con)
+{
+ struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
+ return (con == fbi->currcon || con == -1) ? &fbi->fb.cmap : &fb_display[con].cmap;
+}
+
+static inline u_int
+chan_to_field(u_int chan, struct fb_bitfield *bf)
+{
+ chan &= 0xffff;
+ chan >>= 16 - bf->length;
+ return chan << bf->offset;
+}
+
+/*
+ * Convert bits-per-pixel to a hardware palette PBS value.
+ */
+static inline u_int
+palette_pbs(struct fb_var_screeninfo *var)
+{
+ int ret = 0;
+ switch (var->bits_per_pixel) {
+#ifdef FBCON_HAS_CFB4
+ case 4: ret = 0 << 12; break;
+#endif
+#ifdef FBCON_HAS_CFB8
+ case 8: ret = 1 << 12; break;
+#endif
+#ifdef FBCON_HAS_CFB16
+ case 16: ret = 2 << 12; break;
+#endif
+ }
+ return ret;
+}
+
+static int
+sa1100fb_setpalettereg(u_int regno, u_int red, u_int green, u_int blue,
+ u_int trans, struct fb_info *info)
{
- u_short pal;
+ struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
+ u_int val, ret = 1;
- pal = sa1100fb_palette_read(regno);
+ if (regno < fbi->palette_size) {
+ val = ((red >> 4) & 0xf00);
+ val |= ((green >> 8) & 0x0f0);
+ val |= ((blue >> 12) & 0x00f);
- if( current_par.bits_per_pixel == 4){
- if( current_par.inv_4bpp )
- pal = 15 - pal;
- pal &= 0x000f;
- pal |= pal << 4;
- pal |= pal << 8;
- *blue = *green = *red = pal;
+ if (regno == 0)
+ val |= palette_pbs(&fbi->fb.var);
+
+ fbi->palette_cpu[regno] = val;
+ ret = 0;
+ }
+ return ret;
+}
+
+static int
+sa1100fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+ u_int trans, struct fb_info *info)
+{
+ struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
+ struct display *disp = get_con_display(info, fbi->currcon);
+ u_int val;
+ int ret = 1;
+
+ /*
+ * If inverse mode was selected, invert all the colours
+ * rather than the register number. The register number
+ * is what you poke into the framebuffer to produce the
+ * colour you requested.
+ */
+ if (disp->inverse) {
+ red = 0xffff - red;
+ green = 0xffff - green;
+ blue = 0xffff - blue;
}
- else{
- *blue = (pal & 0x000f) << 12;
- *green = (pal & 0x00f0) << 8;
- *red = (pal & 0x0f00) << 4;
+
+ /*
+ * If greyscale is true, then we convert the RGB value
+ * to greyscale no mater what visual we are using.
+ */
+ if (fbi->fb.var.grayscale)
+ red = green = blue = (19595 * red + 38470 * green +
+ 7471 * blue) >> 16;
+
+ switch (fbi->fb.disp->visual) {
+ case FB_VISUAL_TRUECOLOR:
+ /*
+ * 12 or 16-bit True Colour. We encode the RGB value
+ * according to the RGB bitfield information.
+ */
+ if (regno < 16) {
+ u16 *pal = fbi->fb.pseudo_palette;
+
+ val = chan_to_field(red, &fbi->fb.var.red);
+ val |= chan_to_field(green, &fbi->fb.var.green);
+ val |= chan_to_field(blue, &fbi->fb.var.blue);
+
+ pal[regno] = val;
+ ret = 0;
+ }
+ break;
+
+ case FB_VISUAL_STATIC_PSEUDOCOLOR:
+ case FB_VISUAL_PSEUDOCOLOR:
+ ret = sa1100fb_setpalettereg(regno, red, green, blue, trans, info);
+ break;
}
- *trans = 0;
+
+ return ret;
}
+/*
+ * sa1100fb_display_dma_period()
+ * Calculate the minimum period (in picoseconds) between two DMA
+ * requests for the LCD controller.
+ */
+static unsigned int
+sa1100fb_display_dma_period(struct fb_var_screeninfo *var)
+{
+ unsigned int mem_bits_per_pixel;
+
+ mem_bits_per_pixel = var->bits_per_pixel;
+ if (mem_bits_per_pixel == 12)
+ mem_bits_per_pixel = 16;
+
+ /*
+ * Period = pixclock * bits_per_byte * bytes_per_transfer
+ * / memory_bits_per_pixel;
+ */
+ return var->pixclock * 8 * 16 / mem_bits_per_pixel;
+}
+
+/*
+ * sa1100fb_decode_var():
+ * Get the video params out of 'var'. If a value doesn't fit, round it up,
+ * if it's too big, return -EINVAL.
+ *
+ * Suggestion: Round up in the following order: bits_per_pixel, xres,
+ * yres, xres_virtual, yres_virtual, xoffset, yoffset, grayscale,
+ * bitfields, horizontal timing, vertical timing.
+ */
static int
-sa1100fb_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue, u_int *trans, struct fb_info *info)
+sa1100fb_validate_var(struct fb_var_screeninfo *var,
+ struct sa1100fb_info *fbi)
{
- if (regno >= current_par.palette_size)
- return 1;
-
- sa1100fb_palette_decode(regno, red, green, blue, trans);
+ int ret = -EINVAL;
+
+ if (var->xres < MIN_XRES)
+ var->xres = MIN_XRES;
+ if (var->yres < MIN_YRES)
+ var->yres = MIN_YRES;
+ if (var->xres > fbi->max_xres)
+ var->xres = fbi->max_xres;
+ if (var->yres > fbi->max_yres)
+ var->yres = fbi->max_yres;
+ var->xres_virtual =
+ var->xres_virtual < var->xres ? var->xres : var->xres_virtual;
+ var->yres_virtual =
+ var->yres_virtual < var->yres ? var->yres : var->yres_virtual;
+
+ DPRINTK("var->bits_per_pixel=%d\n", var->bits_per_pixel);
+ switch (var->bits_per_pixel) {
+#ifdef FBCON_HAS_CFB4
+ case 4: ret = 0; break;
+#endif
+#ifdef FBCON_HAS_CFB8
+ case 8: ret = 0; break;
+#endif
+#ifdef FBCON_HAS_CFB16
+ case 16: ret = 0; break;
+#endif
+ default:
+ break;
+ }
- return 0;
+ printk(KERN_DEBUG "dma period = %d ps, clock = %d kHz",
+ sa1100fb_display_dma_period(var),
+ cpufreq_get(smp_processor_id()));
+
+ return ret;
}
+static inline void sa1100fb_set_truecolor(u_int is_true_color)
+{
+ DPRINTK("true_color = %d\n", is_true_color);
+#ifdef CONFIG_SA1100_ASSABET
+ if (machine_is_assabet()) {
+#if 1
+ // phase 4 or newer Assabet's
+ if (is_true_color)
+ BCR_set(BCR_LCD_12RGB);
+ else
+ BCR_clear(BCR_LCD_12RGB);
+#else
+ // older Assabet's
+ if (is_true_color)
+ BCR_clear(BCR_LCD_12RGB);
+ else
+ BCR_set(BCR_LCD_12RGB);
+#endif
+ }
+#endif
+}
+
+static void
+sa1100fb_hw_set_var(struct fb_var_screeninfo *var, struct sa1100fb_info *fbi)
+{
+ u_long palette_mem_size;
+
+ fbi->palette_size = var->bits_per_pixel == 8 ? 256 : 16;
+
+ palette_mem_size = fbi->palette_size * sizeof(u16);
+
+ DPRINTK("palette_mem_size = 0x%08lx\n", (u_long) palette_mem_size);
+
+ fbi->palette_cpu = (u16 *)(fbi->map_cpu + PAGE_SIZE - palette_mem_size);
+ fbi->palette_dma = fbi->map_dma + PAGE_SIZE - palette_mem_size;
+
+ fb_set_cmap(&fbi->fb.cmap, 1, sa1100fb_setcolreg, &fbi->fb);
+ /* Set board control register to handle new color depth */
+ sa1100fb_set_truecolor(var->bits_per_pixel >= 16);
+
+#ifdef CONFIG_SA1100_OMNIMETER
+#error Do we have to do this here? We already do it at init time.
+ if (machine_is_omnimeter())
+ SetLCDContrast(DefaultLCDContrast);
+#endif
+
+ sa1100fb_activate_var(var, fbi);
+
+ fbi->palette_cpu[0] = (fbi->palette_cpu[0] &
+ 0xcfff) | palette_pbs(var);
+
+}
+
+/*
+ * sa1100fb_set_var():
+ * Set the user defined part of the display for the specified console
+ */
static int
-sa1100fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, u_int trans, struct fb_info *info)
+sa1100fb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
{
- u_short pal;
+ struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
+ struct fb_var_screeninfo *dvar = get_con_var(&fbi->fb, con);
+ struct display *display = get_con_display(&fbi->fb, con);
+ int err, chgvar = 0, rgbidx;
+
+ DPRINTK("set_var\n");
+
+ /*
+ * Decode var contents into a par structure, adjusting any
+ * out of range values.
+ */
+ err = sa1100fb_validate_var(var, fbi);
+ if (err)
+ return err;
- if (regno >= current_par.palette_size)
- return 1;
+ if (var->activate & FB_ACTIVATE_TEST)
+ return 0;
- pal = sa1100fb_palette_encode(regno, red, green, blue, trans);
+ if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW)
+ return -EINVAL;
- sa1100fb_palette_write(regno, pal);
+ if (dvar->xres != var->xres)
+ chgvar = 1;
+ if (dvar->yres != var->yres)
+ chgvar = 1;
+ if (dvar->xres_virtual != var->xres_virtual)
+ chgvar = 1;
+ if (dvar->yres_virtual != var->yres_virtual)
+ chgvar = 1;
+ if (dvar->bits_per_pixel != var->bits_per_pixel)
+ chgvar = 1;
+ if (con < 0)
+ chgvar = 0;
+
+ switch (var->bits_per_pixel) {
+#ifdef FBCON_HAS_CFB4
+ case 4:
+ if (fbi->cmap_static)
+ display->visual = FB_VISUAL_STATIC_PSEUDOCOLOR;
+ else
+ display->visual = FB_VISUAL_PSEUDOCOLOR;
+ display->line_length = var->xres / 2;
+ display->dispsw = &fbcon_cfb4;
+ rgbidx = RGB_8;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB8
+ case 8:
+ if (fbi->cmap_static)
+ display->visual = FB_VISUAL_STATIC_PSEUDOCOLOR;
+ else
+ display->visual = FB_VISUAL_PSEUDOCOLOR;
+ display->line_length = var->xres;
+ display->dispsw = &fbcon_cfb8;
+ rgbidx = RGB_8;
+ break;
+#endif
+#ifdef FBCON_HAS_CFB16
+ case 16:
+ display->visual = FB_VISUAL_TRUECOLOR;
+ display->line_length = var->xres * 2;
+ display->dispsw = &fbcon_cfb16;
+ display->dispsw_data = fbi->fb.pseudo_palette;
+ rgbidx = RGB_16;
+ break;
+#endif
+ default:
+ rgbidx = 0;
+ display->dispsw = &fbcon_dummy;
+ break;
+ }
+
+ display->screen_base = fbi->screen_cpu;
+ display->next_line = display->line_length;
+ display->type = fbi->fb.fix.type;
+ display->type_aux = fbi->fb.fix.type_aux;
+ display->ypanstep = fbi->fb.fix.ypanstep;
+ display->ywrapstep = fbi->fb.fix.ywrapstep;
+ display->can_soft_blank = 1;
+ display->inverse = fbi->cmap_inverse;
+
+ *dvar = *var;
+ dvar->activate &= ~FB_ACTIVATE_ALL;
+
+ /*
+ * Copy the RGB parameters for this display
+ * from the machine specific parameters.
+ */
+ dvar->red = fbi->rgb[rgbidx]->red;
+ dvar->green = fbi->rgb[rgbidx]->green;
+ dvar->blue = fbi->rgb[rgbidx]->blue;
+ dvar->transp = fbi->rgb[rgbidx]->transp;
+
+ DPRINTK("RGBT length = %d:%d:%d:%d\n",
+ dvar->red.length, dvar->green.length, dvar->blue.length,
+ dvar->transp.length);
+
+ DPRINTK("RGBT offset = %d:%d:%d:%d\n",
+ dvar->red.offset, dvar->green.offset, dvar->blue.offset,
+ dvar->transp.offset);
+
+ /*
+ * Update the old var. The fbcon drivers still use this.
+ * Once they are using fbi->fb.var, this can be dropped.
+ */
+ display->var = *dvar;
+
+ /*
+ * If we are setting all the virtual consoles, also set the
+ * defaults used to create new consoles.
+ */
+ if (var->activate & FB_ACTIVATE_ALL)
+ fbi->fb.disp->var = *dvar;
+
+ /*
+ * If the console has changed and the console has defined
+ * a changevar function, call that function.
+ */
+ if (chgvar && info && fbi->fb.changevar)
+ fbi->fb.changevar(con);
+
+ /* If the current console is selected, activate the new var. */
+ if (con != fbi->currcon)
+ return 0;
+
+ sa1100fb_hw_set_var(dvar, fbi);
return 0;
}
static int
-sa1100fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
- struct fb_info *info)
+__do_set_cmap(struct fb_cmap *cmap, int kspc, int con,
+ struct fb_info *info)
{
+ struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
+ struct fb_cmap *dcmap = get_con_cmap(info, con);
int err = 0;
- DPRINTK("current_par.visual=%d\n", current_par.visual);
- if (con == current_par.currcon)
- err = fb_get_cmap(cmap, kspc, sa1100fb_getcolreg, info);
- else if (fb_display[con].cmap.len)
- fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
- else
- fb_copy_cmap(fb_default_cmap(current_par.palette_size),
- cmap, kspc ? 0 : 2);
+ if (con == -1)
+ con = fbi->currcon;
+
+ /* no colormap allocated? (we always have "this" colour map allocated) */
+ if (con >= 0)
+ err = fb_alloc_cmap(&fb_display[con].cmap, fbi->palette_size, 0);
+
+ if (!err && con == fbi->currcon)
+ err = fb_set_cmap(cmap, kspc, sa1100fb_setcolreg, info);
+
+ if (!err)
+ fb_copy_cmap(cmap, dcmap, kspc ? 0 : 1);
+
return err;
}
sa1100fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
struct fb_info *info)
{
- int err = 0;
+ struct display *disp = get_con_display(info, con);
- DPRINTK("current_par.visual=%d\n", current_par.visual);
- if (!fb_display[con].cmap.len)
- err = fb_alloc_cmap(&fb_display[con].cmap,
- current_par.palette_size, 0);
- if (!err) {
- if (con == current_par.currcon)
- err = fb_set_cmap(cmap, kspc, sa1100fb_setcolreg,
- info);
- fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
- }
- return err;
+ if (disp->visual == FB_VISUAL_TRUECOLOR ||
+ disp->visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
+ return -EINVAL;
+
+ return __do_set_cmap(cmap, kspc, con, info);
+}
+
+static int
+sa1100fb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
+{
+ struct display *display = get_con_display(info, con);
+
+ *fix = info->fix;
+
+ fix->line_length = display->line_length;
+ fix->visual = display->visual;
+ return 0;
}
-static void inline
-sa1100fb_get_par(struct sa1100fb_par *par)
+static int
+sa1100fb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
{
- *par = current_par;
+ *var = *get_con_var(info, con);
+ return 0;
}
+static int
+sa1100fb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info)
+{
+ struct fb_cmap *dcmap = get_con_cmap(info, con);
+ fb_copy_cmap(dcmap, cmap, kspc ? 0 : 2);
+ return 0;
+}
+
+static struct fb_ops sa1100fb_ops = {
+ owner: THIS_MODULE,
+ fb_get_fix: sa1100fb_get_fix,
+ fb_get_var: sa1100fb_get_var,
+ fb_set_var: sa1100fb_set_var,
+ fb_get_cmap: sa1100fb_get_cmap,
+ fb_set_cmap: sa1100fb_set_cmap,
+};
/*
- * sa1100fb_encode_var():
- * Modify var structure using values in par
+ * sa1100fb_switch():
+ * Change to the specified console. Palette and video mode
+ * are changed to the console's stored parameters.
+ *
+ * Uh oh, this can be called from a tasklet (IRQ)
*/
-static int
-sa1100fb_encode_var(struct fb_var_screeninfo *var,
- struct sa1100fb_par *par)
+static int sa1100fb_switch(int con, struct fb_info *info)
{
- // Don't know if really want to zero var on entry.
- // Look at set_var to see. If so, may need to add extra params to par
-// memset(var, 0, sizeof(struct fb_var_screeninfo));
-
- var->xres = par->xres;
- var->yres = par->yres;
- var->xres_virtual = par->xres_virtual;
- var->yres_virtual = par->yres_virtual;
-
- var->bits_per_pixel = par->bits_per_pixel;
-
- DPRINTK("var->bits_per_pixel=%d\n", var->bits_per_pixel);
- switch(var->bits_per_pixel) {
- case 2:
- case 4:
- case 8:
- var->red.length = 4;
- var->green = var->red;
- var->blue = var->red;
- var->transp.length = 0;
- break;
- case 12: // This case should differ for Active/Passive mode
- case 16:
- if (machine_is_bitsy()) {
- var->red.length = 4;
- var->blue.length = 4;
- var->green.length = 4;
- var->transp.length = 0;
- var->red.offset = 12;
- var->green.offset = 7;
- var->blue.offset = 1;
- var->transp.offset = 0;
- } else {
- var->red.length = 5;
- var->blue.length = 5;
- var->green.length = 6;
- var->transp.length = 0;
- var->red.offset = 11;
- var->green.offset = 5;
- var->blue.offset = 0;
- var->transp.offset = 0;
- }
- break;
+ struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
+ struct display *disp;
+ struct fb_cmap *cmap;
+
+ DPRINTK("con=%d info->modename=%s\n", con, fbi->fb.modename);
+
+ if (con == fbi->currcon)
+ return 0;
+
+ if (fbi->currcon >= 0) {
+ disp = fb_display + fbi->currcon;
+
+ /*
+ * Save the old colormap and video mode.
+ */
+ disp->var = fbi->fb.var;
+
+ if (disp->cmap.len)
+ fb_copy_cmap(&fbi->fb.cmap, &disp->cmap, 0);
}
+
+ fbi->currcon = con;
+ disp = fb_display + con;
+
+ /*
+ * Make sure that our colourmap contains 256 entries.
+ */
+ fb_alloc_cmap(&fbi->fb.cmap, 256, 0);
+
+ if (disp->cmap.len)
+ cmap = &disp->cmap;
+ else
+ cmap = fb_default_cmap(1 << disp->var.bits_per_pixel);
+
+ fb_copy_cmap(cmap, &fbi->fb.cmap, 0);
+
+ fbi->fb.var = disp->var;
+ fbi->fb.var.activate = FB_ACTIVATE_NOW;
+
+ sa1100fb_set_var(&fbi->fb.var, con, info);
return 0;
}
-
+
/*
- * sa1100fb_decode_var():
- * Get the video params out of 'var'. If a value doesn't fit, round it up,
- * if it's too big, return -EINVAL.
+ * Formal definition of the VESA spec:
+ * On
+ * This refers to the state of the display when it is in full operation
+ * Stand-By
+ * This defines an optional operating state of minimal power reduction with
+ * the shortest recovery time
+ * Suspend
+ * This refers to a level of power management in which substantial power
+ * reduction is achieved by the display. The display can have a longer
+ * recovery time from this state than from the Stand-by state
+ * Off
+ * This indicates that the display is consuming the lowest level of power
+ * and is non-operational. Recovery from this state may optionally require
+ * the user to manually power on the monitor
*
- * Suggestion: Round up in the following order: bits_per_pixel, xres,
- * yres, xres_virtual, yres_virtual, xoffset, yoffset, grayscale,
- * bitfields, horizontal timing, vertical timing.
+ * Now, the fbdev driver adds an additional state, (blank), where they
+ * turn off the video (maybe by colormap tricks), but don't mess with the
+ * video itself: think of it semantically between on and Stand-By.
+ *
+ * So here's what we should do in our fbdev blank routine:
+ *
+ * VESA_NO_BLANKING (mode 0) Video on, front/back light on
+ * VESA_VSYNC_SUSPEND (mode 1) Video on, front/back light off
+ * VESA_HSYNC_SUSPEND (mode 2) Video on, front/back light off
+ * VESA_POWERDOWN (mode 3) Video off, front/back light off
+ *
+ * This will match the matrox implementation.
*/
-static int
-sa1100fb_decode_var(struct fb_var_screeninfo *var,
- struct sa1100fb_par *par)
+/*
+ * sa1100fb_blank():
+ * Blank the display by setting all palette values to zero. Note, the
+ * 12 and 16 bpp modes don't really use the palette, so this will not
+ * blank the display in all modes.
+ */
+static void sa1100fb_blank(int blank, struct fb_info *info)
{
- u_long palette_mem_phys;
- u_long palette_mem_size;
+ struct sa1100fb_info *fbi = (struct sa1100fb_info *)info;
+ int i;
- *par = current_par;
-
- if ((par->xres = var->xres) < MIN_XRES)
- par->xres = MIN_XRES;
- if ((par->yres = var->yres) < MIN_YRES)
- par->yres = MIN_YRES;
- if (par->xres > current_par.max_xres)
- par->xres = current_par.max_xres;
- if (par->yres > current_par.max_yres)
- par->yres = current_par.max_yres;
- par->xres_virtual =
- var->xres_virtual < par->xres ? par->xres : var->xres_virtual;
- par->yres_virtual =
- var->yres_virtual < par->yres ? par->yres : var->yres_virtual;
- par->bits_per_pixel = var->bits_per_pixel;
-
- DPRINTK("par->bits_per_pixel=%d\n", par->bits_per_pixel);
- switch (par->bits_per_pixel) {
-#ifdef FBCON_HAS_CFB4
- case 4:
- par->visual = FB_VISUAL_PSEUDOCOLOR;
- par->palette_size = 16;
- break;
-#endif
-#ifdef FBCON_HAS_CFB8
- case 8:
- par->visual = FB_VISUAL_PSEUDOCOLOR;
- par->palette_size = 256;
- break;
-#endif
-#ifdef FBCON_HAS_CFB16
- case 16: /* RGB 565 */
- par->visual = FB_VISUAL_TRUECOLOR;
- par->palette_size = 0;
+ DPRINTK("sa1100fb_blank: blank=%d info->modename=%s\n", blank,
+ fbi->fb.modename);
+
+ switch (blank) {
+ case VESA_POWERDOWN:
+ case VESA_VSYNC_SUSPEND:
+ case VESA_HSYNC_SUSPEND:
+ if (fbi->fb.disp->visual == FB_VISUAL_PSEUDOCOLOR ||
+ fbi->fb.disp->visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
+ for (i = 0; i < fbi->palette_size; i++)
+ sa1100fb_setpalettereg(i, 0, 0, 0, 0, info);
+ sa1100fb_schedule_task(fbi, C_DISABLE);
+ if (sa1100fb_blank_helper)
+ sa1100fb_blank_helper(blank);
break;
+
+ case VESA_NO_BLANKING:
+ if (sa1100fb_blank_helper)
+ sa1100fb_blank_helper(blank);
+ if (fbi->fb.disp->visual == FB_VISUAL_PSEUDOCOLOR ||
+ fbi->fb.disp->visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
+ fb_set_cmap(&fbi->fb.cmap, 1, sa1100fb_setcolreg, info);
+ sa1100fb_schedule_task(fbi, C_ENABLE);
+ }
+}
+
+static int sa1100fb_updatevar(int con, struct fb_info *info)
+{
+ DPRINTK("entered\n");
+ return 0;
+}
+
+/*
+ * Calculate the PCD value from the clock rate (in picoseconds).
+ * We take account of the PPCR clock setting.
+ */
+static inline int get_pcd(unsigned int pixclock)
+{
+ unsigned int pcd;
+
+ if (pixclock) {
+ pcd = get_cclk_frequency() * pixclock;
+ pcd /= 10000000;
+ pcd += 1; /* make up for integer math truncations */
+ } else {
+ /*
+ * People seem to be missing this message. Make it big.
+ * Make it stand out. Make sure people see it.
+ */
+ printk(KERN_WARNING "******************************************************\n");
+ printk(KERN_WARNING "** ZERO PIXEL CLOCK DETECTED **\n");
+ printk(KERN_WARNING "** You are using a zero pixclock. This means that **\n");
+ printk(KERN_WARNING "** clock scaling will not be able to adjust your **\n");
+ printk(KERN_WARNING "** your timing parameters appropriately, and the **\n");
+ printk(KERN_WARNING "** bandwidth calculations will fail to work. This **\n");
+ printk(KERN_WARNING "** will shortly become an error condition, which **\n");
+ printk(KERN_WARNING "** will prevent your LCD display working. Please **\n");
+ printk(KERN_WARNING "** send your patches in as soon as possible to shut **\n");
+ printk(KERN_WARNING "** this message up. **\n");
+ printk(KERN_WARNING "******************************************************\n");
+ pcd = 0;
+ }
+ return pcd;
+}
+
+/*
+ * sa1100fb_activate_var():
+ * Configures LCD Controller based on entries in var parameter. Settings are
+ * only written to the controller if changes were made.
+ */
+static int sa1100fb_activate_var(struct fb_var_screeninfo *var, struct sa1100fb_info *fbi)
+{
+ struct sa1100fb_lcd_reg new_regs;
+ u_int half_screen_size, yres, pcd = get_pcd(var->pixclock);
+ u_long flags;
+
+ DPRINTK("Configuring SA1100 LCD\n");
+
+ DPRINTK("var: xres=%d hslen=%d lm=%d rm=%d\n",
+ var->xres, var->hsync_len,
+ var->left_margin, var->right_margin);
+ DPRINTK("var: yres=%d vslen=%d um=%d bm=%d\n",
+ var->yres, var->vsync_len,
+ var->upper_margin, var->lower_margin);
+
+#if DEBUG_VAR
+ if (var->xres < 16 || var->xres > 1024)
+ printk(KERN_ERR "%s: invalid xres %d\n",
+ fbi->fb.fix.id, var->xres);
+ if (var->hsync_len < 1 || var->hsync_len > 64)
+ printk(KERN_ERR "%s: invalid hsync_len %d\n",
+ fbi->fb.fix.id, var->hsync_len);
+ if (var->left_margin < 1 || var->left_margin > 255)
+ printk(KERN_ERR "%s: invalid left_margin %d\n",
+ fbi->fb.fix.id, var->left_margin);
+ if (var->right_margin < 1 || var->right_margin > 255)
+ printk(KERN_ERR "%s: invalid right_margin %d\n",
+ fbi->fb.fix.id, var->right_margin);
+ if (var->yres < 1 || var->yres > 1024)
+ printk(KERN_ERR "%s: invalid yres %d\n",
+ fbi->fb.fix.id, var->yres);
+ if (var->vsync_len < 1 || var->vsync_len > 64)
+ printk(KERN_ERR "%s: invalid vsync_len %d\n",
+ fbi->fb.fix.id, var->vsync_len);
+ if (var->upper_margin < 0 || var->upper_margin > 255)
+ printk(KERN_ERR "%s: invalid upper_margin %d\n",
+ fbi->fb.fix.id, var->upper_margin);
+ if (var->lower_margin < 0 || var->lower_margin > 255)
+ printk(KERN_ERR "%s: invalid lower_margin %d\n",
+ fbi->fb.fix.id, var->lower_margin);
#endif
- default:
- return -EINVAL;
- }
- palette_mem_size = SA1100_PALETTE_MEM_SIZE(par->bits_per_pixel);
- palette_mem_phys = (u_long)VideoMemRegion_phys + PAGE_SIZE - palette_mem_size;
- par->p_palette_base = (u_short *)palette_mem_phys;
- par->v_palette_base = (u_short *)((u_long)VideoMemRegion + PAGE_SIZE - palette_mem_size);
- par->p_screen_base = (u_char *)((u_long)VideoMemRegion_phys + PAGE_SIZE);
- par->v_screen_base = (u_char *)((u_long)VideoMemRegion + PAGE_SIZE);
-
- DPRINTK("p_palette_base = 0x%08lx\n",(u_long)par->p_palette_base);
- DPRINTK("v_palette_base = 0x%08lx\n",(u_long)par->v_palette_base);
- DPRINTK("palette_size = 0x%08lx\n",(u_long)par->palette_size);
- DPRINTK("palette_mem_size = 0x%08lx\n",(u_long)palette_mem_size);
- DPRINTK("p_screen_base = 0x%08lx\n",(u_long)par->p_screen_base);
- DPRINTK("v_screen_base = 0x%08lx\n",(u_long)par->v_screen_base);
- DPRINTK("VideoMemRegion = 0x%08lx\n",(u_long)VideoMemRegion);
- DPRINTK("VideoMemRegion_phys = 0x%08lx\n",(u_long)VideoMemRegion_phys);
+ new_regs.lccr0 = fbi->lccr0 |
+ LCCR0_LEN | LCCR0_LDM | LCCR0_BAM |
+ LCCR0_ERM | LCCR0_LtlEnd | LCCR0_DMADel(0);
- return 0;
-}
+ new_regs.lccr1 =
+ LCCR1_DisWdth(var->xres) +
+ LCCR1_HorSnchWdth(var->hsync_len) +
+ LCCR1_BegLnDel(var->left_margin) +
+ LCCR1_EndLnDel(var->right_margin);
-static int
-sa1100fb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
-{
- struct sa1100fb_par par;
+ /*
+ * If we have a dual scan LCD, then we need to halve
+ * the YRES parameter.
+ */
+ yres = var->yres;
+ if (fbi->lccr0 & LCCR0_Dual)
+ yres /= 2;
+
+ new_regs.lccr2 =
+ LCCR2_DisHght(yres) +
+ LCCR2_VrtSnchWdth(var->vsync_len) +
+ LCCR2_BegFrmDel(var->upper_margin) +
+ LCCR2_EndFrmDel(var->lower_margin);
+
+ new_regs.lccr3 = fbi->lccr3 |
+ (var->sync & FB_SYNC_HOR_HIGH_ACT ? LCCR3_HorSnchH : LCCR3_HorSnchL) |
+ (var->sync & FB_SYNC_VERT_HIGH_ACT ? LCCR3_VrtSnchH : LCCR3_VrtSnchL) |
+ LCCR3_ACBsCntOff;
+
+ if (pcd)
+ new_regs.lccr3 |= LCCR3_PixClkDiv(pcd);
+
+ sa1100fb_check_shadow(&new_regs, var, pcd);
+
+ DPRINTK("nlccr0 = 0x%08x\n", new_regs.lccr0);
+ DPRINTK("nlccr1 = 0x%08x\n", new_regs.lccr1);
+ DPRINTK("nlccr2 = 0x%08x\n", new_regs.lccr2);
+ DPRINTK("nlccr3 = 0x%08x\n", new_regs.lccr3);
+
+ half_screen_size = var->bits_per_pixel;
+ half_screen_size = half_screen_size * var->xres * var->yres / 16;
+
+ /* Update shadow copy atomically */
+ local_irq_save(flags);
+ fbi->dbar1 = fbi->palette_dma;
+ fbi->dbar2 = fbi->screen_dma + half_screen_size;
+
+ fbi->reg_lccr0 = new_regs.lccr0;
+ fbi->reg_lccr1 = new_regs.lccr1;
+ fbi->reg_lccr2 = new_regs.lccr2;
+ fbi->reg_lccr3 = new_regs.lccr3;
+ local_irq_restore(flags);
- DPRINTK("con=%d\n", con);
- if (con == -1) {
- sa1100fb_get_par(&par);
- sa1100fb_encode_var(var, &par);
- } else
- *var = fb_display[con].var;
+ /*
+ * Only update the registers if the controller is enabled
+ * and something has changed.
+ */
+ if ((LCCR0 != fbi->reg_lccr0) || (LCCR1 != fbi->reg_lccr1) ||
+ (LCCR2 != fbi->reg_lccr2) || (LCCR3 != fbi->reg_lccr3) ||
+ (DBAR1 != (Address) fbi->dbar1) || (DBAR2 != (Address) fbi->dbar2))
+ sa1100fb_schedule_task(fbi, C_REENABLE);
return 0;
}
/*
- * sa1100fb_set_var():
- * Set the user defined part of the display for the specified console
+ * NOTE! The following functions are purely helpers for set_ctrlr_state.
+ * Do not call them directly; set_ctrlr_state does the correct serialisation
+ * to ensure that things happen in the right way 100% of time time.
+ * -- rmk
*/
-static int
-sa1100fb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info)
+
+/*
+ * FIXME: move LCD power stuff into sa1100fb_power_up_lcd()
+ * Also, I'm expecting that the backlight stuff should
+ * be handled differently.
+ */
+static void sa1100fb_backlight_on(struct sa1100fb_info *fbi)
{
- struct display *display;
- int err, chgvar = 0;
- struct sa1100fb_par par;
+ DPRINTK("backlight on\n");
- if (con >= 0)
- display = &fb_display[con]; /* Display settings for console */
- else
- display = &global_disp; /* Default display settings */
+#ifdef CONFIG_SA1100_FREEBIRD
+#error FIXME
+ if (machine_is_freebird()) {
+ BCR_set(BCR_FREEBIRD_LCD_PWR | BCR_FREEBIRD_LCD_DISP);
+ }
+#endif
+#ifdef CONFIG_SA1100_FREEBIRD
+ if (machine_is_freebird()) {
+ /* Turn on backlight ,Chester */
+ BCR_set(BCR_FREEBIRD_LCD_BACKLIGHT);
+ }
+#endif
+#ifdef CONFIG_SA1100_HUW_WEBPANEL
+#error FIXME
+ if (machine_is_huw_webpanel()) {
+ BCR_set(BCR_CCFL_POW + BCR_PWM_BACKLIGHT);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_task(200 * HZ / 1000);
+ BCR_set(BCR_TFT_ENA);
+ }
+#endif
+#ifdef CONFIG_SA1100_OMNIMETER
+ if (machine_is_omnimeter())
+ LEDBacklightOn();
+#endif
+#ifdef CONFIG_SA1100_BITSY
+ /* what rmk said --dneuer */
+#endif
+}
- /* Decode var contents into a par structure, adjusting any */
- /* out of range values. */
- if ((err = sa1100fb_decode_var(var, &par)))
- return err;
- // Store adjusted par values into var structure
- sa1100fb_encode_var(var, &par);
-
- if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_TEST)
- return 0;
- else if (((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW) &&
- ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NXTOPEN))
- return -EINVAL;
+/*
+ * FIXME: move LCD power stuf into sa1100fb_power_down_lcd()
+ * Also, I'm expecting that the backlight stuff should
+ * be handled differently.
+ */
+static void sa1100fb_backlight_off(struct sa1100fb_info *fbi)
+{
+ DPRINTK("backlight off\n");
- if (con >= 0) {
- if ((display->var.xres != var->xres) ||
- (display->var.yres != var->yres) ||
- (display->var.xres_virtual != var->xres_virtual) ||
- (display->var.yres_virtual != var->yres_virtual) ||
- (display->var.sync != var->sync) ||
- (display->var.bits_per_pixel != var->bits_per_pixel) ||
- (memcmp(&display->var.red, &var->red, sizeof(var->red))) ||
- (memcmp(&display->var.green, &var->green, sizeof(var->green))) ||
- (memcmp(&display->var.blue, &var->blue, sizeof(var->blue))))
- chgvar = 1;
+#ifdef CONFIG_SA1100_FREEBIRD
+#error FIXME
+ if (machine_is_freebird()) {
+ BCR_clear(BCR_FREEBIRD_LCD_PWR | BCR_FREEBIRD_LCD_DISP
+ /*| BCR_FREEBIRD_LCD_BACKLIGHT */ );
}
+#endif
+#ifdef CONFIG_SA1100_OMNIMETER
+ if (machine_is_omnimeter())
+ LEDBacklightOff();
+#endif
+#ifdef CONFIG_SA1100_BITSY
+ /* what rmk said --dneuer */
+#endif
+}
- display->var = *var;
- display->screen_base = par.v_screen_base;
- display->visual = par.visual;
- display->type = FB_TYPE_PACKED_PIXELS;
- display->type_aux = 0;
- display->ypanstep = 0;
- display->ywrapstep = 0;
- display->line_length =
- display->next_line = (var->xres * var->bits_per_pixel) / 8;
-
- display->can_soft_blank = 1;
- display->inverse = 0;
+static void sa1100fb_power_up_lcd(struct sa1100fb_info *fbi)
+{
+ DPRINTK("LCD power on\n");
- switch (display->var.bits_per_pixel) {
-#ifdef FBCON_HAS_CFB4
- case 4:
- display->dispsw = &fbcon_cfb4;
- break;
+#if defined(CONFIG_SA1100_ASSABET) && !defined(ASSABET_PAL_VIDEO)
+ if (machine_is_assabet())
+ BCR_set(BCR_LCD_ON);
#endif
-#ifdef FBCON_HAS_CFB8
- case 8:
- display->dispsw = &fbcon_cfb8;
- break;
+#ifdef CONFIG_SA1100_HUW_WEBPANEL
+ if (machine_is_huw_webpanel())
+ BCR_clear(BCR_TFT_NPWR);
#endif
-#ifdef FBCON_HAS_CFB16
- case 16:
- display->dispsw = &fbcon_cfb16;
- break;
+#ifdef CONFIG_SA1100_OMNIMETER
+ if (machine_is_omnimeter())
+ LCDPowerOn();
#endif
- default:
- display->dispsw = &fbcon_dummy;
- break;
+#ifdef CONFIG_SA1100_BITSY
+ if (machine_is_bitsy()) {
+ set_bitsy_egpio(EGPIO_BITSY_LCD_ON |
+ EGPIO_BITSY_LCD_PCI |
+ EGPIO_BITSY_LCD_5V_ON |
+ EGPIO_BITSY_LVDD_ON);
}
+#endif
+}
- /* If the console has changed and the console has defined */
- /* a changevar function, call that function. */
- if (chgvar && info && info->changevar)
- info->changevar(con);
-
- /* If the current console is selected and it's not truecolor,
- * update the palette
- */
- if ((con == current_par.currcon) &&
- (current_par.visual != FB_VISUAL_TRUECOLOR)) {
- struct fb_cmap *cmap;
-
- current_par = par;
- if (display->cmap.len)
- cmap = &display->cmap;
- else
- cmap = fb_default_cmap(current_par.palette_size);
+static void sa1100fb_power_down_lcd(struct sa1100fb_info *fbi)
+{
+ DPRINTK("LCD power off\n");
- fb_set_cmap(cmap, 1, sa1100fb_setcolreg, info);
+#if defined(CONFIG_SA1100_ASSABET) && !defined(ASSABET_PAL_VIDEO)
+ if (machine_is_assabet())
+ BCR_clear(BCR_LCD_ON);
+#endif
+#ifdef CONFIG_SA1100_HUW_WEBPANEL
+ // dont forget to set the control lines to zero (?)
+ if (machine_is_huw_webpanel())
+ BCR_set(BCR_TFT_NPWR);
+#endif
+#ifdef CONFIG_SA1100_BITSY
+ if (machine_is_bitsy()) {
+ clr_bitsy_egpio(EGPIO_BITSY_LCD_ON |
+ EGPIO_BITSY_LCD_PCI |
+ EGPIO_BITSY_LCD_5V_ON |
+ EGPIO_BITSY_LVDD_ON);
}
-
- /* If the current console is selected, activate the new var. */
- if (con == current_par.currcon)
- sa1100fb_activate_var(var);
-
- return 0;
+#endif
}
-static int
-sa1100fb_updatevar(int con, struct fb_info *info)
+static void sa1100fb_setup_gpio(struct sa1100fb_info *fbi)
{
- DPRINTK("entered\n");
- return 0;
-}
+ u_int mask = 0;
-static int
-sa1100fb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
-{
- struct display *display;
+ /*
+ * Enable GPIO<9:2> for LCD use if:
+ * 1. Active display, or
+ * 2. Color Dual Passive display
+ *
+ * see table 11.8 on page 11-27 in the SA1100 manual
+ * -- Erik.
+ *
+ * SA1110 spec update nr. 25 says we can and should
+ * clear LDD15 to 12 for 4 or 8bpp modes with active
+ * panels.
+ */
+ if ((fbi->reg_lccr0 & LCCR0_CMS) == LCCR0_Color &&
+ (fbi->reg_lccr0 & (LCCR0_Dual|LCCR0_Act)) != 0) {
+ mask = GPIO_LDD11 | GPIO_LDD10 | GPIO_LDD9 | GPIO_LDD8;
- memset(fix, 0, sizeof(struct fb_fix_screeninfo));
- strcpy(fix->id, SA1100_NAME);
+ if (fbi->fb.var.bits_per_pixel > 8 ||
+ (fbi->reg_lccr0 & (LCCR0_Dual|LCCR0_Act)) == LCCR0_Dual)
+ mask |= GPIO_LDD15 | GPIO_LDD14 | GPIO_LDD13 | GPIO_LDD12;
- if (con >= 0)
- {
- DPRINTK("Using console specific display for con=%d\n",con);
- display = &fb_display[con]; /* Display settings for console */
}
- else
- display = &global_disp; /* Default display settings */
-
- fix->smem_start = (unsigned long)current_par.p_screen_base;
- fix->smem_len = current_par.screen_size;
- fix->type = display->type;
- fix->type_aux = display->type_aux;
- fix->xpanstep = 0;
- fix->ypanstep = display->ypanstep;
- fix->ywrapstep = display->ywrapstep;
- fix->visual = display->visual;
- fix->line_length = display->line_length;
- fix->accel = FB_ACCEL_NONE;
- return 0;
-}
+#ifdef CONFIG_SA1100_FREEBIRD
+#error Please contact <rmk@arm.linux.org.uk> about this
+ if (machine_is_freebird()) {
+ /* Color single passive */
+ mask |= GPIO_LDD15 | GPIO_LDD14 | GPIO_LDD13 | GPIO_LDD12 |
+ GPIO_LDD11 | GPIO_LDD10 | GPIO_LDD9 | GPIO_LDD8;
+ }
+#endif
+#ifdef CONFIG_SA1100_CERF
+#error Please contact <rmk@arm.linux.org.uk> about this
+ if (machine_is_cerf()) {
+ /* GPIO15 is used as a bypass for 3.8" displays */
+ mask |= GPIO_GPIO15;
+
+ /* FIXME: why is this? The Cerf's display doesn't seem
+ * to be dual scan or active. I just leave it here,
+ * but in my opinion this is definitively wrong.
+ * -- Erik <J.A.K.Mouw@its.tudelft.nl>
+ */
+ /* REPLY: Umm.. Well to be honest, the 5.7" LCD which
+ * this was used for does not use these pins, but
+ * apparently all hell breaks loose if they are not
+ * set on the Cerf, so we decided to leave them in ;)
+ * -- Daniel Chemko <dchemko@intrinsyc.com>
+ */
+ /* color {dual/single} passive */
+ mask |= GPIO_LDD15 | GPIO_LDD14 | GPIO_LDD13 | GPIO_LDD12 |
+ GPIO_LDD11 | GPIO_LDD10 | GPIO_LDD9 | GPIO_LDD8;
+ }
+#endif
-static void
-__init sa1100fb_init_fbinfo(void)
+ if (mask) {
+ GPDR |= mask;
+ GAFR |= mask;
+ }
+}
+
+static void sa1100fb_enable_controller(struct sa1100fb_info *fbi)
{
- strcpy(fb_info.modename, SA1100_NAME);
- strcpy(fb_info.fontname, "Acorn8x8");
-
- fb_info.node = -1;
- fb_info.flags = FBINFO_FLAG_DEFAULT;
- fb_info.fbops = &sa1100fb_ops;
- fb_info.monspecs = monspecs;
- fb_info.disp = &global_disp;
- fb_info.changevar = NULL;
- fb_info.switch_con = sa1100fb_switch;
- fb_info.updatevar = sa1100fb_updatevar;
- fb_info.blank = sa1100fb_blank;
+ DPRINTK("Enabling LCD controller\n");
/*
- * setup initial parameters
+ * Make sure the mode bits are present in the first palette entry
*/
- memset(&init_var, 0, sizeof(init_var));
-
- init_var.transp.length = 0;
- init_var.nonstd = 0;
- init_var.activate = FB_ACTIVATE_NOW;
- init_var.xoffset = 0;
- init_var.yoffset = 0;
- init_var.height = -1;
- init_var.width = -1;
- init_var.vmode = FB_VMODE_NONINTERLACED;
-
- if (machine_is_assabet()) {
- current_par.max_xres = 320;
- current_par.max_yres = 240;
- current_par.max_bpp = 16;
- init_var.red.length = 5;
- init_var.green.length = 6;
- init_var.blue.length = 5;
- init_var.grayscale = 0;
- init_var.sync = 0;
- init_var.pixclock = 171521;
- } else if (machine_is_cerf()) {
- current_par.max_xres = 320;
- current_par.max_yres = 240;
- current_par.max_bpp = 8;
- init_var.red.length = 4;
- init_var.green.length = 4;
- init_var.blue.length = 4;
- init_var.grayscale = 0;
- init_var.sync = 0;
- init_var.pixclock = 171521;
- } else if (machine_is_pangolin()) {
- current_par.max_xres = 1024;
- current_par.max_yres = 768;
- current_par.max_bpp = 16;
- init_var.red.length = 5;
- init_var.green.length = 6;
- init_var.blue.length = 5;
- init_var.grayscale = 0;
- init_var.sync = 0;
- init_var.pixclock = 15400;
- } else if (machine_is_bitsy()) {
- current_par.max_xres = 320;
- current_par.max_yres = 240;
- current_par.max_bpp = 16;
- init_var.red.length = 4;
- init_var.green.length = 4;
- init_var.blue.length = 4;
- init_var.red.offset = 12;
- init_var.green.offset = 7;
- init_var.blue.offset = 1;
- init_var.grayscale = 0;
- } else if (machine_is_brutus()) {
- current_par.max_xres = 320;
- current_par.max_yres = 240;
- current_par.max_bpp = 8;
- init_var.red.length = 4;
- init_var.green = init_var.red;
- init_var.blue = init_var.red;
- init_var.sync = 0;
- } else if (machine_is_lart()) {
- current_par.max_xres = 320;
- current_par.max_yres = 240;
- current_par.max_bpp = 4;
- init_var.red.length = 4;
- init_var.green = init_var.red;
- init_var.blue = init_var.red;
- init_var.grayscale = 1;
- init_var.pixclock = 150000;
- init_var.sync = 0;
- } else if (machine_is_graphicsclient()) {
- current_par.max_xres = 640;
- current_par.max_yres = 480;
- current_par.max_bpp = 8;
- init_var.red.length = 4;
- init_var.green = init_var.red;
- init_var.blue = init_var.red;
- init_var.sync = 0;
- } else if (machine_is_xp860()) {
- current_par.max_xres = 1024;
- current_par.max_yres = 768;
-
- current_par.max_bpp = 8;
- init_var.red.length = 4;
- init_var.green = init_var.red;
- init_var.blue = init_var.red;
-
- init_var.hsync_len = 4;
- init_var.left_margin = 3;
- init_var.right_margin = 2;
-
- init_var.vsync_len = 3;
- init_var.upper_margin = 2;
- init_var.lower_margin = 1;
-
+ fbi->palette_cpu[0] &= 0xcfff;
+ fbi->palette_cpu[0] |= palette_pbs(&fbi->fb.var);
+
+ /* Sequence from 11.7.10 */
+ LCCR3 = fbi->reg_lccr3;
+ LCCR2 = fbi->reg_lccr2;
+ LCCR1 = fbi->reg_lccr1;
+ LCCR0 = fbi->reg_lccr0 & ~LCCR0_LEN;
+ DBAR1 = (Address) fbi->dbar1;
+ DBAR2 = (Address) fbi->dbar2;
+ LCCR0 |= LCCR0_LEN;
+
+#ifdef CONFIG_SA1100_GRAPHICSCLIENT
+#error Where is GPIO24 set as an output? Can we fit this in somewhere else?
+ if (machine_is_graphicsclient()) {
+ // From ADS doc again...same as disable
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(20 * HZ / 1000);
+ GPSR |= GPIO_GPIO24;
}
+#endif
- current_par.p_palette_base = NULL;
- current_par.v_palette_base = NULL;
- current_par.p_screen_base = NULL;
- current_par.v_screen_base = NULL;
- current_par.palette_size = MAX_PALETTE_NUM_ENTRIES;
- current_par.screen_size = MAX_PIXEL_MEM_SIZE;
- current_par.montype = -1;
- current_par.currcon = -1;
- current_par.allow_modeset = 1;
- current_par.controller_state = LCD_MODE_DISABLED;
-
- init_var.xres = current_par.max_xres;
- init_var.yres = current_par.max_yres;
- init_var.xres_virtual = init_var.xres;
- init_var.yres_virtual = init_var.yres;
- init_var.bits_per_pixel = current_par.max_bpp;
-
+ DPRINTK("DBAR1 = %p\n", DBAR1);
+ DPRINTK("DBAR2 = %p\n", DBAR2);
+ DPRINTK("LCCR0 = 0x%08x\n", LCCR0);
+ DPRINTK("LCCR1 = 0x%08x\n", LCCR1);
+ DPRINTK("LCCR2 = 0x%08x\n", LCCR2);
+ DPRINTK("LCCR3 = 0x%08x\n", LCCR3);
}
-
-
-/*
- * sa1100fb_map_video_memory():
- * Allocates the DRAM memory for the frame buffer. This buffer is
- * remapped into a non-cached, non-buffered, memory region to
- * allow palette and pixel writes to occur without flushing the
- * cache. Once this area is remapped, all virtual memory
- * access to the video memory should occur at the new region.
- */
-static int
-__init sa1100fb_map_video_memory(void)
+static void sa1100fb_disable_controller(struct sa1100fb_info *fbi)
{
- u_int required_pages;
- u_int extra_pages;
- u_int order;
- struct page *page;
- char *allocated_region;
+ DECLARE_WAITQUEUE(wait, current);
- if (VideoMemRegion != NULL)
- return -EINVAL;
+ DPRINTK("Disabling LCD controller\n");
- DPRINTK("-1-");
-
- /* Find order required to allocate enough memory for framebuffer */
- required_pages = ALLOCATED_FB_MEM_SIZE >> PAGE_SHIFT;
- for (order = 0 ; required_pages >> order ; order++) {;}
- extra_pages = (1 << order) - required_pages;
-
- if ((allocated_region =
- (char *)__get_free_pages(GFP_KERNEL | GFP_DMA, order)) == NULL)
- return -ENOMEM;
-
- VideoMemRegion = (u_char *)allocated_region + (extra_pages << PAGE_SHIFT);
- VideoMemRegion_phys = (u_char *)__virt_to_phys((u_long)VideoMemRegion);
-
- /* Free all pages that we don't need but were given to us because */
- /* __get_free_pages() works on powers of 2. */
- for (;extra_pages;extra_pages--)
- free_page((u_int)allocated_region + ((extra_pages-1) << PAGE_SHIFT));
-
- /* Set reserved flag for fb memory to allow it to be remapped into */
- /* user space by the common fbmem driver using remap_page_range(). */
- for(page = virt_to_page(VideoMemRegion);
- page < virt_to_page(VideoMemRegion + ALLOCATED_FB_MEM_SIZE); page++)
- mem_map_reserve(page);
-
- /* Remap the fb memory to a non-buffered, non-cached region */
- VideoMemRegion = (u_char *)__ioremap((u_long)VideoMemRegion_phys,
- ALLOCATED_FB_MEM_SIZE,
- L_PTE_PRESENT |
- L_PTE_YOUNG |
- L_PTE_DIRTY |
- L_PTE_WRITE);
- return (VideoMemRegion == NULL ? -EINVAL : 0);
-}
+#ifdef CONFIG_SA1100_GRAPHICSCLIENT
+#error Where is GPIO24 set as an output? Can we fit this in somewhere else?
+ if (machine_is_graphicsclient()) {
+ /*
+ * From ADS internal document:
+ * GPIO24 should be LOW at least 10msec prior to disabling
+ * the LCD interface.
+ *
+ * We'll wait 20msec.
+ */
+ GPCR |= GPIO_GPIO24;
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(20 * HZ / 1000);
+ }
+#endif
+#ifdef CONFIG_SA1100_HUW_WEBPANEL
+#error Move me into sa1100fb_power_up_lcd and/or sa1100fb_backlight_on
+ if (machine_is_huw_webpanel()) {
+ // dont forget to set the control lines to zero (?)
+ DPRINTK("ShutDown HuW LCD controller\n");
+ BCR_clear(BCR_TFT_ENA + BCR_CCFL_POW + BCR_PWM_BACKLIGHT);
+ }
+#endif
-static const int frequency[16] = {
- 59000000,
- 73700000,
- 88500000,
- 103200000,
- 118000000,
- 132700000,
- 147500000,
- 162200000,
- 176900000,
- 191700000,
- 206400000,
- 230000000,
- 245000000,
- 260000000,
- 275000000,
- 290000000
-};
+ add_wait_queue(&fbi->ctrlr_wait, &wait);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ LCSR = 0xffffffff; /* Clear LCD Status Register */
+ LCCR0 &= ~LCCR0_LDM; /* Enable LCD Disable Done Interrupt */
+ enable_irq(IRQ_LCD); /* Enable LCD IRQ */
+ LCCR0 &= ~LCCR0_LEN; /* Disable LCD Controller */
-static inline int get_pcd(unsigned int pixclock)
+ schedule_timeout(20 * HZ / 1000);
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&fbi->ctrlr_wait, &wait);
+}
+
+/*
+ * sa1100fb_handle_irq: Handle 'LCD DONE' interrupts.
+ */
+static void sa1100fb_handle_irq(int irq, void *dev_id, struct pt_regs *regs)
{
- unsigned int pcd = 0;
+ struct sa1100fb_info *fbi = dev_id;
+ unsigned int lcsr = LCSR;
- if (machine_is_assabet() | machine_is_pangolin()) {
- pcd = frequency[PPCR & 0xf] / 1000;
- pcd *= pixclock / 1000;
- pcd = pcd / 1000000;
- pcd++; /* make up for integer math truncations */
+ if (lcsr & LCSR_LDD) {
+ LCCR0 |= LCCR0_LDM;
+ wake_up(&fbi->ctrlr_wait);
}
- return pcd;
-}
+ LCSR = lcsr;
+}
/*
- * sa1100fb_activate_var():
- * Configures LCD Controller based on entries in var parameter. Settings are
- * only written to the controller if changes were made.
+ * This function must be called from task context only, since it will
+ * sleep when disabling the LCD controller, or if we get two contending
+ * processes trying to alter state.
*/
-static int
-sa1100fb_activate_var(struct fb_var_screeninfo *var)
-{
- u_long flags;
- int pcd = get_pcd(var->pixclock);
-
- DPRINTK("Configuring SA1100 LCD\n");
+static void set_ctrlr_state(struct sa1100fb_info *fbi, u_int state)
+{
+ u_int old_state;
- if (current_par.p_palette_base == NULL)
- return -EINVAL;
+ down(&fbi->ctrlr_sem);
- DPRINTK("activating\n");
+ old_state = fbi->state;
- /* Disable interrupts and save status */
- local_irq_save(flags); // disable the interrupts and save flags
+ switch (state) {
+ case C_DISABLE_CLKCHANGE:
+ /*
+ * Disable controller for clock change. If the
+ * controller is already disabled, then do nothing.
+ */
+ if (old_state != C_DISABLE) {
+ fbi->state = state;
+ sa1100fb_disable_controller(fbi);
+ }
+ break;
- /* Reset the LCD Controller's DMA address if it has changed */
- lcd_shadow.dbar1 = (Address)current_par.p_palette_base;
- lcd_shadow.dbar2 = (Address)(current_par.p_screen_base + (current_par.xres * current_par.yres * current_par.bits_per_pixel / 8 / 2));
+ case C_DISABLE:
+ /*
+ * Disable controller
+ */
+ if (old_state != C_DISABLE) {
+ fbi->state = state;
- DPRINTK("Configuring xres = %d, yres = %d\n",var->xres, var->yres);
+ sa1100fb_backlight_off(fbi);
+ if (old_state != C_DISABLE_CLKCHANGE)
+ sa1100fb_disable_controller(fbi);
+ sa1100fb_power_down_lcd(fbi);
+ }
+ break;
- if (machine_is_assabet()) {
- DPRINTK("Configuring Assabet LCD\n");
- lcd_shadow.lccr0 =
- LCCR0_LEN + LCCR0_Color + LCCR0_Sngl +
- LCCR0_LDM + LCCR0_BAM + LCCR0_ERM + LCCR0_Act +
- LCCR0_LtlEnd + LCCR0_DMADel(0);
- lcd_shadow.lccr1 =
- LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(6) +
- LCCR1_BegLnDel(61) + LCCR1_EndLnDel(9);
- lcd_shadow.lccr2 =
- LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(1) +
- LCCR2_BegFrmDel(3) + LCCR2_EndFrmDel(0);
- lcd_shadow.lccr3 =
- LCCR3_OutEnH + LCCR3_PixFlEdg + LCCR3_VrtSnchH +
- LCCR3_HorSnchH + LCCR3_ACBsCntOff +
- LCCR3_ACBsDiv(2) + LCCR3_PixClkDiv(pcd);
-
- /* Set board control register to handle new color depth */
- sa1100fb_assabet_set_truecolor(var->bits_per_pixel >= 16);
- } else if (machine_is_pangolin()) {
- DPRINTK("Configuring Pangolin LCD\n");
- lcd_shadow.lccr0 =
- LCCR0_LEN + LCCR0_Color + LCCR0_LDM +
- LCCR0_BAM + LCCR0_ERM + LCCR0_Act +
- LCCR0_LtlEnd + LCCR0_DMADel(0);
- lcd_shadow.lccr1 =
- LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(63) +
- LCCR1_BegLnDel(127) + LCCR1_EndLnDel(127);
- lcd_shadow.lccr2 =
- LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(2) +
- LCCR2_BegFrmDel(18) + LCCR2_EndFrmDel(18);
- lcd_shadow.lccr3 =
- LCCR3_PixClkDiv(pcd) + LCCR3_HorSnchH +
- LCCR3_VrtSnchH + LCCR3_OutEnH;
- DPRINTK("pcd = %d\n", pcd);
- DPRINTK("LCCR1_DisWdth(var->xres) = 0x%x\n",
- LCCR1_DisWdth(var->xres));
- DPRINTK("LCCR2_DisHght(var->yres) = 0x%x\n",
- LCCR2_DisHght(var->yres));
- } else if (machine_is_bitsy()) {
- DPRINTK("Configuring Bitsy LCD\n");
- lcd_shadow.lccr0 = LCCR0_LEN + LCCR0_Color + LCCR0_Sngl + LCCR0_Act +
- LCCR0_LtlEnd + LCCR0_LDM + LCCR0_BAM + LCCR0_ERM +
- LCCR0_DMADel(0);
- lcd_shadow.lccr1 = LCCR1_DisWdth( var->xres ) +
- LCCR1_HorSnchWdth( 4 ) +
- LCCR1_BegLnDel( 0xC ) +
- LCCR1_EndLnDel( 0x11 );
- lcd_shadow.lccr2 = LCCR2_DisHght( var->yres + 1 ) +
- LCCR2_VrtSnchWdth( 3 )+
- LCCR2_BegFrmDel( 10 ) +
- LCCR2_EndFrmDel( 1 );
- lcd_shadow.lccr3 = (/* PCD */ 0x10
- | /* ACB */ 0
- | /* API */ 0
- | LCCR3_VrtSnchL
- | LCCR3_HorSnchL);
- } else if (machine_is_brutus()) {
- DPRINTK("Configuring Brutus LCD\n");
- lcd_shadow.lccr0 =
- LCCR0_LEN + LCCR0_Color + LCCR0_Sngl + LCCR0_Pas +
- LCCR0_LtlEnd + LCCR0_LDM + LCCR0_BAM + LCCR0_ERM +
- LCCR0_DMADel(0);
- lcd_shadow.lccr1 =
- LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(4) +
- LCCR1_BegLnDel(41) + LCCR1_EndLnDel(101);
- lcd_shadow.lccr2 =
- LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(1) +
- LCCR2_BegFrmDel(0) + LCCR2_EndFrmDel(0);
- lcd_shadow.lccr3 =
- LCCR3_OutEnH + LCCR3_PixFlEdg + LCCR3_VrtSnchH +
- LCCR3_HorSnchH + LCCR3_ACBsCntOff +
- LCCR3_ACBsDiv(2) + LCCR3_PixClkDiv(44);
- } else if (machine_is_cerf()) {
- DPRINTK("Configuring Cerf LCD\n");
- lcd_shadow.lccr0 =
- LCCR0_LEN + LCCR0_Color + LCCR0_Sngl +
- LCCR0_LDM + LCCR0_BAM + LCCR0_ERM + LCCR0_Pas +
- LCCR0_LtlEnd + LCCR0_DMADel(0);
- lcd_shadow.lccr1 =
- LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(6) +
- LCCR1_BegLnDel(61) + LCCR1_EndLnDel(9);
- lcd_shadow.lccr2 =
- LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(1) +
- LCCR2_BegFrmDel(3) + LCCR2_EndFrmDel(0);
- lcd_shadow.lccr3 =
- LCCR3_OutEnH + LCCR3_PixFlEdg + LCCR3_VrtSnchH +
- LCCR3_HorSnchH + LCCR3_ACBsCntOff +
- LCCR3_ACBsDiv(2) + LCCR3_PixClkDiv(38);
- } else if (machine_is_lart()) {
- DPRINTK("Configuring LART LCD\n");
- lcd_shadow.lccr0 =
- LCCR0_LEN + LCCR0_Mono + LCCR0_Sngl + LCCR0_Pas +
- LCCR0_LtlEnd + LCCR0_LDM + LCCR0_BAM + LCCR0_ERM +
- LCCR0_DMADel(0);
- lcd_shadow.lccr1 =
- LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(2) +
- LCCR1_BegLnDel(4) + LCCR1_EndLnDel(2);
- lcd_shadow.lccr2 =
- LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(1) +
- LCCR2_BegFrmDel(0) + LCCR2_EndFrmDel(0);
- lcd_shadow.lccr3 =
- LCCR3_PixClkDiv(34) + LCCR3_ACBsDiv(512) +
- LCCR3_ACBsCntOff + LCCR3_HorSnchH + LCCR3_VrtSnchH;
- } else if (machine_is_graphicsclient()) {
- DPRINTK("Configuring GraphicsClient LCD\n");
- lcd_shadow.lccr0 =
- LCCR0_LEN + LCCR0_Color + LCCR0_Sngl + LCCR0_Act;
- lcd_shadow.lccr1 =
- LCCR1_DisWdth(var->xres) + LCCR1_HorSnchWdth(10) +
- LCCR1_EndLnDel(81) + LCCR1_BegLnDel(81);
- lcd_shadow.lccr2 =
- LCCR2_DisHght(var->yres) + LCCR2_VrtSnchWdth(9) +
- LCCR2_EndFrmDel (20) + LCCR2_BegFrmDel(20);
- lcd_shadow.lccr3 =
- LCCR3_PixClkDiv(6) + LCCR3_ACBsDiv(2) +
- LCCR3_ACBsCntOff + LCCR3_HorSnchL + LCCR3_VrtSnchL;
- } else if (machine_is_xp860()) {
- DPRINTK("Configuring XP860 LCD\n");
- lcd_shadow.lccr0 =
- LCCR0_LEN + LCCR0_Color + LCCR0_Sngl + LCCR0_Act +
- LCCR0_LtlEnd + LCCR0_LDM + LCCR0_ERM +
- LCCR0_DMADel(0);
- lcd_shadow.lccr1 =
- LCCR1_DisWdth(var->xres) +
- LCCR1_HorSnchWdth(var->hsync_len) +
- LCCR1_BegLnDel(var->left_margin) +
- LCCR1_EndLnDel(var->right_margin);
- lcd_shadow.lccr2 =
- LCCR2_DisHght(var->yres) +
- LCCR2_VrtSnchWdth(var->vsync_len) +
- LCCR2_BegFrmDel(var->upper_margin) +
- LCCR2_EndFrmDel(var->lower_margin);
- lcd_shadow.lccr3 =
- LCCR3_PixClkDiv(6) +
- LCCR3_HorSnchL + LCCR3_VrtSnchL;
- }
+ case C_ENABLE_CLKCHANGE:
+ /*
+ * Enable the controller after clock change. Only
+ * do this if we were disabled for the clock change.
+ */
+ if (old_state == C_DISABLE_CLKCHANGE) {
+ fbi->state = C_ENABLE;
+ sa1100fb_enable_controller(fbi);
+ }
+ break;
- /* Restore interrupt status */
- local_irq_restore(flags);
+ case C_REENABLE:
+ /*
+ * Re-enable the controller only if it was already
+ * enabled. This is so we reprogram the control
+ * registers.
+ */
+ if (old_state == C_ENABLE) {
+ sa1100fb_disable_controller(fbi);
+ sa1100fb_setup_gpio(fbi);
+ sa1100fb_enable_controller(fbi);
+ }
+ break;
- if (( LCCR0 != lcd_shadow.lccr0 ) ||
- ( LCCR1 != lcd_shadow.lccr1 ) ||
- ( LCCR2 != lcd_shadow.lccr2 ) ||
- ( LCCR3 != lcd_shadow.lccr3 ) ||
- ( DBAR1 != lcd_shadow.dbar1 ) ||
- ( DBAR2 != lcd_shadow.dbar2 ))
- {
- sa1100fb_enable_lcd_controller();
+ case C_ENABLE:
+ /*
+ * Power up the LCD screen, enable controller, and
+ * turn on the backlight.
+ */
+ if (old_state != C_ENABLE) {
+ fbi->state = C_ENABLE;
+ sa1100fb_setup_gpio(fbi);
+ sa1100fb_power_up_lcd(fbi);
+ sa1100fb_enable_controller(fbi);
+ sa1100fb_backlight_on(fbi);
+ }
+ break;
}
-
- return 0;
+ up(&fbi->ctrlr_sem);
}
-
/*
- * sa1100fb_inter_handler():
- * Interrupt handler for LCD controller. Processes disable done interrupt (LDD)
- * to reenable controller if controller was disabled to change register values.
+ * Our LCD controller task (which is called when we blank or unblank)
+ * via keventd.
*/
-static void sa1100fb_inter_handler(int irq, void *dev_id, struct pt_regs *regs)
+static void sa1100fb_task(void *dummy)
{
- if (LCSR & LCSR_LDD) {
- int controller_state = current_par.controller_state;
- /* Disable Done Flag is set */
- LCCR0 |= LCCR0_LDM; /* Mask LCD Disable Done Interrupt */
- current_par.controller_state = LCD_MODE_DISABLED;
- if (controller_state == LCD_MODE_DISABLE_BEFORE_ENABLE) {
- DPRINTK("sa1100fb_inter_handler: re-enabling LCD controller\n");
- sa1100fb_enable_lcd_controller();
- } else {
- /*
- * Second half of sa1100fb_disable_lcd_controller()
- */
- if (machine_is_assabet()) {
-#ifdef CONFIG_SA1100_ASSABET
- BCR_clear(BCR_LCD_ON);
-#endif
- } else if (machine_is_bitsy()) {
-#ifdef CONFIG_SA1100_BITSY
- if (current_par.controller_state != LCD_MODE_DISABLE_BEFORE_ENABLE)
- clr_bitsy_egpio(EGPIO_BITSY_LCD_ON | EGPIO_BITSY_LCD_PCI | EGPIO_BITSY_LCD_5V_ON | EGPIO_BITSY_LVDD_ON);
-#endif
- }
- }
- }
- LCSR = 0; /* Clear LCD Status Register */
-}
+ struct sa1100fb_info *fbi = dummy;
+ u_int state = xchg(&fbi->task_state, -1);
+ set_ctrlr_state(fbi, state);
+}
+#ifdef CONFIG_CPU_FREQ
/*
- * sa1100fb_disable_lcd_controller():
- * Disables LCD controller by and enables LDD interrupt. The controller_state
- * is not changed until the LDD interrupt is received to indicate the current
- * frame has completed. Platform specific hardware disabling is also included.
+ * Calculate the minimum DMA period over all displays that we own.
+ * This, together with the SDRAM bandwidth defines the slowest CPU
+ * frequency that can be selected.
*/
-static void sa1100fb_disable_lcd_controller(void)
+static unsigned int sa1100fb_min_dma_period(struct sa1100fb_info *fbi)
{
- DPRINTK("Disabling LCD controller\n");
+ unsigned int min_period = (unsigned int)-1;
+ int i;
- /* Exit if already LCD disabled, or LDD IRQ unmasked */
- if ((current_par.controller_state == LCD_MODE_DISABLED) ||
- (!(LCCR0 & LCCR0_LDM))) {
- DPRINTK("LCD already disabled\n");
- return;
+ for (i = 0; i < MAX_NR_CONSOLES; i++) {
+ unsigned int period;
+
+ /*
+ * Do we own this display?
+ */
+ if (fb_display[i].fb_info != &fbi->fb)
+ continue;
+
+ /*
+ * Ok, calculate its DMA period
+ */
+ period = sa1100fb_display_dma_period(get_con_var(fbi, i));
+ if (period < min_period)
+ min_period = period;
}
- LCSR = 0; /* Clear LCD Status Register */
- LCCR0 &= ~(LCCR0_LDM); /* Enable LCD Disable Done Interrupt */
- enable_irq(IRQ_LCD); /* Enable LCD IRQ */
- LCCR0 &= ~(LCCR0_LEN); /* Disable LCD Controller */
+ return min_period;
}
/*
- * sa1100fb_enable_lcd_controller():
- * Enables LCD controller. If the controller is already enabled, it is first disabled.
- * This forces all changes to the LCD controller registers to be done when the
- * controller is disabled. Platform specific hardware enabling is also included.
+ * CPU clock speed change handler. We need to adjust the LCD timing
+ * parameters when the CPU clock is adjusted by the power management
+ * subsystem.
*/
-static void sa1100fb_enable_lcd_controller(void)
+static int
+sa1100fb_clkchg_notifier(struct notifier_block *nb, unsigned long val,
+ void *data)
{
- u_long flags;
-
- local_irq_save(flags);
-
- /* Disable controller before changing parameters */
- if (current_par.controller_state == LCD_MODE_ENABLED) {
- current_par.controller_state = LCD_MODE_DISABLE_BEFORE_ENABLE;
- sa1100fb_disable_lcd_controller();
- } else {
- DPRINTK("Enabling LCD controller\n");
-
- /* Make sure the mode bits are present in the first palette entry */
- current_par.v_palette_base[0] &= 0x0FFF;
- current_par.v_palette_base[0] |= SA1100_PALETTE_MODE_VAL(current_par.bits_per_pixel);
-
- /* Enable GPIO<9:2> for LCD usage if dual-scan */
- if (lcd_shadow.lccr0 & LCCR0_SDS) {
- GPDR |= 0x3fc;
- GAFR |= 0x3fc;
- }
-
- /* Sequence from 11.7.10 */
- LCCR3 = lcd_shadow.lccr3;
- LCCR2 = lcd_shadow.lccr2;
- LCCR1 = lcd_shadow.lccr1;
- LCCR0 = lcd_shadow.lccr0 & ~LCCR0_LEN;
- DBAR1 = lcd_shadow.dbar1;
- DBAR2 = lcd_shadow.dbar2;
- LCCR0 |= LCCR0_LEN;
-
- if (machine_is_assabet()) {
-#ifdef CONFIG_SA1100_ASSABET
- BCR_set(BCR_LCD_ON);
-#endif
- } else if (machine_is_bitsy()) {
-#ifdef CONFIG_SA1100_BITSY
- set_bitsy_egpio(EGPIO_BITSY_LCD_ON | EGPIO_BITSY_LCD_PCI | EGPIO_BITSY_LCD_5V_ON | EGPIO_BITSY_LVDD_ON);
- DPRINTK("DBAR1=%p\n", DBAR1);
- DPRINTK("LCCR0=%x\n", LCCR0);
- DPRINTK("LCCR1=%x\n", LCCR1);
- DPRINTK("LCCR2=%x\n", LCCR2);
- DPRINTK("LCCR3=%x\n", LCCR3);
-#endif
- }
+ struct sa1100fb_info *fbi = TO_INF(nb, clockchg);
+ struct cpufreq_minmax *mm = data;
+ u_int pcd;
+
+ switch (val) {
+ case CPUFREQ_MINMAX:
+ printk(KERN_DEBUG "min dma period: %d ps, old clock %d kHz, "
+ "new clock %d kHz\n", sa1100fb_min_dma_period(fbi),
+ mm->cur_freq, mm->new_freq);
+ /* todo: fill in min/max values */
+ break;
- current_par.controller_state = LCD_MODE_ENABLED;
+ case CPUFREQ_PRECHANGE:
+ set_ctrlr_state(fbi, C_DISABLE_CLKCHANGE);
+ break;
+ case CPUFREQ_POSTCHANGE:
+ pcd = get_pcd(fbi->fb.var.pixclock);
+ fbi->reg_lccr3 = (fbi->reg_lccr3 & ~0xff) | LCCR3_PixClkDiv(pcd);
+ set_ctrlr_state(fbi, C_ENABLE_CLKCHANGE);
+ break;
}
- /* Restore interrupt status */
- local_irq_restore(flags);
+ return 0;
}
+#endif
+#ifdef CONFIG_PM
/*
- * sa1100fb_blank():
- * Blank the display by setting all palette values to zero. Note, the
- * 12 and 16 bpp modes don't really use the palette, so this will not
- * blank the display in all modes.
+ * Power management hook. Note that we won't be called from IRQ context,
+ * unlike the blank functions above, so we may sleep.
*/
-static void
-sa1100fb_blank(int blank, struct fb_info *info)
+static int
+sa1100fb_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data)
{
- int i;
+ struct sa1100fb_info *fbi = pm_dev->data;
- DPRINTK("blank=%d info->modename=%s\n", blank, info->modename);
- if (blank) {
- if (current_par.visual != FB_VISUAL_TRUECOLOR)
- for (i = 0; i < current_par.palette_size; i++)
- sa1100fb_palette_write(i, sa1100fb_palette_encode(i, 0, 0, 0, 0));
- sa1100fb_disable_lcd_controller();
- }
- else {
- if (current_par.visual != FB_VISUAL_TRUECOLOR)
- sa1100fb_set_cmap(&fb_display[current_par.currcon].cmap, 1,
- current_par.currcon, info);
- sa1100fb_enable_lcd_controller();
+ DPRINTK("pm_callback: %d\n", req);
+
+ if (req == PM_SUSPEND || req == PM_RESUME) {
+ int state = (int)data;
+
+ if (state == 0) {
+ /* Enter D0. */
+ set_ctrlr_state(fbi, C_ENABLE);
+ } else {
+ /* Enter D1-D3. Disable the LCD controller. */
+ set_ctrlr_state(fbi, C_DISABLE);
+ }
}
- /* TODO: Bitsy support for blanking display */
+ DPRINTK("done\n");
+ return 0;
}
-
+#endif
/*
- * sa1100fb_switch():
- * Change to the specified console. Palette and video mode
- * are changed to the console's stored parameters.
+ * sa1100fb_map_video_memory():
+ * Allocates the DRAM memory for the frame buffer. This buffer is
+ * remapped into a non-cached, non-buffered, memory region to
+ * allow palette and pixel writes to occur without flushing the
+ * cache. Once this area is remapped, all virtual memory
+ * access to the video memory should occur at the new region.
*/
-static int
-sa1100fb_switch(int con, struct fb_info *info)
+static int __init sa1100fb_map_video_memory(struct sa1100fb_info *fbi)
{
+ /*
+ * We reserve one page for the palette, plus the size
+ * of the framebuffer.
+ */
+ fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + PAGE_SIZE);
+ fbi->map_cpu = consistent_alloc(GFP_KERNEL, fbi->map_size,
+ &fbi->map_dma);
+
+ if (fbi->map_cpu) {
+ fbi->screen_cpu = fbi->map_cpu + PAGE_SIZE;
+ fbi->screen_dma = fbi->map_dma + PAGE_SIZE;
+ fbi->fb.fix.smem_start = fbi->screen_dma;
+ }
- DPRINTK("con=%d info->modename=%s\n", con, info->modename);
- if (current_par.visual != FB_VISUAL_TRUECOLOR) {
- struct fb_cmap *cmap;
- if (current_par.currcon >= 0) {
- // Get the colormap for the selected console
- cmap = &fb_display[current_par.currcon].cmap;
-
- if (cmap->len)
- fb_get_cmap(cmap, 1, sa1100fb_getcolreg, info);
- }
- }
+ return fbi->map_cpu ? 0 : -ENOMEM;
+}
- current_par.currcon = con;
- fb_display[con].var.activate = FB_ACTIVATE_NOW;
- DPRINTK("fb_display[%d].var.activate=%x\n", con, fb_display[con].var.activate);
- sa1100fb_set_var(&fb_display[con].var, con, info);
- current_par.v_palette_base[0] = (current_par.v_palette_base[0] &
- 0xcfff) | SA1100_PALETTE_MODE_VAL(current_par.bits_per_pixel);
+/* Fake monspecs to fill in fbinfo structure */
+static struct fb_monspecs monspecs __initdata = {
+ 30000, 70000, 50, 65, 0 /* Generic */
+};
- return 0;
-}
+static struct sa1100fb_info * __init sa1100fb_init_fbinfo(void)
+{
+ struct sa1100fb_mach_info *inf;
+ struct sa1100fb_info *fbi;
+
+ fbi = kmalloc(sizeof(struct sa1100fb_info) + sizeof(struct display) +
+ sizeof(u16) * 16, GFP_KERNEL);
+ if (!fbi)
+ return NULL;
+
+ memset(fbi, 0, sizeof(struct sa1100fb_info) + sizeof(struct display));
+
+ fbi->currcon = -1;
+
+ strcpy(fbi->fb.fix.id, SA1100_NAME);
+
+ fbi->fb.fix.type = FB_TYPE_PACKED_PIXELS;
+ fbi->fb.fix.type_aux = 0;
+ fbi->fb.fix.xpanstep = 0;
+ fbi->fb.fix.ypanstep = 0;
+ fbi->fb.fix.ywrapstep = 0;
+ fbi->fb.fix.accel = FB_ACCEL_NONE;
+
+ fbi->fb.var.nonstd = 0;
+ fbi->fb.var.activate = FB_ACTIVATE_NOW;
+ fbi->fb.var.height = -1;
+ fbi->fb.var.width = -1;
+ fbi->fb.var.accel_flags = 0;
+ fbi->fb.var.vmode = FB_VMODE_NONINTERLACED;
+
+ strcpy(fbi->fb.modename, SA1100_NAME);
+ strcpy(fbi->fb.fontname, "Acorn8x8");
+
+ fbi->fb.fbops = &sa1100fb_ops;
+ fbi->fb.changevar = NULL;
+ fbi->fb.switch_con = sa1100fb_switch;
+ fbi->fb.updatevar = sa1100fb_updatevar;
+ fbi->fb.blank = sa1100fb_blank;
+ fbi->fb.flags = FBINFO_FLAG_DEFAULT;
+ fbi->fb.node = -1;
+ fbi->fb.monspecs = monspecs;
+ fbi->fb.disp = (struct display *)(fbi + 1);
+ fbi->fb.pseudo_palette = (void *)(fbi->fb.disp + 1);
+
+ fbi->rgb[RGB_8] = &rgb_8;
+ fbi->rgb[RGB_16] = &def_rgb_16;
+
+ inf = sa1100fb_get_machine_info(fbi);
+
+ fbi->max_xres = inf->xres;
+ fbi->fb.var.xres = inf->xres;
+ fbi->fb.var.xres_virtual = inf->xres;
+ fbi->max_yres = inf->yres;
+ fbi->fb.var.yres = inf->yres;
+ fbi->fb.var.yres_virtual = inf->yres;
+ fbi->max_bpp = inf->bpp;
+ fbi->fb.var.bits_per_pixel = inf->bpp;
+ fbi->fb.var.pixclock = inf->pixclock;
+ fbi->fb.var.hsync_len = inf->hsync_len;
+ fbi->fb.var.left_margin = inf->left_margin;
+ fbi->fb.var.right_margin = inf->right_margin;
+ fbi->fb.var.vsync_len = inf->vsync_len;
+ fbi->fb.var.upper_margin = inf->upper_margin;
+ fbi->fb.var.lower_margin = inf->lower_margin;
+ fbi->fb.var.sync = inf->sync;
+ fbi->fb.var.grayscale = inf->cmap_greyscale;
+ fbi->cmap_inverse = inf->cmap_inverse;
+ fbi->cmap_static = inf->cmap_static;
+ fbi->lccr0 = inf->lccr0;
+ fbi->lccr3 = inf->lccr3;
+ fbi->state = C_DISABLE;
+ fbi->task_state = (u_char)-1;
+ fbi->fb.fix.smem_len = fbi->max_xres * fbi->max_yres *
+ fbi->max_bpp / 8;
+
+ init_waitqueue_head(&fbi->ctrlr_wait);
+ INIT_TQUEUE(&fbi->task, sa1100fb_task, fbi);
+ init_MUTEX(&fbi->ctrlr_sem);
+
+ return fbi;
+}
int __init sa1100fb_init(void)
{
+ struct sa1100fb_info *fbi;
int ret;
- sa1100fb_init_fbinfo();
+ fbi = sa1100fb_init_fbinfo();
+ ret = -ENOMEM;
+ if (!fbi)
+ goto failed;
/* Initialize video memory */
- if ((ret = sa1100fb_map_video_memory()) != 0)
- return ret;
+ ret = sa1100fb_map_video_memory(fbi);
+ if (ret)
+ goto failed;
+
+ ret = request_irq(IRQ_LCD, sa1100fb_handle_irq, SA_INTERRUPT,
+ fbi->fb.fix.id, fbi);
+ if (ret) {
+ printk(KERN_ERR "sa1100fb: failed in request_irq: %d\n", ret);
+ goto failed;
+ }
- if (current_par.montype < 0 || current_par.montype > NR_MONTYPES)
- current_par.montype = 1;
+#if defined(CONFIG_SA1100_ASSABET) && defined(ASSABET_PAL_VIDEO)
+ if (machine_is_assabet())
+ BCR_clear(BCR_LCD_ON);
+#endif
- if (request_irq(IRQ_LCD, sa1100fb_inter_handler, SA_INTERRUPT, "SA1100 LCD", NULL) != 0) {
- printk(KERN_ERR "sa1100fb: failed in request_irq\n");
- return -EBUSY;
+#ifdef CONFIG_SA1100_FREEBIRD
+#error Please move this into sa1100fb_power_up_lcd
+ if (machine_is_freebird()) {
+ BCR_set(BCR_FREEBIRD_LCD_DISP);
+ mdelay(20);
+ BCR_set(BCR_FREEBIRD_LCD_PWR);
+ mdelay(20);
}
- DPRINTK("sa1100fb: request_irq succeeded\n");
- disable_irq(IRQ_LCD);
+#endif
- if (machine_is_assabet()) {
- GPDR |= 0x3fc;
- GAFR |= 0x3fc;
- sa1100fb_assabet_set_truecolor(current_par.visual ==
- FB_VISUAL_TRUECOLOR);
- } else if (machine_is_pangolin()) {
- GPDR |= 0x3fc;
- GAFR |= 0x3fc;
- } else if (machine_is_bitsy()) {
- GPDR = (GPIO_LDD15 | GPIO_LDD14 | GPIO_LDD13 | GPIO_LDD12 | GPIO_LDD11 | GPIO_LDD10 | GPIO_LDD9 | GPIO_LDD8);
- GAFR |= (GPIO_LDD15 | GPIO_LDD14 | GPIO_LDD13 | GPIO_LDD12 | GPIO_LDD11 | GPIO_LDD10 | GPIO_LDD9 | GPIO_LDD8);
- } else if (machine_is_cerf()) {
- GPDR |= 0x3fc;
- GAFR |= 0x3fc;
- } else if (machine_is_xp860()) {
- GPDR |= 0x3fc;
- GAFR |= 0x3fc;
- }
+ sa1100fb_set_var(&fbi->fb.var, -1, &fbi->fb);
- if (sa1100fb_set_var(&init_var, -1, &fb_info))
- current_par.allow_modeset = 0;
- sa1100fb_decode_var(&init_var, ¤t_par);
+ ret = register_framebuffer(&fbi->fb);
+ if (ret < 0)
+ goto failed;
+
+#ifdef CONFIG_PM
+ /*
+ * Note that the console registers this as well, but we want to
+ * power down the display prior to sleeping.
+ */
+ fbi->pm = pm_register(PM_SYS_DEV, PM_SYS_VGA, sa1100fb_pm_callback);
+ if (fbi->pm)
+ fbi->pm->data = fbi;
+#endif
+#ifdef CONFIG_CPU_FREQ
+ fbi->clockchg.notifier_call = sa1100fb_clkchg_notifier;
+ cpufreq_register_notifier(&fbi->clockchg);
+#endif
- register_framebuffer(&fb_info);
+ /*
+ * Ok, now enable the LCD controller
+ */
+ set_ctrlr_state(fbi, C_ENABLE);
/* This driver cannot be unloaded at the moment */
MOD_INC_USE_COUNT;
return 0;
+
+failed:
+ if (fbi)
+ kfree(fbi);
+ return ret;
}
int __init sa1100fb_setup(char *options)
{
+#if 0
char *this_opt;
if (!options || !*options)
for (this_opt = strtok(options, ","); this_opt;
this_opt = strtok(NULL, ",")) {
- if (!strncmp(this_opt, "bpp:", 4))
- current_par.max_bpp = simple_strtoul(this_opt+4, NULL, 0);
-
- if (!strncmp(this_opt, "lccr0:", 6))
- lcd_shadow.lccr0 = simple_strtoul(this_opt+6, NULL, 0);
- if (!strncmp(this_opt, "lccr1:", 6)) {
- lcd_shadow.lccr1 = simple_strtoul(this_opt+6, NULL, 0);
- current_par.max_xres = (lcd_shadow.lccr1 & 0x3ff) + 16;
- }
- if (!strncmp(this_opt, "lccr2:", 6)) {
- lcd_shadow.lccr2 = simple_strtoul(this_opt+6, NULL, 0);
- current_par.max_yres = (lcd_shadow.lccr0 & LCCR0_SDS) ?
- ((lcd_shadow.lccr2 & 0x3ff) + 1) * 2 :
- ((lcd_shadow.lccr2 & 0x3ff) + 1);
- }
- if (!strncmp(this_opt, "lccr3:", 6))
- lcd_shadow.lccr3 = simple_strtoul(this_opt+6, NULL, 0);
+ if (!strncmp(this_opt, "bpp:", 4))
+ current_par.max_bpp =
+ simple_strtoul(this_opt + 4, NULL, 0);
+
+ if (!strncmp(this_opt, "lccr0:", 6))
+ lcd_shadow.lccr0 =
+ simple_strtoul(this_opt + 6, NULL, 0);
+ if (!strncmp(this_opt, "lccr1:", 6)) {
+ lcd_shadow.lccr1 =
+ simple_strtoul(this_opt + 6, NULL, 0);
+ current_par.max_xres =
+ (lcd_shadow.lccr1 & 0x3ff) + 16;
+ }
+ if (!strncmp(this_opt, "lccr2:", 6)) {
+ lcd_shadow.lccr2 =
+ simple_strtoul(this_opt + 6, NULL, 0);
+ current_par.max_yres =
+ (lcd_shadow.
+ lccr0 & LCCR0_SDS) ? ((lcd_shadow.
+ lccr2 & 0x3ff) +
+ 1) *
+ 2 : ((lcd_shadow.lccr2 & 0x3ff) + 1);
+ }
+ if (!strncmp(this_opt, "lccr3:", 6))
+ lcd_shadow.lccr3 =
+ simple_strtoul(this_opt + 6, NULL, 0);
}
+#endif
return 0;
}
-
--- /dev/null
+/*
+ * linux/drivers/video/sa1100fb.h
+ * -- StrongARM 1100 LCD Controller Frame Buffer Device
+ *
+ * Copyright (C) 1999 Eric A. Thomas
+ * Based on acornfb.c Copyright (C) Russell King.
+ *
+ * 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.
+ */
+
+/*
+ * These are the bitfields for each
+ * display depth that we support.
+ */
+struct sa1100fb_rgb {
+ struct fb_bitfield red;
+ struct fb_bitfield green;
+ struct fb_bitfield blue;
+ struct fb_bitfield transp;
+};
+
+/*
+ * This structure describes the machine which we are running on.
+ */
+struct sa1100fb_mach_info {
+ u_long pixclock;
+
+ u_short xres;
+ u_short yres;
+
+ u_char bpp;
+ u_char hsync_len;
+ u_char left_margin;
+ u_char right_margin;
+
+ u_char vsync_len;
+ u_char upper_margin;
+ u_char lower_margin;
+ u_char sync;
+
+ u_int cmap_greyscale:1,
+ cmap_inverse:1,
+ cmap_static:1,
+ unused:29;
+
+ u_int lccr0;
+ u_int lccr3;
+};
+
+/* Shadows for LCD controller registers */
+struct sa1100fb_lcd_reg {
+ Word lccr0;
+ Word lccr1;
+ Word lccr2;
+ Word lccr3;
+};
+
+#define RGB_8 (0)
+#define RGB_16 (1)
+#define NR_RGB 2
+
+struct sa1100fb_info {
+ struct fb_info fb;
+ signed int currcon;
+
+ struct sa1100fb_rgb *rgb[NR_RGB];
+
+ u_int max_bpp;
+ u_int max_xres;
+ u_int max_yres;
+
+ /*
+ * These are the addresses we mapped
+ * the framebuffer memory region to.
+ */
+ dma_addr_t map_dma;
+ u_char * map_cpu;
+ u_int map_size;
+
+ u_char * screen_cpu;
+ dma_addr_t screen_dma;
+ u16 * palette_cpu;
+ dma_addr_t palette_dma;
+ u_int palette_size;
+
+ dma_addr_t dbar1;
+ dma_addr_t dbar2;
+
+ u_int lccr0;
+ u_int lccr3;
+ u_int cmap_inverse:1,
+ cmap_static:1,
+ unused:30;
+
+ u_int reg_lccr0;
+ u_int reg_lccr1;
+ u_int reg_lccr2;
+ u_int reg_lccr3;
+
+ volatile u_char state;
+ volatile u_char task_state;
+ struct semaphore ctrlr_sem;
+ wait_queue_head_t ctrlr_wait;
+ struct tq_struct task;
+
+#ifdef CONFIG_PM
+ struct pm_dev *pm;
+#endif
+#ifdef CONFIG_CPU_FREQ
+ struct notifier_block clockchg;
+#endif
+};
+
+#define __type_entry(ptr,type,member) ((type *)((char *)(ptr)-offsetof(type,member)))
+
+#define TO_INF(ptr,member) __type_entry(ptr,struct sa1100fb_info,member)
+
+#define SA1100_PALETTE_MODE_VAL(bpp) (((bpp) & 0x018) << 9)
+
+/*
+ * These are the actions for set_ctrlr_state
+ */
+#define C_DISABLE (0)
+#define C_ENABLE (1)
+#define C_DISABLE_CLKCHANGE (2)
+#define C_ENABLE_CLKCHANGE (3)
+#define C_REENABLE (4)
+
+#define SA1100_NAME "SA1100"
+
+/*
+ * Debug macros
+ */
+#if DEBUG
+# define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ## args)
+#else
+# define DPRINTK(fmt, args...)
+#endif
+
+/*
+ * Minimum X and Y resolutions
+ */
+#define MIN_XRES 64
+#define MIN_YRES 64
+
#include <linux/smp_lock.h>
#include "hpfs_fn.h"
+#define BLOCKS(size) (((size) + 511) >> 9)
+
/* HUH? */
int hpfs_open(struct inode *i, struct file *f)
{
unsigned n, disk_secno;
struct fnode *fnode;
struct buffer_head *bh;
- if (((inode->i_size + 511) >> 9) <= file_secno) return 0;
+ if (BLOCKS(inode->u.hpfs_i.mmu_private) <= file_secno) return 0;
n = file_secno - inode->i_hpfs_file_sec;
if (n < inode->i_hpfs_n_secs) return inode->i_hpfs_disk_sec + n;
if (!(fnode = hpfs_map_fnode(inode->i_sb, inode->i_ino, &bh))) return 0;
static struct file_operations hpfs_file_ops =
{
+ llseek: generic_file_llseek,
read: generic_file_read,
write: hpfs_file_write,
mmap: generic_file_mmap,
static int nfs_file_release(struct inode *, struct file *);
struct file_operations nfs_file_operations = {
+ llseek: generic_file_llseek,
read: nfs_file_read,
write: nfs_file_write,
mmap: nfs_file_mmap,
* the name matching the specified inode number.
*/
static int filldir_one(void * __buf, const char * name, int len,
- off_t pos, ino_t ino, unsigned int d_type)
+ loff_t pos, ino_t ino, unsigned int d_type)
{
struct nfsd_getdents_callback *buf = __buf;
struct qstr *qs = buf->name;
* the coh filesystem.
*/
struct file_operations sysv_file_operations = {
+ llseek: generic_file_llseek,
read: generic_file_read,
write: generic_file_write,
mmap: generic_file_mmap,
* We have mostly NULL's here: the current defaults are ok for
* the ufs filesystem.
*/
+
struct file_operations ufs_file_operations = {
llseek: ufs_file_lseek,
read: generic_file_read,
write: generic_file_write,
mmap: generic_file_mmap,
+ open: generic_file_open,
};
struct inode_operations ufs_file_inode_operations = {
#define LCCR1_DisWdth(Pixel) /* Display Width [16..1024 pix.] */ \
(((Pixel) - 16)/16 << FShft (LCCR1_PPL))
#define LCCR1_HSW Fld (6, 10) /* Horizontal Synchronization */
- /* pulse Width - 1 [Tpix] (L_LCLK) */
+ /* pulse Width - 1 [Tpix] (L_LCLK) */
#define LCCR1_HorSnchWdth(Tpix) /* Horizontal Synchronization */ \
- /* pulse Width [1..64 Tpix] */ \
- (((Tpix) - 1) << FShft (LCCR1_HSW))
+ /* pulse Width [1..64 Tpix] */ \
+ (((Tpix) - 1) << FShft (LCCR1_HSW))
#define LCCR1_ELW Fld (8, 16) /* End-of-Line pixel clock Wait */
/* count - 1 [Tpix] */
#define LCCR1_EndLnDel(Tpix) /* End-of-Line Delay */ \
#define NEPONSET_USAR_IRQ MISC_IRQ1
#define NEPONSET_CPLD_BASE (0x10000000)
-#define Nep_p2v( x ) ((x) - NEPONSET_CPLD_BASE + 0xf0000000)
-#define Nep_v2p( x ) ((x) - 0xf0000000 + NEPONSET_CPLD_BASE)
+#define Nep_p2v( x ) ((x) - NEPONSET_CPLD_BASE + 0xf3000000)
+#define Nep_v2p( x ) ((x) - 0xf3000000 + NEPONSET_CPLD_BASE)
#define _IRR 0x10000024 /* Interrupt Reason Register */
#define _AUD_CTL 0x100000c0 /* Audio controls (RW) */
hw_regs_t hw;
/* Enable GPIO as interrupt line */
- GPDR &= ~GPIO_GPIO1;
- set_GPIO_IRQ_edge(GPIO_GPIO1, GPIO_RISING_EDGE);
+ GPDR &= ~LART_GPIO_IDE;
+ set_GPIO_IRQ_edge(LART_GPIO_IDE, GPIO_RISING_EDGE);
/* set PCMCIA interface timing */
MECR = 0x00060006;
/* init the interface */
ide_init_hwif_ports(&hw, PCMCIA_IO_0_BASE + 0x0000, PCMCIA_IO_0_BASE + 0x1000, NULL);
- hw.irq = IRQ_GPIO1;
+ hw.irq = LART_IRQ_IDE;
ide_register_hw(&hw, NULL);
#endif
}
#ifndef _INCLUDE_LART_H
#define _INCLUDE_LART_H
-#define GPIO_UCB1200_IRQ GPIO_GPIO (18)
-#define IRQ_GPIO_UCB1200_IRQ IRQ_GPIO18
+#define LART_GPIO_ETH0 GPIO_GPIO0
+#define LART_IRQ_ETH0 IRQ_GPIO0
+
+#define LART_GPIO_IDE GPIO_GPIO1
+#define LART_IRQ_IDE IRQ_GPIO1
+
+#define LART_GPIO_UCB1200 GPIO_GPIO18
+#define LART_IRQ_UCB1200 IRQ_GPIO18
#endif
#define SA1100_UART1_EXT \
(struct huw_irq_desc){GPIO_UART1_CTS, IRQ_UART1_CTS, \
- GPIO_UART1_DCD, IRQ_UART1_DCD, \
- GPIO_UART1_DSR, IRQ_UART1_DSR}
+ GPIO_UART1_DCD, IRQ_UART1_DCD, \
+ GPIO_UART1_DSR, IRQ_UART1_DSR}
#define SA1100_UART3_EXT \
(struct huw_irq_desc){GPIO_UART3_CTS, IRQ_UART3_CTS, \
- GPIO_UART3_DCD, IRQ_UART3_DCD, \
- GPIO_UART3_DSR, IRQ_UART3_DSR}
+ GPIO_UART3_DCD, IRQ_UART3_DCD, \
+ GPIO_UART3_DSR, IRQ_UART3_DSR}
/*--- PCMCIA ---*/
#include <asm/arch/keyboard.h>
+#ifndef kbd_rate
+struct kbd_repeat;
+
+extern int kbd_rate(struct kbd_repeat *rate) __attribute__((weak));
+#endif
+
#endif /* __KERNEL__ */
#endif /* __ASM_ARM_KEYBOARD_H */
* cache entries for the kernels virtual memory range are written
* back to the page.
*/
-extern void check_pgcache_dirty(struct page *page);
-
-#define update_mmu_cache(vma,address,pte) check_pgcache_dirty(pte_page(pte))
-
+extern void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, pte_t pte);
ids->size = 0;
}
ids->ary = SPIN_LOCK_UNLOCKED;
- for(i=0;i<size;i++)
+ for(i=0;i<ids->size;i++)
ids->entries[i].p = NULL;
}
EXPORT_SYMBOL(vfs_rename);
EXPORT_SYMBOL(vfs_statfs);
EXPORT_SYMBOL(generic_read_dir);
+EXPORT_SYMBOL(generic_file_llseek);
+EXPORT_SYMBOL(no_llseek);
EXPORT_SYMBOL(__pollwait);
EXPORT_SYMBOL(poll_freewait);
EXPORT_SYMBOL(ROOT_DEV);