Commit 916e723b authored by Andy Grover's avatar Andy Grover

Merge groveronline.com:/root/bk/linux-2.5

into groveronline.com:/root/bk/linux-acpi
parents 81442037 eb40c469
......@@ -140,7 +140,7 @@ understand what the function is all about, you should adhere to the
maximum limits all the more closely. Use helper functions with
descriptive names (you can ask the compiler to in-line them if you think
it's performance-critical, and it will probably do a better job of it
that you would have done).
than you would have done).
Another measure of the function is the number of local variables. They
shouldn't exceed 5-10, or you're doing something wrong. Re-think the
......@@ -200,7 +200,7 @@ automagically when you edit source files under /usr/src/linux.
But even if you fail in getting emacs to do sane formatting, not
everything is lost: use "indent".
Now, again, GNU indent has the same brain dead settings that GNU emacs
Now, again, GNU indent has the same brain-dead settings that GNU emacs
has, which is why you need to give it a few command line options.
However, that's not too bad, because even the makers of GNU indent
recognize the authority of K&R (the GNU people aren't evil, they are
......@@ -232,7 +232,7 @@ fi
Generally, CONFIG_EXPERIMENTAL should surround all options not considered
stable. All options that are known to trash data (experimental write-
support for file-systems, for instance) should be denoted (DANGEROUS), other
Experimental options should be denoted (EXPERIMENTAL).
experimental options should be denoted (EXPERIMENTAL).
Chapter 8: Data structures
......@@ -258,7 +258,7 @@ when there are users of different "classes". The subclass count counts
the number of subclass users, and decrements the global count just once
when the subclass count goes to zero.
Examples of this kind of "multi-reference-counting" can be found in
Examples of this kind of "multi-level-reference-counting" can be found in
memory management ("struct mm_struct": mm_users and mm_count), and in
filesystem code ("struct super_block": s_count and s_active).
......
......@@ -973,7 +973,7 @@ M: scott.feldman@intel.com
S: Supported
INTERMEZZO FILE SYSTEM
P: Chen Yang
P: Cluster File Systems
M: intermezzo-devel@lists.sf.net
W: http://www.inter-mezzo.org/
L: intermezzo-discuss@lists.sourceforge.net
......
VERSION = 2
PATCHLEVEL = 5
SUBLEVEL = 75
EXTRAVERSION =
PATCHLEVEL = 6
SUBLEVEL = 0
EXTRAVERSION = -test1
# *DOCUMENTATION*
# To see a list of typical targets execute "make help"
......
......@@ -269,17 +269,6 @@ config ISA
(MCA) or VESA. ISA is an older system, now being displaced by PCI;
newer boards don't support it. If you have ISA, say Y, otherwise N.
config SBUS
bool
config MCA
bool
help
MicroChannel Architecture is found in some IBM PS/2 machines and
laptops. It is a bus system similar to PCI or ISA. See
<file:Documentation/mca.txt> (and especially the web page given
there) before attempting to build an MCA bus kernel.
config PCI
bool
depends on !ALPHA_JENSEN
......
......@@ -443,6 +443,7 @@ sys_call_table:
.quad sys_clock_getres
.quad sys_clock_nanosleep
.quad sys_semtimedop
.quad sys_tgkill
.size sys_call_table, . - sys_call_table
.type sys_call_table, @object
......
......@@ -682,6 +682,21 @@ __initcall(balanced_irq_init);
#else /* !SMP */
static inline void move_irq(int irq) { }
void send_IPI_self(int vector)
{
unsigned int cfg;
/*
* Wait for idle.
*/
apic_wait_icr_idle();
cfg = APIC_DM_FIXED | APIC_DEST_SELF | vector | APIC_DEST_LOGICAL;
/*
* Send the IPI. The write to APIC_ICR fires this off.
*/
apic_write_around(APIC_ICR, cfg);
}
#endif /* defined(CONFIG_SMP) */
......
......@@ -357,25 +357,23 @@ int register_busmouse(struct busmouse *ops)
{
unsigned int msedev = MINOR_TO_MOUSE(ops->minor);
struct busmouse_data *mse;
int ret;
int ret = -EINVAL;
if (msedev >= NR_MICE) {
printk(KERN_ERR "busmouse: trying to allocate mouse on minor %d\n",
ops->minor);
return -EINVAL;
goto out;
}
ret = -ENOMEM;
mse = kmalloc(sizeof(*mse), GFP_KERNEL);
if (!mse)
return -ENOMEM;
goto out;
down(&mouse_sem);
ret = -EBUSY;
if (busmouse_data[msedev])
{
up(&mouse_sem);
kfree(mse);
return -EBUSY;
}
goto freemem;
memset(mse, 0, sizeof(*mse));
......@@ -386,14 +384,22 @@ int register_busmouse(struct busmouse *ops)
mse->lock = (spinlock_t)SPIN_LOCK_UNLOCKED;
init_waitqueue_head(&mse->wait);
busmouse_data[msedev] = mse;
ret = misc_register(&mse->miscdev);
if (!ret)
ret = msedev;
if (ret < 0)
goto freemem;
busmouse_data[msedev] = mse;
ret = msedev;
out:
up(&mouse_sem);
return ret;
freemem:
kfree(mse);
goto out;
}
/**
......
......@@ -3,7 +3,7 @@
*
* Watchdog driver for integrated watchdog in the SuperH processors.
*
* Copyright (C) 2001, 2002 Paul Mundt <lethal@0xd6.org>
* Copyright (C) 2001, 2002, 2003 Paul Mundt <lethal@linux-sh.org>
*
* 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
......@@ -12,6 +12,10 @@
*
* 14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
* Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
*
* 19-Apr-2002 Rob Radez <rob@osinvestor.com>
* Added expect close support, made emulated timeout runtime changeable
* general cleanups, add some ioctls
*/
#include <linux/config.h>
#include <linux/module.h>
......@@ -22,76 +26,50 @@
#include <linux/reboot.h>
#include <linux/notifier.h>
#include <linux/ioport.h>
#include <linux/fs.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#if defined(CONFIG_CPU_SH5)
#define WTCNT CPRC_BASE + 0x10
#define WTCSR CPRC_BASE + 0x18
#elif defined(CONFIG_CPU_SH4)
#define WTCNT 0xffc00008
#define WTCSR 0xffc0000c
#elif defined(CONFIG_CPU_SH3)
#define WTCNT 0xffffff84
#define WTCSR 0xffffff86
#else
#error "Can't use SuperH watchdog on this platform"
#endif
#define WTCNT_HIGH 0x5a00
#define WTCSR_HIGH 0xa500
#define WTCSR_TME 0x80
#define WTCSR_WT 0x40
#define WTCSR_RSTS 0x20
#define WTCSR_WOVF 0x10
#define WTCSR_IOVF 0x08
#define WTCSR_CKS2 0x04
#define WTCSR_CKS1 0x02
#define WTCSR_CKS0 0x01
#include <asm/watchdog.h>
/*
* CKS0-2 supports a number of clock division ratios. At the time the watchdog
* is enabled, it defaults to a 41 usec overflow period .. we overload this to
* something a little more reasonable, and really can't deal with anything
* lower than WTCSR_CKS_1024, else we drop back into the usec range.
* Default clock division ratio is 5.25 msecs. For an additional table of
* values, consult the asm-sh/watchdog.h. Overload this at module load
* time.
*
* Clock Division Ratio Overflow Period
* --------------------------------------------
* 1/32 (initial value) 41 usecs
* 1/64 82 usecs
* 1/128 164 usecs
* 1/256 328 usecs
* 1/512 656 usecs
* 1/1024 1.31 msecs
* 1/2048 2.62 msecs
* 1/4096 5.25 msecs
*/
#define WTCSR_CKS_32 0x00
#define WTCSR_CKS_64 0x01
#define WTCSR_CKS_128 0x02
#define WTCSR_CKS_256 0x03
#define WTCSR_CKS_512 0x04
#define WTCSR_CKS_1024 0x05
#define WTCSR_CKS_2048 0x06
#define WTCSR_CKS_4096 0x07
/*
* Default clock division ratio is 5.25 msecs. Overload this at module load
* time. Any value not in the msec range will default to a timeout of one
* jiffy, which exceeds the usec overflow periods.
* In order for this to work reliably we need to have HZ set to 1000 or
* something quite higher than 100 (or we need a proper high-res timer
* implementation that will deal with this properly), otherwise the 10ms
* resolution of a jiffy is enough to trigger the overflow. For things like
* the SH-4 and SH-5, this isn't necessarily that big of a problem, though
* for the SH-2 and SH-3, this isn't recommended unless the WDT is absolutely
* necssary.
*
* As a result of this timing problem, the only modes that are particularly
* feasible are the 4096 and the 2048 divisors, which yeild 5.25 and 2.62ms
* overflow periods respectively.
*
* Also, since we can't really expect userspace to be responsive enough
* before the overflow happens, we maintain two seperate timers .. One in
* the kernel for clearing out WOVF every 2ms or so (again, this depends on
* HZ == 1000), and another for monitoring userspace writes to the WDT device.
*
* As such, we currently use a configurable heartbeat interval which defaults
* to 30s. In this case, the userspace daemon is only responsible for periodic
* writes to the device before the next heartbeat is scheduled. If the daemon
* misses its deadline, the kernel timer will allow the WDT to overflow.
*/
static int clock_division_ratio = WTCSR_CKS_4096;
#define msecs_to_jiffies(msecs) (jiffies + ((HZ * msecs + 999) / 1000))
#define msecs_to_jiffies(msecs) (jiffies + (HZ * msecs + 9999) / 10000)
#define next_ping_period(cks) msecs_to_jiffies(cks - 4)
#define user_ping_period(cks) (next_ping_period(cks) * 10)
static unsigned long sh_is_open = 0;
static unsigned long shwdt_is_open;
static struct watchdog_info sh_wdt_info;
static char shwdt_expect_close;
static struct timer_list timer;
static unsigned long next_heartbeat;
static int heartbeat = 30;
#ifdef CONFIG_WATCHDOG_NOWAYOUT
static int nowayout = 1;
......@@ -99,35 +77,6 @@ static int nowayout = 1;
static int nowayout = 0;
#endif
MODULE_PARM(nowayout,"i");
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
/**
* sh_wdt_write_cnt - Write to Counter
*
* @val: Value to write
*
* Writes the given value @val to the lower byte of the timer counter.
* The upper byte is set manually on each write.
*/
static void sh_wdt_write_cnt(__u8 val)
{
ctrl_outw(WTCNT_HIGH | (__u16)val, WTCNT);
}
/**
* sh_wdt_write_csr - Write to Control/Status Register
*
* @val: Value to write
*
* Writes the given value @val to the lower byte of the control/status
* register. The upper byte is set manually on each write.
*/
static void sh_wdt_write_csr(__u8 val)
{
ctrl_outw(WTCSR_HIGH | (__u16)val, WTCSR);
}
/**
* sh_wdt_start - Start the Watchdog
*
......@@ -135,13 +84,44 @@ static void sh_wdt_write_csr(__u8 val)
*/
static void sh_wdt_start(void)
{
timer.expires = next_ping_period(clock_division_ratio);
next_heartbeat = user_ping_period(clock_division_ratio);
add_timer(&timer);
__u8 csr;
mod_timer(&timer, next_ping_period(clock_division_ratio));
next_heartbeat = jiffies + (heartbeat * HZ);
csr = sh_wdt_read_csr();
csr |= WTCSR_WT | clock_division_ratio;
sh_wdt_write_csr(csr);
sh_wdt_write_csr(WTCSR_WT | WTCSR_CKS_4096);
sh_wdt_write_cnt(0);
sh_wdt_write_csr((ctrl_inb(WTCSR) | WTCSR_TME));
/*
* These processors have a bit of an inconsistent initialization
* process.. starting with SH-3, RSTS was moved to WTCSR, and the
* RSTCSR register was removed.
*
* On the SH-2 however, in addition with bits being in different
* locations, we must deal with RSTCSR outright..
*/
csr = sh_wdt_read_csr();
csr |= WTCSR_TME;
csr &= ~WTCSR_RSTS;
sh_wdt_write_csr(csr);
#ifdef CONFIG_CPU_SH2
/*
* Whoever came up with the RSTCSR semantics must've been smoking
* some of the good stuff, since in addition to the WTCSR/WTCNT write
* brain-damage, it's managed to fuck things up one step further..
*
* If we need to clear the WOVF bit, the upper byte has to be 0xa5..
* but if we want to touch RSTE or RSTS, the upper byte has to be
* 0x5a..
*/
csr = sh_wdt_read_rstcsr();
csr &= ~RSTCSR_RSTS;
sh_wdt_write_rstcsr(csr);
#endif
}
/**
......@@ -151,9 +131,13 @@ static void sh_wdt_start(void)
*/
static void sh_wdt_stop(void)
{
__u8 csr;
del_timer(&timer);
sh_wdt_write_csr((ctrl_inb(WTCSR) & ~WTCSR_TME));
csr = sh_wdt_read_csr();
csr &= ~WTCSR_TME;
sh_wdt_write_csr(csr);
}
/**
......@@ -166,11 +150,15 @@ static void sh_wdt_stop(void)
static void sh_wdt_ping(unsigned long data)
{
if (time_before(jiffies, next_heartbeat)) {
sh_wdt_write_csr((ctrl_inb(WTCSR) & ~WTCSR_IOVF));
__u8 csr;
csr = sh_wdt_read_csr();
csr &= ~WTCSR_IOVF;
sh_wdt_write_csr(csr);
sh_wdt_write_cnt(0);
timer.expires = next_ping_period(clock_division_ratio);
add_timer(&timer);
mod_timer(&timer, next_ping_period(clock_division_ratio));
}
}
......@@ -184,21 +172,12 @@ static void sh_wdt_ping(unsigned long data)
*/
static int sh_wdt_open(struct inode *inode, struct file *file)
{
switch (minor(inode->i_rdev)) {
case WATCHDOG_MINOR:
if (test_and_set_bit(0, &sh_is_open))
return -EBUSY;
if (test_and_set_bit(0, &shwdt_is_open))
return -EBUSY;
if (nowayout)
MOD_INC_USE_COUNT;
if (nowayout) {
MOD_INC_USE_COUNT;
}
sh_wdt_start();
break;
default:
return -ENODEV;
}
sh_wdt_start();
return 0;
}
......@@ -213,32 +192,19 @@ static int sh_wdt_open(struct inode *inode, struct file *file)
*/
static int sh_wdt_close(struct inode *inode, struct file *file)
{
if (minor(inode->i_rdev) == WATCHDOG_MINOR) {
if (!nowayout) {
sh_wdt_stop();
}
clear_bit(0, &sh_is_open);
if (!nowayout && shwdt_expect_close == 42) {
sh_wdt_stop();
} else {
printk(KERN_CRIT "shwdt: Unexpected close, not stopping watchdog!\n");
next_heartbeat = jiffies + (heartbeat * HZ);
}
clear_bit(0, &shwdt_is_open);
shwdt_expect_close = 0;
return 0;
}
/**
* sh_wdt_read - Read from Device
*
* @file: file handle of device
* @buf: buffer to write to
* @count: length of buffer
* @ppos: offset
*
* Unsupported.
*/
static ssize_t sh_wdt_read(struct file *file, char *buf,
size_t count, loff_t *ppos)
{
return -EINVAL;
}
/**
* sh_wdt_write - Write to Device
*
......@@ -257,11 +223,21 @@ static ssize_t sh_wdt_write(struct file *file, const char *buf,
return -ESPIPE;
if (count) {
next_heartbeat = user_ping_period(clock_division_ratio);
return 1;
size_t i;
shwdt_expect_close = 0;
for (i = 0; i != count; i++) {
char c;
if (get_user(c, buf + i))
return -EFAULT;
if (c == 'V')
shwdt_expect_close = 42;
}
next_heartbeat = jiffies + (heartbeat * HZ);
}
return 0;
return count;
}
/**
......@@ -278,6 +254,8 @@ static ssize_t sh_wdt_write(struct file *file, const char *buf,
static int sh_wdt_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
int new_timeout;
switch (cmd) {
case WDIOC_GETSUPPORT:
if (copy_to_user((struct watchdog_info *)arg,
......@@ -288,17 +266,41 @@ static int sh_wdt_ioctl(struct inode *inode, struct file *file,
break;
case WDIOC_GETSTATUS:
if (copy_to_user((int *)arg,
&sh_is_open,
sizeof(int))) {
case WDIOC_GETBOOTSTATUS:
return put_user(0, (int *)arg);
case WDIOC_KEEPALIVE:
next_heartbeat = jiffies + (heartbeat * HZ);
break;
case WDIOC_SETTIMEOUT:
if (get_user(new_timeout, (int *)arg))
return -EFAULT;
if (new_timeout < 1 || new_timeout > 3600) /* arbitrary upper limit */
return -EINVAL;
heartbeat = new_timeout;
next_heartbeat = jiffies + (heartbeat * HZ);
/* Fall */
case WDIOC_GETTIMEOUT:
return put_user(heartbeat, (int *)arg);
case WDIOC_SETOPTIONS:
{
int options, retval = -EINVAL;
if (get_user(options, (int *)arg))
return -EFAULT;
if (options & WDIOS_DISABLECARD) {
sh_wdt_stop();
retval = 0;
}
break;
case WDIOC_KEEPALIVE:
next_heartbeat = user_ping_period(clock_division_ratio);
if (options & WDIOS_ENABLECARD) {
sh_wdt_start();
retval = 0;
}
break;
return retval;
}
default:
return -ENOTTY;
}
......@@ -328,7 +330,7 @@ static int sh_wdt_notify_sys(struct notifier_block *this,
static struct file_operations sh_wdt_fops = {
.owner = THIS_MODULE,
.read = sh_wdt_read,
.llseek = no_llseek,
.write = sh_wdt_write,
.ioctl = sh_wdt_ioctl,
.open = sh_wdt_open,
......@@ -336,21 +338,20 @@ static struct file_operations sh_wdt_fops = {
};
static struct watchdog_info sh_wdt_info = {
.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
.firmware_version = 1,
.identity = "SH WDT",
.options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
.firmware_version = 1,
.identity = "SH WDT",
};
static struct notifier_block sh_wdt_notifier = {
.notifier_call = sh_wdt_notify_sys,
.next = NULL,
.priority = 0
.notifier_call = sh_wdt_notify_sys,
.priority = 0,
};
static struct miscdevice sh_wdt_miscdev = {
.minor = WATCHDOG_MINOR,
.name = "watchdog",
.fops &sh_wdt_fops,
.minor = WATCHDOG_MINOR,
.name = "watchdog",
.fops = &sh_wdt_fops,
};
/**
......@@ -366,23 +367,8 @@ static int __init sh_wdt_init(void)
return -EINVAL;
}
if (!request_region(WTCNT, 1, "shwdt")) {
printk(KERN_ERR "shwdt: Can't request WTCNT region\n");
misc_deregister(&sh_wdt_miscdev);
return -ENXIO;
}
if (!request_region(WTCSR, 1, "shwdt")) {
printk(KERN_ERR "shwdt: Can't request WTCSR region\n");
release_region(WTCNT, 1);
misc_deregister(&sh_wdt_miscdev);
return -ENXIO;
}
if (register_reboot_notifier(&sh_wdt_notifier)) {
printk(KERN_ERR "shwdt: Can't register reboot notifier\n");
release_region(WTCSR, 1);
release_region(WTCNT, 1);
misc_deregister(&sh_wdt_miscdev);
return -EINVAL;
}
......@@ -403,16 +389,16 @@ static int __init sh_wdt_init(void)
static void __exit sh_wdt_exit(void)
{
unregister_reboot_notifier(&sh_wdt_notifier);
release_region(WTCSR, 1);
release_region(WTCNT, 1);
misc_deregister(&sh_wdt_miscdev);
}
MODULE_AUTHOR("Paul Mundt <lethal@0xd6.org>");
MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>");
MODULE_DESCRIPTION("SuperH watchdog driver");
MODULE_LICENSE("GPL");
MODULE_PARM(clock_division_ratio, "i");
MODULE_PARM_DESC(clock_division_ratio, "Clock division ratio. Valid ranges are from 0x5 (1.31ms) to 0x7 (5.25ms). Defaults to 0x7.");
MODULE_PARM(nowayout,"i");
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
module_init(sh_wdt_init);
module_exit(sh_wdt_exit);
......
......@@ -161,7 +161,7 @@ static int debug;
* then put the packet into tx_queue, and call sppp_flush_xmit()
* after spinlock is released.
*/
static void sppp_flush_xmit()
static void sppp_flush_xmit(void)
{
struct sk_buff *skb;
while ((skb = skb_dequeue(&tx_queue)) != NULL)
......
......@@ -258,7 +258,7 @@ static int mtd_modify_window(window_handle_t win, mtd_mod_win_t *req)
win->ctl.flags |= MAP_ATTRIB;
win->ctl.speed = req->AccessSpeed;
win->ctl.card_start = req->CardOffset;
win->sock->ss_entry->set_mem_map(win->sock, &win->ctl);
win->sock->ops->set_mem_map(win->sock, &win->ctl);
return CS_SUCCESS;
}
......@@ -271,7 +271,7 @@ static int mtd_set_vpp(client_handle_t handle, mtd_vpp_req_t *req)
return CS_BAD_VPP;
s = SOCKET(handle);
s->socket.Vpp = req->Vpp1;
if (s->ss_entry->set_socket(s, &s->socket))
if (s->ops->set_socket(s, &s->socket))
return CS_BAD_VPP;
return CS_SUCCESS;
}
......@@ -286,7 +286,7 @@ static int mtd_rdy_mask(client_handle_t handle, mtd_rdy_req_t *req)
s->socket.csc_mask |= SS_READY;
else
s->socket.csc_mask &= ~SS_READY;
if (s->ss_entry->set_socket(s, &s->socket))
if (s->ops->set_socket(s, &s->socket))
return CS_GENERAL_FAILURE;
return CS_SUCCESS;
}
......
......@@ -86,7 +86,7 @@ void release_cis_mem(struct pcmcia_socket *s)
{
if (s->cis_mem.sys_start != 0) {
s->cis_mem.flags &= ~MAP_ACTIVE;
s->ss_entry->set_mem_map(s, &s->cis_mem);
s->ops->set_mem_map(s, &s->cis_mem);
if (!(s->features & SS_CAP_STATIC_MAP))
release_mem_region(s->cis_mem.sys_start, s->map_size);
iounmap(s->cis_virt);
......@@ -118,7 +118,7 @@ set_cis_map(struct pcmcia_socket *s, unsigned int card_offset, unsigned int flag
}
mem->card_start = card_offset;
mem->flags = flags;
s->ss_entry->set_mem_map(s, mem);
s->ops->set_mem_map(s, mem);
if (s->features & SS_CAP_STATIC_MAP) {
if (s->cis_virt)
iounmap(s->cis_virt);
......
......@@ -225,43 +225,6 @@ static const lookup_t service_table[] = {
};
#define SERVICE_COUNT (sizeof(service_table)/sizeof(lookup_t))
/*======================================================================
These functions are just shorthand for the actual low-level drivers
======================================================================*/
static int get_socket_status(struct pcmcia_socket *s, int *val)
{
return s->ss_entry->get_status(s, val);
}
static int set_socket(struct pcmcia_socket *s, socket_state_t *state)
{
return s->ss_entry->set_socket(s, state);
}
static int set_io_map(struct pcmcia_socket *s, struct pccard_io_map *io)
{
return s->ss_entry->set_io_map(s, io);
}
static int set_mem_map(struct pcmcia_socket *s, struct pccard_mem_map *mem)
{
return s->ss_entry->set_mem_map(s, mem);
}
static int suspend_socket(struct pcmcia_socket *s)
{
s->socket = dead_socket;
return s->ss_entry->suspend(s);
}
static int init_socket(struct pcmcia_socket *s)
{
s->socket = dead_socket;
return s->ss_entry->init(s);
}
/*====================================================================
......@@ -338,12 +301,14 @@ static int pcmcia_add_socket(struct class_device *class_dev)
socket->erase_busy.next = socket->erase_busy.prev = &socket->erase_busy;
INIT_LIST_HEAD(&socket->cis_cache);
spin_lock_init(&socket->lock);
init_completion(&socket->thread_done);
init_waitqueue_head(&socket->thread_wait);
init_MUTEX(&socket->skt_sem);
spin_lock_init(&socket->thread_lock);
init_socket(socket);
socket->socket = dead_socket;
socket->ops->init(socket);
ret = kernel_thread(pccardd, socket, CLONE_KERNEL);
if (ret < 0)
......@@ -373,7 +338,7 @@ static void pcmcia_remove_socket(struct class_device *class_dev)
socket->clients = socket->clients->next;
kfree(client);
}
socket->ss_entry = NULL;
socket->ops = NULL;
}
static void pcmcia_release_socket(struct class_device *class_dev)
......@@ -388,10 +353,10 @@ static void pcmcia_release_socket(struct class_device *class_dev)
*/
int pcmcia_register_socket(struct pcmcia_socket *socket)
{
if (!socket || !socket->ss_entry || !socket->dev.dev)
if (!socket || !socket->ops || !socket->dev.dev)
return -EINVAL;
DEBUG(0, "cs: pcmcia_register_socket(0x%p)\n", socket->ss_entry);
DEBUG(0, "cs: pcmcia_register_socket(0x%p)\n", socket->ops);
/* try to obtain a socket number [yes, it gets ugly if we
* register more than 2^sizeof(unsigned int) pcmcia
......@@ -443,7 +408,7 @@ void pcmcia_unregister_socket(struct pcmcia_socket *socket)
if (!socket)
return;
DEBUG(0, "cs: pcmcia_unregister_socket(0x%p)\n", socket->ss_entry);
DEBUG(0, "cs: pcmcia_unregister_socket(0x%p)\n", socket->ops);
init_completion(&socket->socket_released);
......@@ -510,7 +475,8 @@ static void shutdown_socket(struct pcmcia_socket *s)
/* Blank out the socket state */
s->state &= SOCKET_PRESENT|SOCKET_SETUP_PENDING;
init_socket(s);
s->socket = dead_socket;
s->ops->init(s);
s->irq.AssignedIRQ = s->irq.Config = 0;
s->lock_count = 0;
destroy_cis_cache(s);
......@@ -525,7 +491,7 @@ static void shutdown_socket(struct pcmcia_socket *s)
s->socket.Vpp = 0;
s->socket.Vcc = 0;
s->socket.io_irq = 0;
set_socket(s, &s->socket);
s->ops->set_socket(s, &s->socket);
/* */
#ifdef CONFIG_CARDBUS
cb_free(s);
......@@ -619,16 +585,16 @@ static int socket_reset(struct pcmcia_socket *skt)
int status, i;
skt->socket.flags |= SS_OUTPUT_ENA | SS_RESET;
set_socket(skt, &skt->socket);
skt->ops->set_socket(skt, &skt->socket);
udelay((long)reset_time);
skt->socket.flags &= ~SS_RESET;
set_socket(skt, &skt->socket);
skt->ops->set_socket(skt, &skt->socket);
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(cs_to_timeout(unreset_delay));
for (i = 0; i < unreset_limit; i++) {
get_socket_status(skt, &status);
skt->ops->get_status(skt, &status);
if (!(status & SS_DETECT))
return CS_NO_CARD;
......@@ -648,7 +614,7 @@ static int socket_setup(struct pcmcia_socket *skt, int initial_delay)
{
int status, i;
get_socket_status(skt, &status);
skt->ops->get_status(skt, &status);
if (!(status & SS_DETECT))
return CS_NO_CARD;
......@@ -656,7 +622,7 @@ static int socket_setup(struct pcmcia_socket *skt, int initial_delay)
schedule_timeout(cs_to_timeout(initial_delay));
for (i = 0; i < 100; i++) {
get_socket_status(skt, &status);
skt->ops->get_status(skt, &status);
if (!(status & SS_DETECT))
return CS_NO_CARD;
......@@ -693,7 +659,7 @@ static int socket_setup(struct pcmcia_socket *skt, int initial_delay)
}
skt->state |= SOCKET_PRESENT;
skt->socket.flags = SS_DEBOUNCED;
set_socket(skt, &skt->socket);
skt->ops->set_socket(skt, &skt->socket);
/*
* Wait "vcc_settle" for the supply to stabilise.
......@@ -739,7 +705,8 @@ static int socket_suspend(struct pcmcia_socket *skt)
return CS_IN_USE;
send_event(skt, CS_EVENT_PM_SUSPEND, CS_EVENT_PRI_LOW);
suspend_socket(skt);
skt->socket = dead_socket;
skt->ops->suspend(skt);
skt->state |= SOCKET_SUSPEND;
return CS_SUCCESS;
......@@ -757,7 +724,8 @@ static int socket_resume(struct pcmcia_socket *skt)
if (!(skt->state & SOCKET_SUSPEND))
return CS_IN_USE;
init_socket(skt);
skt->socket = dead_socket;
skt->ops->init(skt);
ret = socket_setup(skt, resume_delay);
if (ret == CS_SUCCESS) {
......@@ -811,7 +779,7 @@ static void socket_detect_change(struct pcmcia_socket *skt)
schedule_timeout(cs_to_timeout(2));
}
get_socket_status(skt, &status);
skt->ops->get_status(skt, &status);
if ((skt->state & SOCKET_PRESENT) &&
!(status & SS_DETECT))
socket_remove(skt);
......@@ -1368,7 +1336,7 @@ int pcmcia_get_status(client_handle_t handle, cs_status_t *status)
if (CHECK_HANDLE(handle))
return CS_BAD_HANDLE;
s = SOCKET(handle);
get_socket_status(s, &val);
s->ops->get_status(s, &val);
status->CardState = status->SocketState = 0;
status->CardState |= (val & SS_DETECT) ? CS_EVENT_CARD_DETECT : 0;
status->CardState |= (val & SS_CARDBUS) ? CS_EVENT_CB_DETECT : 0;
......@@ -1447,7 +1415,7 @@ int pcmcia_map_mem_page(window_handle_t win, memreq_t *req)
return CS_BAD_PAGE;
s = win->sock;
win->ctl.card_start = req->CardOffset;
if (set_mem_map(s, &win->ctl) != 0)
if (s->ops->set_mem_map(s, &win->ctl) != 0)
return CS_BAD_OFFSET;
return CS_SUCCESS;
} /* map_mem_page */
......@@ -1480,7 +1448,7 @@ int pcmcia_modify_configuration(client_handle_t handle,
c->Attributes &= ~CONF_ENABLE_IRQ;
s->socket.io_irq = 0;
}
set_socket(s, &s->socket);
s->ops->set_socket(s, &s->socket);
}
if (mod->Attributes & CONF_VCC_CHANGE_VALID)
......@@ -1492,7 +1460,7 @@ int pcmcia_modify_configuration(client_handle_t handle,
if (mod->Vpp1 != mod->Vpp2)
return CS_BAD_VPP;
c->Vpp1 = c->Vpp2 = s->socket.Vpp = mod->Vpp1;
if (set_socket(s, &s->socket))
if (s->ops->set_socket(s, &s->socket))
return CS_BAD_VPP;
} else if ((mod->Attributes & CONF_VPP1_CHANGE_VALID) ||
(mod->Attributes & CONF_VPP2_CHANGE_VALID))
......@@ -1522,7 +1490,7 @@ int pcmcia_modify_window(window_handle_t win, modwin_t *req)
if (req->Attributes & WIN_USE_WAIT)
win->ctl.flags |= MAP_USE_WAIT;
win->ctl.speed = req->AccessSpeed;
set_mem_map(win->sock, &win->ctl);
win->sock->ops->set_mem_map(win->sock, &win->ctl);
return CS_SUCCESS;
} /* modify_window */
......@@ -1622,7 +1590,7 @@ int pcmcia_release_configuration(client_handle_t handle)
s->socket.flags = SS_OUTPUT_ENA; /* Is this correct? */
s->socket.Vpp = 0;
s->socket.io_irq = 0;
set_socket(s, &s->socket);
s->ops->set_socket(s, &s->socket);
}
if (c->state & CONFIG_IO_REQ)
for (i = 0; i < MAX_IO_WIN; i++) {
......@@ -1632,7 +1600,7 @@ int pcmcia_release_configuration(client_handle_t handle)
if (s->io[i].Config != 0)
continue;
io.map = i;
set_io_map(s, &io);
s->ops->set_io_map(s, &io);
}
c->state &= ~CONFIG_LOCKED;
}
......@@ -1733,7 +1701,7 @@ int pcmcia_release_window(window_handle_t win)
/* Shut down memory window */
win->ctl.flags &= ~MAP_ACTIVE;
set_mem_map(s, &win->ctl);
s->ops->set_mem_map(s, &win->ctl);
s->state &= ~SOCKET_WIN_REQ(win->index);
/* Release system memory */
......@@ -1780,7 +1748,7 @@ int pcmcia_request_configuration(client_handle_t handle,
if (req->Vpp1 != req->Vpp2)
return CS_BAD_VPP;
s->socket.Vpp = req->Vpp1;
if (set_socket(s, &s->socket))
if (s->ops->set_socket(s, &s->socket))
return CS_BAD_VPP;
c->Vcc = req->Vcc; c->Vpp1 = c->Vpp2 = req->Vpp1;
......@@ -1798,7 +1766,7 @@ int pcmcia_request_configuration(client_handle_t handle,
s->socket.io_irq = s->irq.AssignedIRQ;
else
s->socket.io_irq = 0;
set_socket(s, &s->socket);
s->ops->set_socket(s, &s->socket);
s->lock_count++;
/* Set up CIS configuration registers */
......@@ -1863,7 +1831,7 @@ int pcmcia_request_configuration(client_handle_t handle,
}
iomap.start = s->io[i].BasePort;
iomap.stop = iomap.start + s->io[i].NumPorts - 1;
set_io_map(s, &iomap);
s->ops->set_io_map(s, &iomap);
s->io[i].Config++;
}
}
......@@ -2084,7 +2052,7 @@ int pcmcia_request_window(client_handle_t *handle, win_req_t *req, window_handle
win->ctl.sys_start = win->base;
win->ctl.sys_stop = win->base + win->size-1;
win->ctl.card_start = 0;
if (set_mem_map(s, &win->ctl) != 0)
if (s->ops->set_mem_map(s, &win->ctl) != 0)
return CS_BAD_ARGS;
s->state |= SOCKET_WIN_REQ(w);
......
......@@ -113,7 +113,7 @@ struct cis_cache_entry {
(((h) == NULL) || ((h)->client_magic != CLIENT_MAGIC))
#define CHECK_SOCKET(s) \
(((s) >= sockets) || (socket_table[s]->ss_entry == NULL))
(((s) >= sockets) || (socket_table[s]->ops == NULL))
#define SOCKET(h) (h->Socket)
#define CONFIG(h) (&SOCKET(h)->config[(h)->Function])
......
/*
* $Id$
* $Id: hd64465_ss.c,v 1.7 2003/07/06 14:42:50 lethal Exp $
*
* Device driver for the PCMCIA controller module of the
* Hitachi HD64465 handheld companion chip.
......@@ -24,7 +24,6 @@
*
* by Greg Banks <gbanks@pocketpenguins.com>
* (c) 2000 PocketPenguins Inc
*
*/
#include <linux/types.h>
......@@ -37,28 +36,26 @@
#include <linux/vmalloc.h>
#include <asm/errno.h>
#include <linux/irq.h>
#include <linux/workqueue.h>
#include <linux/interrupt.h>
#include <linux/device.h>
#include <asm/io.h>
#include <asm/hd64465.h>
#include <asm/hd64465/hd64465.h>
#include <asm/hd64465/io.h>
#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ds.h>
#include <pcmcia/ss.h>
#include <pcmcia/bulkmem.h>
#include <pcmcia/cistpl.h>
#include "cs_internal.h"
#define MODNAME "hd64465_ss"
/* #define HD64465_DEBUG 1 */
#ifndef HD64465_DEBUG
#define HD64465_DEBUG 0
#endif
#if HD64465_DEBUG
#define DPRINTK(args...) printk(MODNAME ": " args)
#else
......@@ -66,7 +63,8 @@
#endif
extern int hd64465_io_debug;
extern void * p3_ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags);
extern void p3_iounmap(void *addr);
/*============================================================*/
......@@ -74,37 +72,22 @@ extern int hd64465_io_debug;
typedef struct hs_socket_t
{
unsigned int number;
u_int irq;
u_long mem_base;
void *io_base;
u_long mem_length;
void (*handler)(void *info, u_int events);
void *handler_info;
u_int pending_events;
u_int ctrl_base;
socket_state_t state;
pccard_io_map io_maps[MAX_IO_WIN];
pccard_mem_map mem_maps[MAX_WIN];
struct vm_struct *io_vma; /* allocated kernel vm for mapping IO space */
struct pcmcia_socket socket;
} hs_socket_t;
#define HS_MAX_SOCKETS 2
static hs_socket_t hs_sockets[HS_MAX_SOCKETS];
static spinlock_t hs_pending_event_lock = SPIN_LOCK_UNLOCKED;
/* Calculate socket number from ptr into hs_sockets[] */
#define hs_sockno(sp) (sp - hs_sockets)
static socket_cap_t hs_socket_cap =
{
SS_CAP_PCCARD /* support 16 bit cards */
|SS_CAP_STATIC_MAP /* mappings are fixed in host memory */
,
0xffde/*0xffff*/, /* IRQs mapped in s/w so can do any, really */
HD64465_PCC_WINDOW, /* 16MB fixed window size */
0, /* no PCI support */
0, /* no CardBus support */
0 /* no bus operations needed */
};
#define HS_MAX_SOCKETS 2
static hs_socket_t hs_sockets[HS_MAX_SOCKETS];
#define hs_in(sp, r) inb((sp)->ctrl_base + (r))
#define hs_out(sp, v, r) outb(v, (sp)->ctrl_base + (r))
......@@ -179,7 +162,7 @@ static void hs_socket_enable_ireq(hs_socket_t *sp)
{
unsigned short cscier;
DPRINTK("hs_socket_enable_ireq(sock=%d)\n", hs_sockno(sp));
DPRINTK("hs_socket_enable_ireq(sock=%d)\n", sp->number);
cscier = hs_in(sp, CSCIER);
cscier &= ~HD64465_PCCCSCIER_PIREQE_MASK;
......@@ -191,7 +174,7 @@ static void hs_socket_disable_ireq(hs_socket_t *sp)
{
unsigned short cscier;
DPRINTK("hs_socket_disable_ireq(sock=%d)\n", hs_sockno(sp));
DPRINTK("hs_socket_disable_ireq(sock=%d)\n", sp->number);
cscier = hs_in(sp, CSCIER);
cscier &= ~HD64465_PCCCSCIER_PIREQE_MASK;
......@@ -255,7 +238,7 @@ static struct hw_interrupt_type hd64465_ss_irq_type = {
*/
static void hs_map_irq(hs_socket_t *sp, unsigned int irq)
{
DPRINTK("hs_map_irq(sock=%d irq=%d)\n", hs_sockno(sp), irq);
DPRINTK("hs_map_irq(sock=%d irq=%d)\n", sp->number, irq);
if (irq >= HS_NUM_MAPPED_IRQS)
return;
......@@ -272,7 +255,7 @@ static void hs_map_irq(hs_socket_t *sp, unsigned int irq)
*/
static void hs_unmap_irq(hs_socket_t *sp, unsigned int irq)
{
DPRINTK("hs_unmap_irq(sock=%d irq=%d)\n", hs_sockno(sp), irq);
DPRINTK("hs_unmap_irq(sock=%d irq=%d)\n", sp->number, irq);
if (irq >= HS_NUM_MAPPED_IRQS)
return;
......@@ -301,7 +284,7 @@ static int hs_set_voltages(hs_socket_t *sp, int Vcc, int Vpp)
{
u_int psr;
u_int vcci = 0;
u_int sock = hs_sockno(sp);
u_int sock = sp->number;
DPRINTK("hs_set_voltage(%d, %d, %d)\n", sock, Vcc, Vpp);
......@@ -359,13 +342,12 @@ static void hs_reset_socket(hs_socket_t *sp, int on)
/*============================================================*/
static int hs_init(unsigned int sock)
static int hs_init(struct pcmcia_socket *s)
{
hs_socket_t *sp = &hs_sockets[sock];
hs_socket_t *sp = container_of(s, struct hs_socket_t, socket);
DPRINTK("hs_init(%d)\n", sock);
DPRINTK("hs_init(%d)\n", sp->number);
sp->pending_events = 0;
sp->state.Vcc = 0;
sp->state.Vpp = 0;
hs_set_voltages(sp, 0, 0);
......@@ -375,9 +357,12 @@ static int hs_init(unsigned int sock)
/*============================================================*/
static int hs_suspend(unsigned int sock)
static int hs_suspend(struct pcmcia_socket *s)
{
DPRINTK("hs_suspend(%d)\n", sock);
#ifdef HD64465_DEBUG
hs_socket_t *sp = container_of(s, struct hs_socket_t, socket);
DPRINTK("hs_suspend(%d)\n", sp->number);
#endif
/* TODO */
......@@ -386,32 +371,10 @@ static int hs_suspend(unsigned int sock)
/*============================================================*/
static int hs_register_callback(unsigned int sock,
void (*handler)(void *, unsigned int), void * info)
{
hs_socket_t *sp = &hs_sockets[sock];
DPRINTK("hs_register_callback(%d)\n", sock);
sp->handler = handler;
sp->handler_info = info;
return 0;
}
/*============================================================*/
static int hs_inquire_socket(unsigned int sock, socket_cap_t *cap)
static int hs_get_status(struct pcmcia_socket *s, u_int *value)
{
DPRINTK("hs_inquire_socket(%d)\n", sock);
*cap = hs_socket_cap;
return 0;
}
/*============================================================*/
static int hs_get_status(unsigned int sock, u_int *value)
{
hs_socket_t *sp = &hs_sockets[sock];
hs_socket_t *sp = container_of(s, struct hs_socket_t, socket);
unsigned int isr;
u_int status = 0;
......@@ -473,9 +436,9 @@ static int hs_get_status(unsigned int sock, u_int *value)
/*============================================================*/
static int hs_get_socket(unsigned int sock, socket_state_t *state)
static int hs_get_socket(struct pcmcia_socket *s, socket_state_t *state)
{
hs_socket_t *sp = &hs_sockets[sock];
hs_socket_t *sp = container_of(s, struct hs_socket_t, socket);
DPRINTK("hs_get_socket(%d)\n", sock);
......@@ -485,9 +448,9 @@ static int hs_get_socket(unsigned int sock, socket_state_t *state)
/*============================================================*/
static int hs_set_socket(unsigned int sock, socket_state_t *state)
static int hs_set_socket(struct pcmcia_socket *s, socket_state_t *state)
{
hs_socket_t *sp = &hs_sockets[sock];
hs_socket_t *sp = container_of(s, struct hs_socket_t, socket);
u_long flags;
u_int changed;
unsigned short cscier;
......@@ -495,12 +458,12 @@ static int hs_set_socket(unsigned int sock, socket_state_t *state)
DPRINTK("hs_set_socket(sock=%d, flags=%x, csc_mask=%x, Vcc=%d, Vpp=%d, io_irq=%d)\n",
sock, state->flags, state->csc_mask, state->Vcc, state->Vpp, state->io_irq);
save_and_cli(flags); /* Don't want interrupts happening here */
local_irq_save(flags); /* Don't want interrupts happening here */
if (state->Vpp != sp->state.Vpp ||
state->Vcc != sp->state.Vcc) {
if (!hs_set_voltages(sp, state->Vcc, state->Vpp)) {
restore_flags(flags);
local_irq_restore(flags);
return -EINVAL;
}
}
......@@ -588,7 +551,7 @@ static int hs_set_socket(unsigned int sock, socket_state_t *state)
/* hd64465_io_debug = 0; */
sp->state = *state;
restore_flags(flags);
local_irq_restore(flags);
#if HD64465_DEBUG > 10
if (state->flags & SS_OUTPUT_ENA)
......@@ -599,10 +562,11 @@ static int hs_set_socket(unsigned int sock, socket_state_t *state)
/*============================================================*/
static int hs_set_io_map(unsigned int sock, struct pccard_io_map *io)
static int hs_set_io_map(struct pcmcia_socket *s, struct pccard_io_map *io)
{
hs_socket_t *sp = &hs_sockets[sock];
hs_socket_t *sp = container_of(s, struct hs_socket_t, socket);
int map = io->map;
int sock = sp->number;
struct pccard_io_map *sio;
pgprot_t prot;
......@@ -639,10 +603,9 @@ static int hs_set_io_map(unsigned int sock, struct pccard_io_map *io)
printk(KERN_INFO MODNAME ": MAP_0WS unimplemented\n");
if (io->flags & MAP_ACTIVE) {
unsigned long pstart, psize, paddrbase, vaddrbase;
unsigned long pstart, psize, paddrbase;
paddrbase = virt_to_phys((void*)(sp->mem_base + 2 * HD64465_PCC_WINDOW));
vaddrbase = (unsigned long)sp->io_vma->addr;
pstart = io->start & PAGE_MASK;
psize = ((io->stop + PAGE_SIZE) & PAGE_MASK) - pstart;
......@@ -653,26 +616,17 @@ static int hs_set_io_map(unsigned int sock, struct pccard_io_map *io)
* page will be mapped. But the code allows for weird cards
* that might want IO ports > 4K.
*/
DPRINTK("remap_page_range(vaddr=0x%08lx, paddr=0x%08lx, size=0x%08lxx)\n",
vaddrbase + pstart, paddrbase + pstart, psize);
#error This does not work. Firstly remap_page_range() uses current->mm for
#error the address space, which is wrong for kernel mappings. remap_page_range
#error also does flush_{cache,tlb}_range() which ONLY works for user mappings.
#error Next, remap_page_range() now wants to take a vm_area_struct arg.
remap_page_range(vaddrbase + pstart, paddrbase + pstart, psize, prot);
sp->io_base = p3_ioremap(paddrbase + pstart, psize, pgprot_val(prot));
/*
* Change the mapping used by inb() outb() etc
*/
hd64465_port_map(
io->start,
hd64465_port_map(io->start,
io->stop - io->start + 1,
vaddrbase + io->start,0);
(unsigned long)sp->io_base + io->start, 0);
} else {
hd64465_port_unmap(
sio->start,
sio->stop - sio->start + 1);
/* TODO: remap_page_range() to mark pages not present ? */
hd64465_port_unmap(sio->start, sio->stop - sio->start + 1);
p3_iounmap(sp->io_base);
}
*sio = *io;
......@@ -681,9 +635,9 @@ static int hs_set_io_map(unsigned int sock, struct pccard_io_map *io)
/*============================================================*/
static int hs_set_mem_map(unsigned int sock, struct pccard_mem_map *mem)
static int hs_set_mem_map(struct pcmcia_socket *s, struct pccard_mem_map *mem)
{
hs_socket_t *sp = &hs_sockets[sock];
hs_socket_t *sp = container_of(s, struct hs_socket_t, socket);
struct pccard_mem_map *smem;
int map = mem->map;
unsigned long paddr, size;
......@@ -722,13 +676,6 @@ static int hs_set_mem_map(unsigned int sock, struct pccard_mem_map *mem)
/*============================================================*/
static void hs_proc_setup(unsigned int sock, struct proc_dir_entry *base)
{
DPRINTK("hs_proc_setup(%d)\n", sock);
}
/*============================================================*/
/*
* This function is registered with the HD64465 glue code to do a
* secondary demux step on the PCMCIA interrupts. It handles
......@@ -756,35 +703,9 @@ static int hs_irq_demux(int irq, void *dev)
/*
* Interrupt handling routine.
*
* This uses the schedule_work() technique to cause reportable events
* such as card insertion and removal to be handled in keventd's
* process context.
*/
static void hs_events_bh(void *dummy)
{
hs_socket_t *sp;
u_int events;
int i;
for (i=0; i<HS_MAX_SOCKETS; i++) {
sp = &hs_sockets[i];
spin_lock_irq(&hs_pending_event_lock);
events = sp->pending_events;
sp->pending_events = 0;
spin_unlock_irq(&hs_pending_event_lock);
if (sp->handler)
sp->handler(sp->handler_info, events);
}
}
static DECLARE_WORK(hs_events_task, hs_events_bh, NULL);
static void hs_interrupt(int irq, void *dev, struct pt_regs *regs)
static irqreturn_t hs_interrupt(int irq, void *dev, struct pt_regs *regs)
{
hs_socket_t *sp = (hs_socket_t *)dev;
u_int events = 0;
......@@ -801,7 +722,7 @@ static void hs_interrupt(int irq, void *dev, struct pt_regs *regs)
if ((hs_in(sp, ISR) & HD64465_PCCISR_PCD_MASK) != 0) {
printk(KERN_NOTICE MODNAME
": socket %d, card not a supported card type or not inserted correctly\n",
hs_sockno(sp));
sp->number);
/* Don't do the rest unless a card is present */
cscr &= ~(HD64465_PCCCSCR_PCDC|
HD64465_PCCCSCR_PRC|
......@@ -839,34 +760,22 @@ static void hs_interrupt(int irq, void *dev, struct pt_regs *regs)
hs_out(sp, cscr, CSCR);
if (events) {
/*
* Arrange for events to be reported to the registered
* event handler function (from CardServices) in a process
* context (keventd) "soon".
*/
spin_lock(&hs_pending_event_lock);
sp->pending_events |= events;
spin_unlock(&hs_pending_event_lock);
schedule_work(&hs_events_task);
}
if (events)
pcmcia_parse_events(&sp->socket, events);
return IRQ_HANDLED;
}
/*============================================================*/
static struct pccard_operations hs_operations = {
.owner = THIS_MODULE,
.init = hs_init,
.suspend = hs_suspend,
.register_callback = hs_register_callback,
.inquire_socket = hs_inquire_socket,
.get_status = hs_get_status,
.get_socket = hs_get_socket,
.set_socket = hs_set_socket,
.set_io_map = hs_set_io_map,
.set_mem_map = hs_set_mem_map,
.proc_setup = hs_proc_setup,
};
static int hs_init_socket(hs_socket_t *sp, int irq, unsigned long mem_base,
......@@ -886,9 +795,6 @@ static int hs_init_socket(hs_socket_t *sp, int irq, unsigned long mem_base,
for (i=0 ; i<MAX_WIN ; i++)
sp->mem_maps[i].map = i;
if ((sp->io_vma = get_vm_area(HS_IO_MAP_SIZE, VM_IOREMAP)) == 0)
return -ENOMEM;
hd64465_register_irq_demux(sp->irq, hs_irq_demux, sp);
if ((err = request_irq(sp->irq, hs_interrupt, SA_INTERRUPT, MODNAME, sp)) < 0)
......@@ -925,9 +831,8 @@ static int hs_init_socket(hs_socket_t *sp, int irq, unsigned long mem_base,
hs_reset_socket(sp, 1);
printk(KERN_INFO "HD64465 PCMCIA bridge socket %d at 0x%08lx irq %d io window %ldK@0x%08lx\n",
i, sp->mem_base, sp->irq,
sp->io_vma->size>>10, (unsigned long)sp->io_vma->addr);
printk(KERN_INFO "HD64465 PCMCIA bridge socket %d at 0x%08lx irq %d\n",
i, sp->mem_base, sp->irq);
return 0;
}
......@@ -935,7 +840,10 @@ static int hs_init_socket(hs_socket_t *sp, int irq, unsigned long mem_base,
static void hs_exit_socket(hs_socket_t *sp)
{
unsigned short cscier, gcr;
unsigned long flags;
local_irq_save(flags);
/* turn off interrupts in hardware */
cscier = hs_in(sp, CSCIER);
cscier = (cscier & IER_MASK) | IER_OFF;
......@@ -955,19 +863,13 @@ static void hs_exit_socket(hs_socket_t *sp)
free_irq(sp->irq, hs_interrupt);
hd64465_unregister_irq_demux(sp->irq);
}
if (sp->io_vma != 0)
vfree(sp->io_vma->addr);
}
static struct pcmcia_socket_class_data hd64465_data = {
.nsock = HS_MAX_SOCKETS,
.ops = &hs_operations,
};
local_irq_restore(flags);
}
static struct device_driver hd64465_driver = {
.name = "hd64465-pcmcia",
.bus = &platform_bus_type,
.devclass = &pcmcia_socket_class,
.suspend = pcmcia_socket_dev_suspend,
.resume = pcmcia_socket_dev_resume,
};
......@@ -996,7 +898,8 @@ static int __init init_hs(void)
}
/* hd64465_io_debug = 1; */
register_driver(&hd64465_driver);
if (driver_register(&hd64465_driver))
return -EINVAL;
/* Wake both sockets out of STANDBY mode */
/* TODO: wait 15ms */
......@@ -1014,14 +917,22 @@ static int __init init_hs(void)
v |= HD64465_PCCCSCR_PSWSEL;
outb(v, HD64465_REG_PCC0CSCR);
hs_set_voltages(&hs_sockets[0], 0, 0);
hs_set_voltages(&hs_sockets[1], 0, 0);
/*
* Setup hs_sockets[] structures and request system resources.
* TODO: on memory allocation failure, power down the socket
* before quitting.
*/
for (i=0; i<HS_MAX_SOCKETS; i++) {
hs_set_voltages(&hs_sockets[i], 0, 0);
hs_sockets[i].socket.features |= SS_CAP_PCCARD | SS_CAP_STATIC_MAP; /* mappings are fixed in host memory */
hs_sockets[i].socket.irq_mask = 0xffde;/*0xffff*/ /* IRQs mapped in s/w so can do any, really */
hs_sockets[i].socket.map_size = HD64465_PCC_WINDOW; /* 16MB fixed window size */
hs_sockets[i].socket.owner = THIS_MODULE;
hs_sockets[i].socket.ss_entry = &hs_operations;
}
i = hs_init_socket(&hs_sockets[0],
HD64465_IRQ_PCMCIA0,
HD64465_PCC0_BASE,
......@@ -1040,27 +951,31 @@ static int __init init_hs(void)
}
/* hd64465_io_debug = 0; */
hd64465_device.dev.class_data = &hd64465_data;
platform_device_register(&hd64465_device);
return 0;
for (i=0; i<HS_MAX_SOCKETS; i++) {
unsigned int ret;
hs_sockets[i].socket.dev.dev = &hd64465_device.dev;
hs_sockets[i].number = i;
ret = pcmcia_register_socket(&hs_sockets[i].socket);
if (ret && i)
pcmcia_unregister_socket(&hs_sockets[0].socket);
}
return 0;
}
static void __exit exit_hs(void)
{
u_long flags;
int i;
save_and_cli(flags);
/*
* Release kernel resources
*/
for (i=0 ; i<HS_MAX_SOCKETS ; i++)
hs_exit_socket(&hs_sockets[i]);
for (i=0 ; i<HS_MAX_SOCKETS ; i++) {
pcmcia_unregister_socket(&hs_sockets[i].socket);
hs_exit_socket(&hs_sockets[i]);
}
platform_device_unregister(&hd64465_device);
restore_flags(flags);
unregister_driver(&hd64465_driver);
}
......
......@@ -161,7 +161,7 @@ static int __init i82092aa_pci_probe(struct pci_dev *dev, const struct pci_devic
for (i = 0; i<socket_count; i++) {
sockets[i].socket.dev.dev = &dev->dev;
sockets[i].socket.ss_entry = &i82092aa_operations;
sockets[i].socket.ops = &i82092aa_operations;
ret = pcmcia_register_socket(&sockets[i].socket);
if (ret) {
goto err_out_free_sockets;
......
......@@ -1403,7 +1403,7 @@ static int __init init_i82365(void)
/* register sockets with the pcmcia core */
for (i = 0; i < sockets; i++) {
socket[i].socket.dev.dev = &i82365_device.dev;
socket[i].socket.ss_entry = &pcic_operations;
socket[i].socket.ops = &pcic_operations;
socket[i].socket.owner = THIS_MODULE;
socket[i].number = i;
ret = pcmcia_register_socket(&socket[i].socket);
......
......@@ -161,7 +161,7 @@ static int ricoh_override(struct yenta_socket *socket)
rl_config(socket) |= RL5C4XX_CONFIG_PREFETCH;
}
socket->socket.ss_entry->init = ricoh_init;
socket->socket.ops->init = ricoh_init;
return 0;
}
......
......@@ -360,7 +360,7 @@ static int checksum(struct pcmcia_socket *s, struct resource *res)
map.sys_start = res->start;
map.sys_stop = res->end;
map.card_start = 0;
s->ss_entry->set_mem_map(s, &map);
s->ops->set_mem_map(s, &map);
/* Don't bother checking every word... */
for (i = 0; i < s->map_size; i += 44) {
......@@ -370,7 +370,7 @@ static int checksum(struct pcmcia_socket *s, struct resource *res)
}
map.flags = 0;
s->ss_entry->set_mem_map(s, &map);
s->ops->set_mem_map(s, &map);
iounmap(virt);
}
......
......@@ -725,7 +725,7 @@ int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, in
struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(i);
memset(skt, 0, sizeof(*skt));
skt->socket.ss_entry = &sa11xx_pcmcia_operations;
skt->socket.ops = &sa11xx_pcmcia_operations;
skt->socket.owner = ops->owner;
skt->socket.dev.dev = dev;
......
......@@ -519,7 +519,7 @@ static int __init init_tcic(void)
platform_device_register(&tcic_device);
for (i = 0; i < sockets; i++) {
socket_table[i].socket.ss_entry = &tcic_operations;
socket_table[i].socket.ops = &tcic_operations;
socket_table[i].socket.dev.dev = &tcic_device.dev;
ret = pcmcia_register_socket(&socket_table[i].socket);
if (ret && i)
......
......@@ -182,25 +182,30 @@ static int ti_override(struct yenta_socket *socket)
/*
* If ISA interrupts don't work, then fall back to routing card
* interrupts to the PCI interrupt of the socket.
*
* Tweaking this when we are using serial PCI IRQs causes hangs
* --rmk
*/
if (!socket->socket.irq_mask) {
int irqmux, devctl;
printk (KERN_INFO "ti113x: Routing card interrupts to PCI\n");
u8 irqmux, devctl;
devctl = config_readb(socket, TI113X_DEVICE_CONTROL);
devctl &= ~TI113X_DCR_IMODE_MASK;
if (devctl & TI113X_DCR_IMODE_MASK != TI12XX_DCR_IMODE_ALL_SERIAL) {
printk (KERN_INFO "ti113x: Routing card interrupts to PCI\n");
devctl &= ~TI113X_DCR_IMODE_MASK;
irqmux = config_readl(socket, TI122X_IRQMUX);
irqmux = (irqmux & ~0x0f) | 0x02; /* route INTA */
irqmux = (irqmux & ~0xf0) | 0x20; /* route INTB */
irqmux = config_readl(socket, TI122X_IRQMUX);
irqmux = (irqmux & ~0x0f) | 0x02; /* route INTA */
irqmux = (irqmux & ~0xf0) | 0x20; /* route INTB */
config_writel(socket, TI122X_IRQMUX, irqmux);
config_writeb(socket, TI113X_DEVICE_CONTROL, devctl);
config_writel(socket, TI122X_IRQMUX, irqmux);
config_writeb(socket, TI113X_DEVICE_CONTROL, devctl);
}
}
#endif
socket->socket.ss_entry->init = ti_init;
socket->socket.ops->init = ti_init;
return 0;
}
......@@ -233,7 +238,7 @@ static int ti113x_override(struct yenta_socket *socket)
if (socket->cb_irq)
ti_cardctl(socket) |= TI113X_CCR_PCI_IRQ_ENA | TI113X_CCR_PCI_CSC | TI113X_CCR_PCI_IREQ;
ti_override(socket);
socket->socket.ss_entry->init = ti113x_init;
socket->socket.ops->init = ti113x_init;
return 0;
}
......@@ -262,7 +267,7 @@ static int ti1250_override(struct yenta_socket *socket)
if (socket->cb_irq)
ti_diag(socket) |= TI1250_DIAG_PCI_CSC | TI1250_DIAG_PCI_IREQ;
ti113x_override(socket);
socket->socket.ss_entry->init = ti1250_init;
socket->socket.ops->init = ti1250_init;
return 0;
}
......
......@@ -828,7 +828,7 @@ static int __devinit yenta_probe (struct pci_dev *dev, const struct pci_device_i
memset(socket, 0, sizeof(*socket));
/* prepare pcmcia_socket */
socket->socket.ss_entry = &yenta_socket_operations;
socket->socket.ops = &yenta_socket_operations;
socket->socket.dev.dev = &dev->dev;
socket->socket.driver_data = socket;
socket->socket.owner = THIS_MODULE;
......
......@@ -69,7 +69,7 @@ obj-$(CONFIG_FB_SA1100) += sa1100fb.o cfbfillrect.o cfbcopyarea.o cfbi
obj-$(CONFIG_FB_VIRTUAL) += vfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
obj-$(CONFIG_FB_HIT) += hitfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
obj-$(CONFIG_FB_E1355) += epson1355fb.o
obj-$(CONFIG_FB_PVR2) += pvr2fb.o
obj-$(CONFIG_FB_PVR2) += pvr2fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
obj-$(CONFIG_FB_VOODOO1) += sstfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
obj-$(CONFIG_FB_FFB) += ffb.o sbuslib.o cfbimgblt.o cfbcopyarea.o
......
......@@ -4,7 +4,7 @@
* Dreamcast.
*
* Copyright (c) 2001 M. R. Brown <mrbrown@0xd6.org>
* Copyright (c) 2001 Paul Mundt <lethal@chaoticdreams.org>
* Copyright (c) 2001, 2002, 2003 Paul Mundt <lethal@linux-sh.org>
*
* This file is part of the LinuxDC project (linuxdc.sourceforge.net).
*
......@@ -12,14 +12,15 @@
/*
* This driver is mostly based on the excellent amifb and vfb sources. It uses
* an odd scheme for converting hardware values to/from framebuffer values, here are
* some hacked-up formulas:
* an odd scheme for converting hardware values to/from framebuffer values,
* here are some hacked-up formulas:
*
* The Dreamcast has screen offsets from each side of its four borders and the start
* offsets of the display window. I used these values to calculate 'pseudo' values
* (think of them as placeholders) for the fb video mode, so that when it came time
* to convert these values back into their hardware values, I could just add mode-
* specific offsets to get the correct mode settings:
* The Dreamcast has screen offsets from each side of its four borders and
* the start offsets of the display window. I used these values to calculate
* 'pseudo' values (think of them as placeholders) for the fb video mode, so
* that when it came time to convert these values back into their hardware
* values, I could just add mode- specific offsets to get the correct mode
* settings:
*
* left_margin = diwstart_h - borderstart_h;
* right_margin = borderstop_h - (diwstart_h + xres);
......@@ -29,9 +30,9 @@
* hsync_len = borderstart_h + (hsync_total - borderstop_h);
* vsync_len = borderstart_v + (vsync_total - borderstop_v);
*
* Then, when it's time to convert back to hardware settings, the only constants
* are the borderstart_* offsets, all other values are derived from the fb video
* mode:
* Then, when it's time to convert back to hardware settings, the only
* constants are the borderstart_* offsets, all other values are derived from
* the fb video mode:
*
* // PAL
* borderstart_h = 116;
......@@ -57,7 +58,6 @@
#include <linux/interrupt.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/console.h>
#ifdef CONFIG_SH_DREAMCAST
#include <asm/io.h>
......@@ -66,14 +66,9 @@
#endif
#ifdef CONFIG_MTRR
#include <asm/mtrr.h>
#include <asm/mtrr.h>
#endif
#include <video/fbcon.h>
#include <video/fbcon-cfb16.h>
#include <video/fbcon-cfb24.h>
#include <video/fbcon-cfb32.h>
#ifdef CONFIG_FB_PVR2_DEBUG
# define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
#else
......@@ -124,16 +119,6 @@ static struct pvr2_params outputs[] __initdata = {
*/
static struct pvr2fb_par {
int xres;
int yres;
int vxres;
int vyres;
int xoffset;
int yoffset;
u_short bpp;
u_long pixclock;
u_short hsync_total; /* Clocks/line */
u_short vsync_total; /* Lines/field */
u_short borderstart_h;
......@@ -144,53 +129,49 @@ static struct pvr2fb_par {
u_short diwstart_v; /* Vertical offset of the display field, for
interlaced modes, this is the long field */
u_long disp_start; /* Address of image within VRAM */
u_long next_line; /* Modulo for next line */
u_char is_interlaced; /* Is the display interlaced? */
u_char is_doublescan; /* Are scanlines output twice? (doublescan) */
u_char is_lowres; /* Is horizontal pixel-doubling enabled? */
} *currentpar;
u_long bordercolor; /* RGB888 format border color */
u_long vmode;
} currentpar;
static int currbpp;
static struct display disp;
static struct fb_info fb_info;
static struct fb_info *fb_info;
static int pvr2fb_inverse = 0;
static struct { u_short red, green, blue, alpha; } palette[256];
static union {
#ifdef FBCON_HAS_CFB16
u16 cfb16[16];
#endif
#ifdef FBCON_HAS_CFB24
u32 cfb24[16];
#endif
#ifdef FBCON_HAS_CFB32
u32 cfb32[16];
#endif
} fbcon_cmap;
static struct fb_fix_screeninfo pvr2_fix __initdata = {
.id = "NEC PowerVR2",
.type = FB_TYPE_PACKED_PIXELS,
.visual = FB_VISUAL_TRUECOLOR,
.ypanstep = 1,
.ywrapstep = 1,
.accel = FB_ACCEL_NONE,
};
static char pvr2fb_name[16] = "NEC PowerVR2";
static struct fb_var_screeninfo pvr2_var __initdata = {
.xres = 640,
.yres = 480,
.xres_virtual = 640,
.yres_virtual = 480,
.bits_per_pixel =16,
.red = { 11, 5, 0 },
.green = { 5, 6, 0 },
.blue = { 0, 5, 0 },
.activate = FB_ACTIVATE_NOW,
.height = -1,
.width = -1,
.vmode = FB_VMODE_NONINTERLACED,
};
#define VIDEOMEMSIZE (8*1024*1024)
static u_long videomemory = 0xa5000000, videomemorysize = VIDEOMEMSIZE;
static int cable_type = -1;
static int video_output = -1;
#ifdef CONFIG_MTRR
static int enable_mtrr = 1;
static int mtrr_handle;
#endif
static int nopan = 0;
static int nowrap = 1;
/*
* We do all updating, blanking, etc. during the vertical retrace period
*/
static u_short do_vmode_full = 0; /* Change the video mode */
static u_short do_vmode_pan = 0; /* Update the video mode */
static short do_blank = 0; /* (Un)Blank the screen */
......@@ -201,50 +182,15 @@ static u_short is_blanked = 0; /* Is the screen blanked? */
int pvr2fb_setup(char*);
static int pvr2fb_get_fix(struct fb_fix_screeninfo *fix, int con,
struct fb_info *info);
static int pvr2fb_get_var(struct fb_var_screeninfo *var, int con,
struct fb_info *info);
static int pvr2fb_set_var(struct fb_var_screeninfo *var, int con,
struct fb_info *info);
static int pvr2fb_pan_display(struct fb_var_screeninfo *var, int con,
struct fb_info *info);
static int pvr2fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
struct fb_info *info);
static int pvr2fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
struct fb_info *info);
static int pvr2fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
u_int transp, struct fb_info *info);
static int pvr2fb_blank(int blank, struct fb_info *info);
/*
* Interface to the low level console driver
*/
static int pvr2fbcon_switch(int con, struct fb_info *info);
static int pvr2fbcon_updatevar(int con, struct fb_info *info);
/*
* Internal/hardware-specific routines
*/
static u_long get_line_length(int xres_virtual, int bpp);
static void set_color_bitfields(struct fb_var_screeninfo *var);
static int pvr2_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
u_int *transp, struct fb_info *info);
static int pvr2_encode_fix(struct fb_fix_screeninfo *fix,
struct pvr2fb_par *par);
static int pvr2_decode_var(struct fb_var_screeninfo *var,
struct pvr2fb_par *par);
static int pvr2_encode_var(struct fb_var_screeninfo *var,
struct pvr2fb_par *par);
static void pvr2_get_par(struct pvr2fb_par *par);
static void pvr2_set_var(struct fb_var_screeninfo *var);
static void pvr2_pan_var(struct fb_var_screeninfo *var);
static int pvr2_update_par(void);
static void pvr2_update_display(void);
static void pvr2_init_display(void);
static int pvr2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info);
static int pvr2fb_set_par(struct fb_info *info);
static void pvr2_update_display(struct fb_info *info);
static void pvr2_init_display(struct fb_info *info);
static void pvr2_do_blank(void);
static irqreturn_t pvr2fb_interrupt(int irq, void *dev_id, struct pt_regs *fp);
static int pvr2_init_cable(void);
......@@ -252,19 +198,18 @@ static int pvr2_get_param(const struct pvr2_params *p, const char *s,
int val, int size);
static struct fb_ops pvr2fb_ops = {
.owner = THIS_MODULE,
.fb_get_fix = pvr2fb_get_fix,
.fb_get_var = pvr2fb_get_var,
.fb_set_var = pvr2fb_set_var,
.fb_get_cmap = pvr2fb_get_cmap,
.fb_set_cmap = pvr2fb_set_cmap,
.fb_setcolreg = pvr2fb_setcolreg,
.fb_pan_display = pvr2fb_pan_display,
.fb_blank = pvr2fb_blank,
.owner = THIS_MODULE,
.fb_setcolreg = pvr2fb_setcolreg,
.fb_blank = pvr2fb_blank,
.fb_check_var = pvr2fb_check_var,
.fb_set_par = pvr2fb_set_par,
.fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit,
.fb_cursor = soft_cursor,
};
static struct fb_videomode pvr2_modedb[] __initdata = {
/*
* Broadcast video modes (PAL and NTSC). I'm unfamiliar with
* PAL-M and PAL-N, but from what I've read both modes parallel PAL and
......@@ -275,21 +220,16 @@ static struct fb_videomode pvr2_modedb[] __initdata = {
/* 640x480 @ 60Hz interlaced (NTSC) */
"ntsc_640x480i", 60, 640, 480, TV_CLK, 38, 33, 0, 18, 146, 26,
FB_SYNC_BROADCAST, FB_VMODE_INTERLACED | FB_VMODE_YWRAP
},
{
}, {
/* 640x240 @ 60Hz (NTSC) */
/* XXX: Broken! Don't use... */
"ntsc_640x240", 60, 640, 240, TV_CLK, 38, 33, 0, 0, 146, 22,
FB_SYNC_BROADCAST, FB_VMODE_YWRAP
},
{
}, {
/* 640x480 @ 60hz (VGA) */
"vga_640x480", 60, 640, 480, VGA_CLK, 38, 33, 0, 18, 146, 26,
0, FB_VMODE_YWRAP
},
},
};
#define NUM_TOTAL_MODES ARRAY_SIZE(pvr2_modedb)
......@@ -301,222 +241,10 @@ static struct fb_videomode pvr2_modedb[] __initdata = {
static int defmode = DEFMODE_NTSC;
static char *mode_option __initdata = NULL;
/* Get the fixed part of the display */
static int pvr2fb_get_fix(struct fb_fix_screeninfo *fix, int con,
struct fb_info *info)
{
struct pvr2fb_par par;
if (con == -1)
pvr2_get_par(&par);
else {
int err;
if ((err = pvr2_decode_var(&fb_display[con].var, &par)))
return err;
}
return pvr2_encode_fix(fix, &par);
}
/* Get the user-defined part of the display */
static int pvr2fb_get_var(struct fb_var_screeninfo *var, int con,
struct fb_info *info)
{
int err = 0;
if (con == -1) {
struct pvr2fb_par par;
pvr2_get_par(&par);
err = pvr2_encode_var(var, &par);
} else
*var = fb_display[con].var;
return err;
}
/* Set the user-defined part of the display */
static int pvr2fb_set_var(struct fb_var_screeninfo *var, int con,
struct fb_info *info)
{
int err, activate = var->activate;
int oldxres, oldyres, oldvxres, oldvyres, oldbpp;
struct pvr2fb_par par;
struct display *display;
if (con >= 0)
display = &fb_display[con];
else
display = &disp; /* used during initialization */
/*
* FB_VMODE_CONUPDATE and FB_VMODE_SMOOTH_XPAN are equal!
* as FB_VMODE_SMOOTH_XPAN is only used internally
*/
if (var->vmode & FB_VMODE_CONUPDATE) {
var->vmode |= FB_VMODE_YWRAP;
var->xoffset = display->var.xoffset;
var->yoffset = display->var.yoffset;
}
if ((err = pvr2_decode_var(var, &par)))
return err;
pvr2_encode_var(var, &par);
/* Do memory check and bitfield set here?? */
if ((activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
oldxres = display->var.xres;
oldyres = display->var.yres;
oldvxres = display->var.xres_virtual;
oldvyres = display->var.yres_virtual;
oldbpp = display->var.bits_per_pixel;
display->var = *var;
if (oldxres != var->xres || oldyres != var->yres ||
oldvxres != var->xres_virtual || oldvyres != var->yres_virtual ||
oldbpp != var->bits_per_pixel) {
struct fb_fix_screeninfo fix;
pvr2_encode_fix(&fix, &par);
display->scrollmode = SCROLL_YREDRAW;
display->visual = fix.visual;
display->type = fix.type;
display->type_aux = fix.type_aux;
display->ypanstep = fix.ypanstep;
display->ywrapstep = fix.ywrapstep;
display->line_length = fix.line_length;
display->can_soft_blank = 1;
display->inverse = pvr2fb_inverse;
switch (var->bits_per_pixel) {
#ifdef FBCON_HAS_CFB16
case 16:
display->dispsw = &fbcon_cfb16;
display->dispsw_data = fbcon_cmap.cfb16;
break;
#endif
#ifdef FBCON_HAS_CFB24
case 24:
display->dispsw = &fbcon_cfb24;
display->dispsw_data = fbcon_cmap.cfb24;
break;
#endif
#ifdef FBCON_HAS_CFB32
case 32:
display->dispsw = &fbcon_cfb32;
display->dispsw_data = fbcon_cmap.cfb32;
break;
#endif
default:
display->dispsw = &fbcon_dummy;
break;
}
if (fb_info.changevar)
(*fb_info.changevar)(con);
}
if (oldbpp != var->bits_per_pixel) {
if ((err = fb_alloc_cmap(&display->cmap, 0, 0)))
return err;
do_install_cmap(con, info);
}
if (con == info->currcon)
pvr2_set_var(&display->var);
}
return 0;
}
/*
* Pan or wrap the display.
* This call looks only at xoffset, yoffset and the FB_VMODE_YRAP flag
*/
static int pvr2fb_pan_display(struct fb_var_screeninfo *var, int con,
struct fb_info *info)
{
if (var->vmode & FB_VMODE_YWRAP) {
if (var->yoffset<0 || var->yoffset >=
fb_display[con].var.yres_virtual || var->xoffset)
return -EINVAL;
} else {
if (var->xoffset+fb_display[con].var.xres >
fb_display[con].var.xres_virtual ||
var->yoffset+fb_display[con].var.yres >
fb_display[con].var.yres_virtual)
return -EINVAL;
}
if (con == info->currcon)
pvr2_pan_var(var);
fb_display[con].var.xoffset = var->xoffset;
fb_display[con].var.yoffset = var->yoffset;
if (var->vmode & FB_VMODE_YWRAP)
fb_display[con].var.vmode |= FB_VMODE_YWRAP;
else
fb_display[con].var.vmode &= ~FB_VMODE_YWRAP;
return 0;
}
/* Get the colormap */
static int pvr2fb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
struct fb_info *info)
{
if (con == info->currcon) /* current console? */
return fb_get_cmap(cmap, kspc, pvr2_getcolreg, info);
else if (fb_display[con].cmap.len) /* non default colormap? */
fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
else
fb_copy_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
cmap, kspc ? 0 : 2);
return 0;
}
/* Set the colormap */
static int pvr2fb_set_cmap(struct fb_cmap *cmap, int kspc, int con,
struct fb_info *info)
{
int err;
if (!fb_display[con].cmap.len) { /* no colormap allocated? */
if ((err = fb_alloc_cmap(&fb_display[con].cmap,
1<<fb_display[con].var.bits_per_pixel,
0)))
return err;
}
if (con == info->currcon) /* current console? */
return fb_set_cmap(cmap, kspc, info);
else
fb_copy_cmap(cmap, &fb_display[con].cmap, kspc ? 0 : 1);
return 0;
}
static int pvr2fbcon_switch(int con, struct fb_info *info)
{
/* Do we have to save the colormap? */
if (fb_display[info->currcon].cmap.len)
fb_get_cmap(&fb_display[info->currcon].cmap, 1, pvr2_getcolreg, info);
info->currcon = con;
pvr2_set_var(&fb_display[con].var);
/* Install new colormap */
do_install_cmap(con, info);
return 0;
}
static int pvr2fbcon_updatevar(int con, struct fb_info *info)
{
pvr2_pan_var(&fb_display[con].var);
return 0;
}
static int pvr2fb_blank(int blank, struct fb_info *info)
{
do_blank = blank ? blank : -1;
return 0;
}
static inline u_long get_line_length(int xres_virtual, int bpp)
......@@ -548,52 +276,29 @@ static void set_color_bitfields(struct fb_var_screeninfo *var)
}
}
static int pvr2_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
u_int *transp, struct fb_info *info)
{
if (regno > 255)
return 1;
*red = palette[regno].red;
*green = palette[regno].green;
*blue = palette[regno].blue;
*transp = 0;
return 0;
}
static int pvr2fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
u_int transp, struct fb_info *info)
{
if (regno > 255)
return 1;
palette[regno].red = red;
palette[regno].green = green;
palette[regno].blue = blue;
if (regno < 16) {
switch (currbpp) {
#ifdef FBCON_HAS_CFB16
switch (info->var.bits_per_pixel) {
case 16: /* RGB 565 */
fbcon_cmap.cfb16[regno] = (red & 0xf800) |
((green & 0xfc00) >> 5) |
((u16*)(info->pseudo_palette))[regno] = (red & 0xf800) |
((green & 0xfc00) >> 5) |
((blue & 0xf800) >> 11);
break;
#endif
#ifdef FBCON_HAS_CFB24
case 24: /* RGB 888 */
red >>= 8; green >>= 8; blue >>= 8;
fbcon_cmap.cfb24[regno] = (red << 16) | (green << 8) | blue;
((u32*)(info->pseudo_palette))[regno] = (red << 16) | (green << 8) | blue;
break;
#endif
#ifdef FBCON_HAS_CFB32
case 32: /* ARGB 8888 */
red >>= 8; green >>= 8; blue >>= 8;
fbcon_cmap.cfb32[regno] = (red << 16) | (green << 8) | blue;
((u32*)(info->pseudo_palette))[regno] = (transp << 24) |(red << 16) | (green << 8) | blue;
break;
#endif
default:
DPRINTK("Invalid bit depth %d?!?\n", currbpp);
DPRINTK("Invalid bit depth %d?!?\n", info->var.bits_per_pixel);
return 1;
}
}
......@@ -601,85 +306,33 @@ static int pvr2fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
return 0;
}
static int pvr2_encode_fix(struct fb_fix_screeninfo *fix,
struct pvr2fb_par *par)
{
memset(fix, 0, sizeof(struct fb_fix_screeninfo));
strcpy(fix->id, pvr2fb_name);
fix->smem_start = videomemory;
fix->smem_len = videomemorysize;
fix->type = FB_TYPE_PACKED_PIXELS;
fix->type_aux = 0;
fix->visual = FB_VISUAL_TRUECOLOR;
if (par->vmode & FB_VMODE_YWRAP) {
fix->ywrapstep = 1;
fix->xpanstep = fix->ypanstep = 0;
} else {
fix->ywrapstep = 0;
fix->xpanstep = 1;
fix->ypanstep = 1;
}
fix->line_length = par->next_line;
return 0;
}
/*
* Create a hardware video mode using the framebuffer values. If a value needs
* to be clipped or constrained it's done here. This routine needs a bit more
* work to make sure we're doing the right tests at the right time.
*/
static int pvr2_decode_var(struct fb_var_screeninfo *var,
struct pvr2fb_par *par)
static int pvr2fb_set_par(struct fb_info *info)
{
struct pvr2fb_par *par = (struct pvr2fb_par *)info->par;
struct fb_var_screeninfo *var = &info->var;
u_long line_length;
u_short vtotal;
if (var->pixclock != TV_CLK && var->pixclock != VGA_CLK) {
DPRINTK("Invalid pixclock value %d\n", var->pixclock);
return -EINVAL;
}
par->pixclock = var->pixclock;
if ((par->xres = var->xres) < 320)
par->xres = 320;
if ((par->yres = var->yres) < 240)
par->yres = 240;
if ((par->vxres = var->xres_virtual) < par->xres)
par->vxres = par->xres;
if ((par->vyres = var->yres_virtual) < par->yres)
par->vyres = par->yres;
if ((par->bpp = var->bits_per_pixel) <= 16)
par->bpp = 16;
else if ((par->bpp = var->bits_per_pixel) <= 24)
par->bpp = 24;
else if ((par->bpp = var->bits_per_pixel) <= 32)
par->bpp = 32;
currbpp = par->bpp;
/*
* XXX: It's possible that a user could use a VGA box, change the cable
* type in hardware (i.e. switch from VGA<->composite), then change modes
* (i.e. switching to another VT). If that happens we should automagically
* change the output format to cope, but currently I don't have a VGA box
* to make sure this works properly.
* type in hardware (i.e. switch from VGA<->composite), then change
* modes (i.e. switching to another VT). If that happens we should
* automagically change the output format to cope, but currently I
* don't have a VGA box to make sure this works properly.
*/
cable_type = pvr2_init_cable();
if (cable_type == CT_VGA && video_output != VO_VGA)
video_output = VO_VGA;
par->vmode = var->vmode & FB_VMODE_MASK;
if (par->vmode & FB_VMODE_INTERLACED && video_output != VO_VGA)
var->vmode &= FB_VMODE_MASK;
if (var->vmode & FB_VMODE_INTERLACED && video_output != VO_VGA)
par->is_interlaced = 1;
/*
* XXX: Need to be more creative with this (i.e. allow doublecan for
* PAL/NTSC output).
*/
par->is_doublescan = (par->yres < 480 && video_output == VO_VGA);
if (var->vmode & FB_VMODE_DOUBLE && video_output == VO_VGA)
par->is_doublescan = 1;
par->hsync_total = var->left_margin + var->xres + var->right_margin +
var->hsync_len;
......@@ -691,22 +344,12 @@ static int pvr2_decode_var(struct fb_var_screeninfo *var,
if (par->is_interlaced)
vtotal /= 2;
if (vtotal > (PAL_VTOTAL + NTSC_VTOTAL)/2) {
/* PAL video output */
/* XXX: Should be using a range here ... ? */
if (par->hsync_total != PAL_HTOTAL) {
DPRINTK("invalid hsync total for PAL\n");
return -EINVAL;
}
/* XXX: Check for start values here... */
/* XXX: Check hardware for PAL-compatibility */
par->borderstart_h = 116;
par->borderstart_v = 44;
} else {
/* NTSC video output */
if (par->hsync_total != NTSC_HTOTAL) {
DPRINTK("invalid hsync total for NTSC\n");
return -EINVAL;
}
par->borderstart_h = 126;
par->borderstart_v = 18;
}
......@@ -714,155 +357,123 @@ static int pvr2_decode_var(struct fb_var_screeninfo *var,
/* VGA mode */
/* XXX: What else needs to be checked? */
/*
* XXX: We have a little freedom in VGA modes, what ranges should
* be here (i.e. hsync/vsync totals, etc.)?
* XXX: We have a little freedom in VGA modes, what ranges
* should be here (i.e. hsync/vsync totals, etc.)?
*/
par->borderstart_h = 126;
par->borderstart_v = 40;
}
/* Calculate the remainding offsets */
par->borderstop_h = par->borderstart_h + par->hsync_total -
var->hsync_len;
par->borderstop_v = par->borderstart_v + par->vsync_total -
var->vsync_len;
par->diwstart_h = par->borderstart_h + var->left_margin;
par->diwstart_v = par->borderstart_v + var->upper_margin;
par->borderstop_h = par->diwstart_h + var->xres +
var->right_margin;
par->borderstop_v = par->diwstart_v + var->yres +
var->lower_margin;
if (!par->is_interlaced)
par->borderstop_v /= 2;
if (par->xres < 640)
if (info->var.xres < 640)
par->is_lowres = 1;
/* XXX: Needs testing. */
if (!((par->vmode ^ var->vmode) & FB_VMODE_YWRAP)) {
par->xoffset = var->xoffset;
par->yoffset = var->yoffset;
if (par->vmode & FB_VMODE_YWRAP) {
if (par->xoffset || par->yoffset < 0 || par->yoffset >=
par->vyres)
par->xoffset = par->yoffset = 0;
} else {
if (par->xoffset < 0 || par->xoffset > par->vxres-par->xres ||
par->yoffset < 0 || par->yoffset > par->vyres-par->yres)
par->xoffset = par->yoffset = 0;
}
} else
par->xoffset = par->yoffset = 0;
/* Check memory sizes */
line_length = get_line_length(var->xres_virtual, var->bits_per_pixel);
if (line_length * var->yres_virtual > videomemorysize)
return -ENOMEM;
par->disp_start = videomemory + (get_line_length(par->vxres, par->bpp) *
par->yoffset) * get_line_length(par->xoffset, par->bpp);
par->next_line = line_length;
par->disp_start = videomemory + (line_length * var->yoffset) * line_length;
info->fix.line_length = line_length;
return 0;
}
static int pvr2_encode_var(struct fb_var_screeninfo *var,
struct pvr2fb_par *par)
static int pvr2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
{
memset(var, 0, sizeof(struct fb_var_screeninfo));
u_short vtotal, hsync_total;
u_long line_length;
if (var->pixclock != TV_CLK || var->pixclock != VGA_CLK) {
DPRINTK("Invalid pixclock value %d\n", var->pixclock);
return -EINVAL;
}
var->xres = par->xres;
var->yres = par->yres;
var->xres_virtual = par->vxres;
var->yres_virtual = par->vyres;
var->xoffset = par->xoffset;
var->yoffset = par->yoffset;
if (var->xres < 320)
var->xres = 320;
if (var->yres < 240)
var->yres = 240;
if (var->xres_virtual < var->xres)
var->xres_virtual = var->xres;
if (var->yres_virtual < var->yres)
var->yres_virtual = var->yres;
if (var->bits_per_pixel <= 16)
var->bits_per_pixel = 16;
else if (var->bits_per_pixel <= 24)
var->bits_per_pixel = 24;
else if (var->bits_per_pixel <= 32)
var->bits_per_pixel = 32;
var->bits_per_pixel = par->bpp;
set_color_bitfields(var);
var->activate = FB_ACTIVATE_NOW;
var->height = -1;
var->width = -1;
var->pixclock = par->pixclock;
if (var->vmode & FB_VMODE_YWRAP) {
if (var->xoffset || var->yoffset < 0 ||
var->yoffset >= var->yres_virtual) {
var->xoffset = var->yoffset = 0;
} else {
if (var->xoffset > var->xres_virtual - var->xres ||
var->yoffset > var->yres_virtual - var->yres ||
var->xoffset < 0 || var->yoffset < 0)
var->xoffset = var->yoffset = 0;
}
} else {
var->xoffset = var->yoffset = 0;
}
if (par->is_doublescan)
/*
* XXX: Need to be more creative with this (i.e. allow doublecan for
* PAL/NTSC output).
*/
if (var->yres < 480 && video_output == VO_VGA)
var->vmode = FB_VMODE_DOUBLE;
if (par->is_interlaced)
var->vmode |= FB_VMODE_INTERLACED;
else
var->vmode |= FB_VMODE_NONINTERLACED;
var->right_margin = par->borderstop_h - (par->diwstart_h + par->xres);
var->left_margin = par->diwstart_h - par->borderstart_h;
var->hsync_len = par->borderstart_h + (par->hsync_total - par->borderstop_h);
var->upper_margin = par->diwstart_v - par->borderstart_v;
var->lower_margin = par->borderstop_v - (par->diwstart_v + par->yres);
var->vsync_len = par->borderstart_v + (par->vsync_total - par->borderstop_v);
if (video_output != VO_VGA)
var->sync = FB_SYNC_BROADCAST;
if (par->vmode & FB_VMODE_YWRAP)
var->vmode |= FB_VMODE_YWRAP;
return 0;
}
static void pvr2_get_par(struct pvr2fb_par *par)
{
*par = currentpar;
}
/* Setup the new videomode in hardware */
static void pvr2_set_var(struct fb_var_screeninfo *var)
{
do_vmode_pan = 0;
do_vmode_full = 0;
pvr2_decode_var(var, &currentpar);
var->sync = FB_SYNC_BROADCAST | FB_VMODE_INTERLACED;
do_vmode_full = 1;
}
/*
* Pan or wrap the display
* This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag in `var'.
*/
static void pvr2_pan_var(struct fb_var_screeninfo *var)
{
struct pvr2fb_par *par = &currentpar;
par->xoffset = var->xoffset;
par->yoffset = var->yoffset;
if (var->vmode & FB_VMODE_YWRAP)
par->vmode |= FB_VMODE_YWRAP;
else
par->vmode &= ~FB_VMODE_YWRAP;
do_vmode_pan = 0;
pvr2_update_par();
do_vmode_pan = 1;
}
static int pvr2_update_par(void)
{
struct pvr2fb_par *par = &currentpar;
u_long move;
move = get_line_length(par->xoffset, par->bpp);
if (par->yoffset) {
par->disp_start += (par->next_line * par->yoffset) + move;
} else
par->disp_start += move;
hsync_total = var->left_margin + var->xres + var->right_margin +
var->hsync_len;
vtotal = var->upper_margin + var->yres + var->lower_margin +
var->vsync_len;
if (var->sync & FB_SYNC_BROADCAST) {
if (var->vmode & FB_VMODE_INTERLACED)
vtotal /= 2;
if (vtotal > (PAL_VTOTAL + NTSC_VTOTAL)/2) {
/* PAL video output */
/* XXX: Should be using a range here ... ? */
if (hsync_total != PAL_HTOTAL) {
DPRINTK("invalid hsync total for PAL\n");
return -EINVAL;
}
} else {
/* NTSC video output */
if (hsync_total != NTSC_HTOTAL) {
DPRINTK("invalid hsync total for NTSC\n");
return -EINVAL;
}
}
}
/* Check memory sizes */
line_length = get_line_length(var->xres_virtual, var->bits_per_pixel);
if (line_length * var->yres_virtual > videomemorysize)
return -ENOMEM;
return 0;
}
static void pvr2_update_display(void)
static void pvr2_update_display(struct fb_info *info)
{
struct pvr2fb_par *par = &currentpar;
struct pvr2fb_par *par = (struct pvr2fb_par *) info->par;
struct fb_var_screeninfo *var = &info->var;
/* Update the start address of the display image */
ctrl_outl(par->disp_start, DISP_DIWADDRL);
ctrl_outl(par->disp_start +
get_line_length(par->xoffset + par->xres, par->bpp),
get_line_length(var->xoffset+var->xres, var->bits_per_pixel),
DISP_DIWADDRS);
}
......@@ -872,11 +483,12 @@ static void pvr2_update_display(void)
* registers are still undocumented.
*/
static void pvr2_init_display(void)
static void pvr2_init_display(struct fb_info *info)
{
struct pvr2fb_par *par = &currentpar;
struct pvr2fb_par *par = (struct pvr2fb_par *) info->par;
struct fb_var_screeninfo *var = &info->var;
u_short diw_height, diw_width, diw_modulo = 1;
u_short bytesperpixel = par->bpp / 8;
u_short bytesperpixel = var->bits_per_pixel >> 3;
/* hsync and vsync totals */
ctrl_outl((par->vsync_total << 16) | par->hsync_total, DISP_SYNCSIZE);
......@@ -885,16 +497,16 @@ static void pvr2_init_display(void)
/* since we're "panning" within vram, we need to offset things based
* on the offset from the virtual x start to our real gfx. */
if (video_output != VO_VGA && par->is_interlaced)
diw_modulo += par->next_line / 4;
diw_height = (par->is_interlaced ? par->yres / 2 : par->yres);
diw_width = get_line_length(par->xres, par->bpp) / 4;
diw_modulo += info->fix.line_length / 4;
diw_height = (par->is_interlaced ? var->yres / 2 : var->yres);
diw_width = get_line_length(var->xres, var->bits_per_pixel) / 4;
ctrl_outl((diw_modulo << 20) | (--diw_height << 10) | --diw_width,
DISP_DIWSIZE);
/* display address, long and short fields */
ctrl_outl(par->disp_start, DISP_DIWADDRL);
ctrl_outl(par->disp_start +
get_line_length(par->xoffset + par->xres, par->bpp),
get_line_length(var->xoffset+var->xres, var->bits_per_pixel),
DISP_DIWADDRS);
/* border horizontal, border vertical, border color */
......@@ -919,7 +531,6 @@ static void pvr2_init_display(void)
/* video enable, color sync, interlace,
* hsync and vsync polarity (currently unused) */
ctrl_outl(0x100 | ((par->is_interlaced /*|4*/) << 4), DISP_SYNCCONF);
}
/* Simulate blanking by making the border cover the entire screen */
......@@ -941,23 +552,20 @@ static void pvr2_do_blank(void)
static irqreturn_t pvr2fb_interrupt(int irq, void *dev_id, struct pt_regs *fp)
{
if (do_vmode_pan || do_vmode_full)
pvr2_update_display();
struct fb_info *info = dev_id;
if (do_vmode_pan || do_vmode_full)
pvr2_update_display(info);
if (do_vmode_full)
pvr2_init_display();
pvr2_init_display(info);
if (do_vmode_pan)
do_vmode_pan = 0;
if (do_vmode_full)
do_vmode_full = 0;
if (do_blank) {
pvr2_do_blank();
do_blank = 0;
}
if (do_vmode_full) {
do_vmode_full = 0;
}
return IRQ_HANDLED;
}
......@@ -991,94 +599,120 @@ static int pvr2_init_cable(void)
int __init pvr2fb_init(void)
{
struct fb_var_screeninfo var;
u_long modememused;
int err = -EINVAL;
if (!MACH_DREAMCAST)
if (!mach_is_dreamcast())
return -ENXIO;
fb_info = kmalloc(sizeof(struct fb_info) + sizeof(struct pvr2fb_par) +
sizeof(u32) * 16, GFP_KERNEL);
if (!fb_info) {
printk(KERN_ERR "Failed to allocate memory for fb_info\n");
return -ENOMEM;
}
memset(fb_info, 0, sizeof(fb_info) + sizeof(struct pvr2fb_par) + sizeof(u32) * 16);
currentpar = (struct pvr2fb_par *)(fb_info + 1);
/* Make a guess at the monitor based on the attached cable */
if (pvr2_init_cable() == CT_VGA) {
fb_info.monspecs.hfmin = 30000;
fb_info.monspecs.hfmax = 70000;
fb_info.monspecs.vfmin = 60;
fb_info.monspecs.vfmax = 60;
}
else { /* Not VGA, using a TV (taken from acornfb) */
fb_info.monspecs.hfmin = 15469;
fb_info.monspecs.hfmax = 15781;
fb_info.monspecs.vfmin = 49;
fb_info.monspecs.vfmax = 51;
fb_info->monspecs.hfmin = 30000;
fb_info->monspecs.hfmax = 70000;
fb_info->monspecs.vfmin = 60;
fb_info->monspecs.vfmax = 60;
} else {
/* Not VGA, using a TV (taken from acornfb) */
fb_info->monspecs.hfmin = 15469;
fb_info->monspecs.hfmax = 15781;
fb_info->monspecs.vfmin = 49;
fb_info->monspecs.vfmax = 51;
}
/* XXX: This needs to pull default video output via BIOS or other means */
/*
* XXX: This needs to pull default video output via BIOS or other means
*/
if (video_output < 0) {
if (cable_type == CT_VGA)
if (cable_type == CT_VGA) {
video_output = VO_VGA;
else
} else {
video_output = VO_NTSC;
}
}
strcpy(fb_info.modename, pvr2fb_name);
fb_info.changevar = NULL;
fb_info.fbops = &pvr2fb_ops;
fb_info.screen_base = (char *) videomemory;
fb_info.disp = &disp;
fb_info.currcon = -1;
fb_info.switch_con = &pvr2fbcon_switch;
fb_info.updatevar = &pvr2fbcon_updatevar;
fb_info.flags = FBINFO_FLAG_DEFAULT;
memset(&var, 0, sizeof(var));
pvr2_fix.smem_start = videomemory;
pvr2_fix.smem_len = videomemorysize;
fb_info->screen_base = ioremap_nocache(pvr2_fix.smem_start,
pvr2_fix.smem_len);
if (!fb_info->screen_base) {
printk("Failed to remap MMIO space\n");
err = -ENXIO;
goto out_err;
}
memset_io((unsigned long)fb_info->screen_base, 0, pvr2_fix.smem_len);
pvr2_fix.ypanstep = nopan ? 0 : 1;
pvr2_fix.ywrapstep = nowrap ? 0 : 1;
fb_info->fbops = &pvr2fb_ops;
fb_info->fix = pvr2_fix;
fb_info->par = currentpar;
fb_info->pseudo_palette = (void *)(fb_info->par + 1);
fb_info->flags = FBINFO_FLAG_DEFAULT;
if (video_output == VO_VGA)
defmode = DEFMODE_VGA;
if (!fb_find_mode(&var, &fb_info, mode_option, pvr2_modedb,
NUM_TOTAL_MODES, &pvr2_modedb[defmode], 16)) {
return -EINVAL;
}
if (!mode_option)
mode_option = "640x480@60";
if (request_irq(HW_EVENT_VSYNC, pvr2fb_interrupt, 0,
"pvr2 VBL handler", &currentpar)) {
DPRINTK("couldn't register VBL int\n");
return -EBUSY;
}
if (!fb_find_mode(&fb_info->var, fb_info, mode_option, pvr2_modedb,
NUM_TOTAL_MODES, &pvr2_modedb[defmode], 16))
fb_info->var = pvr2_var;
#ifdef CONFIG_MTRR
if (enable_mtrr) {
mtrr_handle = mtrr_add(videomemory, videomemorysize, MTRR_TYPE_WRCOMB, 1);
printk("pvr2fb: MTRR turned on\n");
if (request_irq(HW_EVENT_VSYNC, pvr2fb_interrupt, 0,
"pvr2 VBL handler", fb_info)) {
err = -EBUSY;
goto out_err;
}
#endif
pvr2fb_set_var(&var, -1, &fb_info);
if (register_framebuffer(fb_info) < 0)
goto reg_failed;
if (register_framebuffer(&fb_info) < 0)
return -EINVAL;
modememused = get_line_length(fb_info->var.xres_virtual,
fb_info->var.bits_per_pixel);
modememused *= fb_info->var.yres_virtual;
modememused = get_line_length(var.xres_virtual, var.bits_per_pixel);
modememused *= var.yres_virtual;
printk("fb%d: %s frame buffer device, using %ldk/%ldk of video memory\n",
fb_info.node, fb_info.modename, modememused>>10,
fb_info->node, fb_info->fix.id, modememused>>10,
videomemorysize>>10);
printk("fb%d: Mode %dx%d-%d pitch = %ld cable: %s video output: %s\n",
fb_info.node, var.xres, var.yres, var.bits_per_pixel,
get_line_length(var.xres, var.bits_per_pixel),
fb_info->node, fb_info->var.xres, fb_info->var.yres,
fb_info->var.bits_per_pixel,
get_line_length(fb_info->var.xres, fb_info->var.bits_per_pixel),
(char *)pvr2_get_param(cables, NULL, cable_type, 3),
(char *)pvr2_get_param(outputs, NULL, video_output, 3));
return 0;
reg_failed:
free_irq(HW_EVENT_VSYNC, 0);
out_err:
kfree(fb_info);
return err;
}
static void __exit pvr2fb_exit(void)
{
#ifdef CONFIG_MTRR
if (enable_mtrr) {
mtrr_del(mtrr_handle, videomemory, videomemorysize);
printk("pvr2fb: MTRR turned off\n");
}
#endif
unregister_framebuffer(&fb_info);
unregister_framebuffer(fb_info);
free_irq(HW_EVENT_VSYNC, 0);
kfree(fb_info);
}
static int __init pvr2_get_param(const struct pvr2_params *p, const char *s,
......@@ -1102,7 +736,6 @@ static int __init pvr2_get_param(const struct pvr2_params *p, const char *s,
* Parse command arguments. Supported arguments are:
* inverse Use inverse color maps
* nomtrr Disable MTRR usage
* font:<fontname> Specify console font
* cable:composite|rgb|vga Override the video cable type
* output:NTSC|PAL|VGA Override the video output format
*
......@@ -1117,8 +750,6 @@ int __init pvr2fb_setup(char *options)
char cable_arg[80];
char output_arg[80];
fb_info.fontname[0] = '\0';
if (!options || !*options)
return 0;
......@@ -1128,23 +759,21 @@ int __init pvr2fb_setup(char *options)
if (!strcmp(this_opt, "inverse")) {
pvr2fb_inverse = 1;
fb_invert_cmaps();
} else if (!strncmp(this_opt, "font:", 5))
strcpy(fb_info.fontname, this_opt + 5);
else if (!strncmp(this_opt, "cable:", 6))
} else if (!strncmp(this_opt, "cable:", 6)) {
strcpy(cable_arg, this_opt + 6);
else if (!strncmp(this_opt, "output:", 7))
} else if (!strncmp(this_opt, "output:", 7)) {
strcpy(output_arg, this_opt + 7);
#ifdef CONFIG_MTRR
else if (!strncmp(this_opt, "nomtrr", 6))
enable_mtrr = 0;
#endif
else
} else if (!strncmp(this_opt, "nopan", 5)) {
nopan = 1;
} else if (!strncmp(this_opt, "nowrap", 6)) {
nowrap = 1;
} else {
mode_option = this_opt;
}
}
if (*cable_arg)
cable_type = pvr2_get_param(cables, cable_arg, 0, 3);
if (*output_arg)
video_output = pvr2_get_param(outputs, output_arg, 0, 3);
......
......@@ -536,7 +536,8 @@ static ssize_t read_profile(struct file *file, char *buf,
buf++; p++; count--; read++;
}
pnt = (char *)prof_buffer + p - sizeof(unsigned int);
copy_to_user(buf,(void *)pnt,count);
if (copy_to_user(buf,(void *)pnt,count))
return -EFAULT;
read += count;
*ppos += read;
return read;
......
......@@ -6,7 +6,9 @@
#ifndef _ASMALPHA_TIMEX_H
#define _ASMALPHA_TIMEX_H
#define CLOCK_TICK_RATE 1193180 /* Underlying HZ */
/* With only one or two oddballs, we use the RTC as the ticker, selecting
the 32.768kHz reference clock, which nicely divides down to our HZ. */
#define CLOCK_TICK_RATE 32768
/*
* Standard way to access the cycle counter.
......
......@@ -359,7 +359,8 @@
#define __NR_clock_getres 421
#define __NR_clock_nanosleep 422
#define __NR_semtimedop 423
#define NR_SYSCALLS 424
#define __NR_tgkill 424
#define NR_SYSCALLS 425
#if defined(__GNUC__)
......
......@@ -107,7 +107,7 @@ static inline void x86_do_profile(struct pt_regs * regs)
atomic_inc((atomic_t *)&prof_buffer[eip]);
}
#if defined(CONFIG_X86_IO_APIC) && defined(CONFIG_SMP)
#if defined(CONFIG_X86_IO_APIC)
static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i)
{
if (IO_APIC_IRQ(i))
......
......@@ -2,7 +2,7 @@
#define _NAMESPACE_H_
#ifdef __KERNEL__
#include <linux/dcache.h>
#include <linux/mount.h>
#include <linux/sched.h>
struct namespace {
......@@ -19,9 +19,9 @@ static inline void put_namespace(struct namespace *namespace)
{
if (atomic_dec_and_test(&namespace->count)) {
down_write(&namespace->sem);
spin_lock(&dcache_lock);
spin_lock(&vfsmount_lock);
umount_tree(namespace->root);
spin_unlock(&dcache_lock);
spin_unlock(&vfsmount_lock);
up_write(&namespace->sem);
kfree(namespace);
}
......
......@@ -456,10 +456,10 @@ struct pci_bus {
void *sysdata; /* hook for sys-specific extension */
struct proc_dir_entry *procdir; /* directory entry in /proc/bus/pci */
unsigned char number; /* bus number */
unsigned char primary; /* number of primary bridge */
unsigned char secondary; /* number of secondary bridge */
unsigned char subordinate; /* max number of subordinate buses */
unsigned int number; /* bus number */
unsigned int primary; /* number of primary bridge */
unsigned int secondary; /* number of secondary bridge */
unsigned int subordinate; /* max number of subordinate buses */
char name[48];
......
......@@ -170,7 +170,6 @@ struct region_t;
struct pcmcia_socket {
struct module *owner;
spinlock_t lock;
struct pccard_operations * ss_entry;
socket_state_t socket;
u_int state;
u_short functions;
......@@ -207,6 +206,9 @@ struct pcmcia_socket {
u_char pci_irq;
struct pci_dev * cb_dev;
/* socket operations */
struct pccard_operations * ops;
/* state thread */
struct semaphore skt_sem; /* protects socket h/w state */
......
......@@ -605,6 +605,9 @@ EXPORT_SYMBOL(next_thread);
EXPORT_SYMBOL(__per_cpu_offset);
#endif
EXPORT_SYMBOL(set_fs_pwd);
EXPORT_SYMBOL(set_fs_root);
/* debug */
EXPORT_SYMBOL(dump_stack);
EXPORT_SYMBOL(ptrace_notify);
......
......@@ -2373,7 +2373,7 @@ static void tcp_fin(struct sk_buff *skb, struct sock *sk, struct tcphdr *th)
tcp_schedule_ack(tp);
sk->sk_shutdown |= RCV_SHUTDOWN;
sock_reset_flag(sk, SOCK_DONE);
sock_set_flag(sk, SOCK_DONE);
switch (sk->sk_state) {
case TCP_SYN_RECV:
......
......@@ -368,7 +368,8 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev)
dev, dev->name);
ndev->cnf.use_tempaddr = -1;
} else {
__ipv6_regen_rndid(ndev);
in6_dev_hold(ndev);
ipv6_regen_rndid((unsigned long) ndev);
}
#endif
......@@ -1122,9 +1123,6 @@ static int __ipv6_regen_rndid(struct inet6_dev *idev)
sg[1].offset = ((long) eui64 & ~PAGE_MASK);
sg[1].length = 8;
if (!del_timer(&idev->regen_timer))
in6_dev_hold(idev);
dev = idev->dev;
if (ipv6_generate_eui64(eui64, dev)) {
......@@ -1137,7 +1135,6 @@ static int __ipv6_regen_rndid(struct inet6_dev *idev)
spin_lock(&md5_tfm_lock);
if (unlikely(md5_tfm == NULL)) {
spin_unlock(&md5_tfm_lock);
in6_dev_put(idev);
return -1;
}
crypto_digest_init(md5_tfm);
......@@ -1170,33 +1167,41 @@ static int __ipv6_regen_rndid(struct inet6_dev *idev)
if ((idev->rndid[2]|idev->rndid[3]|idev->rndid[4]|idev->rndid[5]|idev->rndid[6]|idev->rndid[7]) == 0x00)
goto regen;
}
idev->regen_timer.expires = jiffies +
idev->cnf.temp_prefered_lft * HZ -
idev->cnf.regen_max_retry * idev->cnf.dad_transmits * idev->nd_parms->retrans_time - desync_factor;
if (time_before(idev->regen_timer.expires, jiffies)) {
idev->regen_timer.expires = 0;
printk(KERN_WARNING
"__ipv6_regen_rndid(): too short regeneration interval; timer disabled for %s.\n",
idev->dev->name);
in6_dev_put(idev);
return -1;
}
add_timer(&idev->regen_timer);
return 0;
}
static void ipv6_regen_rndid(unsigned long data)
{
struct inet6_dev *idev = (struct inet6_dev *) data;
unsigned long expires;
read_lock_bh(&addrconf_lock);
write_lock_bh(&idev->lock);
if (!idev->dead)
__ipv6_regen_rndid(idev);
if (idev->dead)
goto out;
if (__ipv6_regen_rndid(idev) < 0)
goto out;
expires = jiffies +
idev->cnf.temp_prefered_lft * HZ -
idev->cnf.regen_max_retry * idev->cnf.dad_transmits * idev->nd_parms->retrans_time - desync_factor;
if (time_before(expires, jiffies)) {
printk(KERN_WARNING
"ipv6_regen_rndid(): too short regeneration interval; timer disabled for %s.\n",
idev->dev->name);
goto out;
}
if (!mod_timer(&idev->regen_timer, expires))
in6_dev_hold(idev);
out:
write_unlock_bh(&idev->lock);
read_unlock_bh(&addrconf_lock);
in6_dev_put(idev);
}
static int __ipv6_try_regen_rndid(struct inet6_dev *idev, struct in6_addr *tmpaddr) {
......@@ -1928,6 +1933,27 @@ static int addrconf_ifdown(struct net_device *dev, int how)
/* Step 3: clear address list */
write_lock_bh(&idev->lock);
#ifdef CONFIG_IPV6_PRIVACY
if (how == 1 && del_timer(&idev->regen_timer))
in6_dev_put(idev);
/* clear tempaddr list */
while ((ifa = idev->tempaddr_list) != NULL) {
idev->tempaddr_list = ifa->tmp_next;
ifa->tmp_next = NULL;
ifa->dead = 1;
write_unlock_bh(&idev->lock);
spin_lock_bh(&ifa->lock);
if (ifa->ifpub) {
in6_ifa_put(ifa->ifpub);
ifa->ifpub = NULL;
}
spin_unlock_bh(&ifa->lock);
in6_ifa_put(ifa);
write_lock_bh(&idev->lock);
}
#endif
while ((ifa = idev->addr_list) != NULL) {
idev->addr_list = ifa->if_next;
ifa->if_next = NULL;
......
......@@ -668,7 +668,7 @@ static int wanrouter_device_stat(struct wan_device *wandev,
static int wanrouter_device_new_if(struct wan_device *wandev,
wanif_conf_t *u_conf)
{
wanif_conf_t conf;
wanif_conf_t *cnf;
struct net_device *dev = NULL;
#ifdef CONFIG_WANPIPE_MULTPPP
struct ppp_device *pppdev=NULL;
......@@ -678,38 +678,47 @@ static int wanrouter_device_new_if(struct wan_device *wandev,
if ((wandev->state == WAN_UNCONFIGURED) || (wandev->new_if == NULL))
return -ENODEV;
if (copy_from_user(&conf, u_conf, sizeof(wanif_conf_t)))
return -EFAULT;
cnf = kmalloc(sizeof(wanif_conf_t), GFP_KERNEL);
if (!cnf)
return -ENOBUFS;
if (conf.magic != ROUTER_MAGIC)
return -EINVAL;
err = -EFAULT;
if (copy_from_user(cnf, u_conf, sizeof(wanif_conf_t)))
goto out;
err = -EINVAL;
if (cnf->magic != ROUTER_MAGIC)
goto out;
if (conf.config_id == WANCONFIG_MPPP) {
if (cnf->config_id == WANCONFIG_MPPP) {
#ifdef CONFIG_WANPIPE_MULTPPP
pppdev = kmalloc(sizeof(struct ppp_device), GFP_KERNEL);
err = -ENOBUFS;
if (pppdev == NULL)
return -ENOBUFS;
goto out;
memset(pppdev, 0, sizeof(struct ppp_device));
pppdev->dev = kmalloc(sizeof(struct net_device), GFP_KERNEL);
if (pppdev->dev == NULL) {
kfree(pppdev);
return -ENOBUFS;
err = -ENOBUFS;
goto out;
}
memset(pppdev->dev, 0, sizeof(struct net_device));
err = wandev->new_if(wandev,
(struct net_device *)pppdev, &conf);
err = wandev->new_if(wandev, (struct net_device *)pppdev, cnf);
dev = pppdev->dev;
#else
printk(KERN_INFO "%s: Wanpipe Mulit-Port PPP support has not been compiled in!\n",
wandev->name);
return -EPROTONOSUPPORT;
err = -EPROTONOSUPPORT;
goto out;
#endif
} else {
dev = kmalloc(sizeof(struct net_device), GFP_KERNEL);
err = -ENOBUFS;
if (dev == NULL)
return -ENOBUFS;
goto out;
memset(dev, 0, sizeof(struct net_device));
err = wandev->new_if(wandev, dev, &conf);
err = wandev->new_if(wandev, dev, cnf);
}
if (!err) {
......@@ -748,7 +757,8 @@ static int wanrouter_device_new_if(struct wan_device *wandev,
++wandev->ndev;
unlock_adapter_irq(&wandev->lock, &smp_flags);
return 0; /* done !!! */
err = 0; /* done !!! */
goto out;
}
}
if (wandev->del_if)
......@@ -761,18 +771,19 @@ static int wanrouter_device_new_if(struct wan_device *wandev,
dev->priv = NULL;
}
#ifdef CONFIG_WANPIPE_MULTPPP
if (conf.config_id == WANCONFIG_MPPP)
if (cnf->config_id == WANCONFIG_MPPP)
kfree(pppdev);
else
kfree(dev);
#else
/* Sync PPP is disabled */
if (conf.config_id != WANCONFIG_MPPP)
if (cnf->config_id != WANCONFIG_MPPP)
kfree(dev);
#endif
out:
kfree(cnf);
return err;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment