forked from Minki/linux
Merge git://git.kernel.org/pub/scm/linux/kernel/git/brodo/pcmcia-2.6/
* git://git.kernel.org/pub/scm/linux/kernel/git/brodo/pcmcia-2.6/: [PATCH] pcmcia: fix deadlock in pcmcia_parse_events [PATCH] com20020_cs: more device support [PATCH] au1xxx: pcmcia: fix __init called from non-init [PATCH] kill open-coded offsetof in cm4000_cs.c ZERO_DEV() [PATCH] pcmcia: convert pcmcia_cs to kthread [PATCH] pcmcia: fix kernel-doc function name [PATCH] pcmcia: hostap_cs.c - 0xc00f,0x0000 conflicts with pcnet_cs [PATCH] pcmcia: at91_cf suspend/resume/wakeup [PATCH] pcmcia: Make ide_cs work with the memory space of CF-Cards if IO space is not available [PATCH] pcmcia: TI PCIxx12 CardBus controller support [PATCH] pcmcia: warn if driver requests exclusive, but gets a shared IRQ [PATCH] pcmcia: expose tool in pcmcia/Documentation/pcmcia/ [PATCH] pcmcia: another ID for serial_cs.c [PATCH] yenta: fix hidden PCI bus numbers [PATCH] yenta: do power-up only after socket is configured
This commit is contained in:
commit
39302175c2
32
Documentation/pcmcia/crc32hash.c
Normal file
32
Documentation/pcmcia/crc32hash.c
Normal file
@ -0,0 +1,32 @@
|
||||
/* crc32hash.c - derived from linux/lib/crc32.c, GNU GPL v2 */
|
||||
/* Usage example:
|
||||
$ ./crc32hash "Dual Speed"
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
unsigned int crc32(unsigned char const *p, unsigned int len)
|
||||
{
|
||||
int i;
|
||||
unsigned int crc = 0;
|
||||
while (len--) {
|
||||
crc ^= *p++;
|
||||
for (i = 0; i < 8; i++)
|
||||
crc = (crc >> 1) ^ ((crc & 1) ? 0xedb88320 : 0);
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
unsigned int result;
|
||||
if (argc != 2) {
|
||||
printf("no string passed as argument\n");
|
||||
return -1;
|
||||
}
|
||||
result = crc32(argv[1], strlen(argv[1]));
|
||||
printf("0x%x\n", result);
|
||||
return 0;
|
||||
}
|
@ -27,37 +27,7 @@ pcmcia:m0149cC1ABf06pfn00fn00pa725B842DpbF1EFEE84pc0877B627pd00000000
|
||||
The hex value after "pa" is the hash of product ID string 1, after "pb" for
|
||||
string 2 and so on.
|
||||
|
||||
Alternatively, you can use this small tool to determine the crc32 hash.
|
||||
simply pass the string you want to evaluate as argument to this program,
|
||||
e.g.
|
||||
Alternatively, you can use crc32hash (see Documentation/pcmcia/crc32hash.c)
|
||||
to determine the crc32 hash. Simply pass the string you want to evaluate
|
||||
as argument to this program, e.g.:
|
||||
$ ./crc32hash "Dual Speed"
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
/* crc32hash.c - derived from linux/lib/crc32.c, GNU GPL v2 */
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
unsigned int crc32(unsigned char const *p, unsigned int len)
|
||||
{
|
||||
int i;
|
||||
unsigned int crc = 0;
|
||||
while (len--) {
|
||||
crc ^= *p++;
|
||||
for (i = 0; i < 8; i++)
|
||||
crc = (crc >> 1) ^ ((crc & 1) ? 0xedb88320 : 0);
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
unsigned int result;
|
||||
if (argc != 2) {
|
||||
printf("no string passed as argument\n");
|
||||
return -1;
|
||||
}
|
||||
result = crc32(argv[1], strlen(argv[1]));
|
||||
printf("0x%x\n", result);
|
||||
return 0;
|
||||
}
|
||||
|
@ -149,12 +149,7 @@ struct cm4000_dev {
|
||||
#define ZERO_DEV(dev) \
|
||||
memset(&dev->atr_csum,0, \
|
||||
sizeof(struct cm4000_dev) - \
|
||||
/*link*/ sizeof(struct pcmcia_device *) - \
|
||||
/*node*/ sizeof(dev_node_t) - \
|
||||
/*atr*/ MAX_ATR*sizeof(char) - \
|
||||
/*rbuf*/ 512*sizeof(char) - \
|
||||
/*sbuf*/ 512*sizeof(char) - \
|
||||
/*queue*/ 4*sizeof(wait_queue_head_t))
|
||||
offsetof(struct cm4000_dev, atr_csum))
|
||||
|
||||
static struct pcmcia_device *dev_table[CM4000_MAX_DEV];
|
||||
static struct class *cmm_class;
|
||||
|
@ -146,7 +146,16 @@ static void ide_detach(struct pcmcia_device *link)
|
||||
kfree(link->priv);
|
||||
} /* ide_detach */
|
||||
|
||||
static int idecs_register(unsigned long io, unsigned long ctl, unsigned long irq, struct pcmcia_device *handle)
|
||||
static void idecs_mmio_fixup(ide_hwif_t *hwif)
|
||||
{
|
||||
default_hwif_mmiops(hwif);
|
||||
hwif->mmio = 2;
|
||||
|
||||
ide_undecoded_slave(hwif);
|
||||
}
|
||||
|
||||
static int idecs_register(unsigned long io, unsigned long ctl,
|
||||
unsigned long irq, struct pcmcia_device *handle, int is_mmio)
|
||||
{
|
||||
hw_regs_t hw;
|
||||
memset(&hw, 0, sizeof(hw));
|
||||
@ -154,7 +163,19 @@ static int idecs_register(unsigned long io, unsigned long ctl, unsigned long irq
|
||||
hw.irq = irq;
|
||||
hw.chipset = ide_pci;
|
||||
hw.dev = &handle->dev;
|
||||
return ide_register_hw_with_fixup(&hw, NULL, ide_undecoded_slave);
|
||||
|
||||
if(is_mmio)
|
||||
return ide_register_hw_with_fixup(&hw, NULL, idecs_mmio_fixup);
|
||||
else
|
||||
return ide_register_hw_with_fixup(&hw, NULL, ide_undecoded_slave);
|
||||
}
|
||||
|
||||
void outb_io(unsigned char value, unsigned long port) {
|
||||
outb(value, port);
|
||||
}
|
||||
|
||||
void outb_mem(unsigned char value, unsigned long port) {
|
||||
writeb(value, (void __iomem *) port);
|
||||
}
|
||||
|
||||
/*======================================================================
|
||||
@ -180,7 +201,8 @@ static int ide_config(struct pcmcia_device *link)
|
||||
} *stk = NULL;
|
||||
cistpl_cftable_entry_t *cfg;
|
||||
int i, pass, last_ret = 0, last_fn = 0, hd, is_kme = 0;
|
||||
unsigned long io_base, ctl_base;
|
||||
unsigned long io_base, ctl_base, is_mmio, try_slave;
|
||||
void (*my_outb)(unsigned char, unsigned long);
|
||||
|
||||
DEBUG(0, "ide_config(0x%p)\n", link);
|
||||
|
||||
@ -210,7 +232,7 @@ static int ide_config(struct pcmcia_device *link)
|
||||
/* Not sure if this is right... look up the current Vcc */
|
||||
CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(link, &stk->conf));
|
||||
|
||||
pass = io_base = ctl_base = 0;
|
||||
pass = io_base = ctl_base = is_mmio = try_slave = 0;
|
||||
tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
|
||||
tuple.Attributes = 0;
|
||||
CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple));
|
||||
@ -258,11 +280,45 @@ static int ide_config(struct pcmcia_device *link)
|
||||
goto next_entry;
|
||||
io_base = link->io.BasePort1;
|
||||
ctl_base = link->io.BasePort1 + 0x0e;
|
||||
|
||||
if (io->win[0].len >= 0x20)
|
||||
try_slave = 1;
|
||||
|
||||
} else goto next_entry;
|
||||
/* If we've got this far, we're done */
|
||||
break;
|
||||
}
|
||||
|
||||
if ((cfg->mem.nwin > 0) || (stk->dflt.mem.nwin > 0)) {
|
||||
win_req_t req;
|
||||
memreq_t map;
|
||||
cistpl_mem_t *mem = (cfg->mem.nwin) ? &cfg->mem : &stk->dflt.mem;
|
||||
|
||||
if (mem->win[0].len < 16)
|
||||
goto next_entry;
|
||||
|
||||
req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM;
|
||||
req.Attributes |= WIN_ENABLE;
|
||||
req.Base = mem->win[0].host_addr;
|
||||
req.Size = 0;
|
||||
|
||||
req.AccessSpeed = 0;
|
||||
if (pcmcia_request_window(&link, &req, &link->win) != 0)
|
||||
goto next_entry;
|
||||
map.Page = 0; map.CardOffset = mem->win[0].card_addr;
|
||||
if (pcmcia_map_mem_page(link->win, &map) != 0)
|
||||
goto next_entry;
|
||||
|
||||
io_base = (unsigned long) ioremap(req.Base, req.Size);
|
||||
ctl_base = io_base + 0x0e;
|
||||
is_mmio = 1;
|
||||
|
||||
if (mem->win[0].len >= 0x20)
|
||||
try_slave = 1;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
next_entry:
|
||||
if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
|
||||
memcpy(&stk->dflt, cfg, sizeof(stk->dflt));
|
||||
@ -278,21 +334,26 @@ static int ide_config(struct pcmcia_device *link)
|
||||
CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
|
||||
CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
|
||||
|
||||
if(is_mmio)
|
||||
my_outb = outb_mem;
|
||||
else
|
||||
my_outb = outb_io;
|
||||
|
||||
/* disable drive interrupts during IDE probe */
|
||||
outb(0x02, ctl_base);
|
||||
my_outb(0x02, ctl_base);
|
||||
|
||||
/* special setup for KXLC005 card */
|
||||
if (is_kme)
|
||||
outb(0x81, ctl_base+1);
|
||||
my_outb(0x81, ctl_base+1);
|
||||
|
||||
/* retry registration in case device is still spinning up */
|
||||
for (hd = -1, i = 0; i < 10; i++) {
|
||||
hd = idecs_register(io_base, ctl_base, link->irq.AssignedIRQ, link);
|
||||
hd = idecs_register(io_base, ctl_base, link->irq.AssignedIRQ, link, is_mmio);
|
||||
if (hd >= 0) break;
|
||||
if (link->io.NumPorts1 == 0x20) {
|
||||
outb(0x02, ctl_base + 0x10);
|
||||
if (try_slave) {
|
||||
my_outb(0x02, ctl_base + 0x10);
|
||||
hd = idecs_register(io_base + 0x10, ctl_base + 0x10,
|
||||
link->irq.AssignedIRQ, link);
|
||||
link->irq.AssignedIRQ, link, is_mmio);
|
||||
if (hd >= 0) {
|
||||
io_base += 0x10;
|
||||
ctl_base += 0x10;
|
||||
|
@ -387,7 +387,10 @@ static int com20020_resume(struct pcmcia_device *link)
|
||||
}
|
||||
|
||||
static struct pcmcia_device_id com20020_ids[] = {
|
||||
PCMCIA_DEVICE_PROD_ID12("Contemporary Control Systems, Inc.", "PCM20 Arcnet Adapter", 0x59991666, 0x95dfffaf),
|
||||
PCMCIA_DEVICE_PROD_ID12("Contemporary Control Systems, Inc.",
|
||||
"PCM20 Arcnet Adapter", 0x59991666, 0x95dfffaf),
|
||||
PCMCIA_DEVICE_PROD_ID12("SoHard AG",
|
||||
"SH ARC PCMCIA", 0xf8991729, 0x69dff0c7),
|
||||
PCMCIA_DEVICE_NULL
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pcmcia, com20020_ids);
|
||||
|
@ -844,7 +844,7 @@ static struct pcmcia_device_id hostap_cs_ids[] = {
|
||||
PCMCIA_DEVICE_MANF_CARD(0x02d2, 0x0001),
|
||||
PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x0001),
|
||||
PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x7300),
|
||||
PCMCIA_DEVICE_MANF_CARD(0xc00f, 0x0000),
|
||||
/* PCMCIA_DEVICE_MANF_CARD(0xc00f, 0x0000), conflict with pcnet_cs */
|
||||
PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0002),
|
||||
PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0005),
|
||||
PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0010),
|
||||
|
@ -214,11 +214,10 @@ static struct pccard_operations at91_cf_ops = {
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
static int __init at91_cf_probe(struct device *dev)
|
||||
static int __init at91_cf_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct at91_cf_socket *cf;
|
||||
struct at91_cf_data *board = dev->platform_data;
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct at91_cf_data *board = pdev->dev.platform_data;
|
||||
struct resource *io;
|
||||
unsigned int csa;
|
||||
int status;
|
||||
@ -236,7 +235,7 @@ static int __init at91_cf_probe(struct device *dev)
|
||||
|
||||
cf->board = board;
|
||||
cf->pdev = pdev;
|
||||
dev_set_drvdata(dev, cf);
|
||||
platform_set_drvdata(pdev, cf);
|
||||
|
||||
/* CF takes over CS4, CS5, CS6 */
|
||||
csa = at91_sys_read(AT91_EBI_CSA);
|
||||
@ -271,6 +270,7 @@ static int __init at91_cf_probe(struct device *dev)
|
||||
SA_SAMPLE_RANDOM, driver_name, cf);
|
||||
if (status < 0)
|
||||
goto fail0;
|
||||
device_init_wakeup(&pdev->dev, 1);
|
||||
|
||||
/*
|
||||
* The card driver will request this irq later as needed.
|
||||
@ -301,7 +301,7 @@ static int __init at91_cf_probe(struct device *dev)
|
||||
board->det_pin, board->irq_pin);
|
||||
|
||||
cf->socket.owner = THIS_MODULE;
|
||||
cf->socket.dev.dev = dev;
|
||||
cf->socket.dev.dev = &pdev->dev;
|
||||
cf->socket.ops = &at91_cf_ops;
|
||||
cf->socket.resource_ops = &pccard_static_ops;
|
||||
cf->socket.features = SS_CAP_PCCARD | SS_CAP_STATIC_MAP
|
||||
@ -323,21 +323,25 @@ fail1:
|
||||
free_irq(board->irq_pin, cf);
|
||||
fail0a:
|
||||
free_irq(board->det_pin, cf);
|
||||
device_init_wakeup(&pdev->dev, 0);
|
||||
fail0:
|
||||
at91_sys_write(AT91_EBI_CSA, csa);
|
||||
kfree(cf);
|
||||
return status;
|
||||
}
|
||||
|
||||
static int __exit at91_cf_remove(struct device *dev)
|
||||
static int __exit at91_cf_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct at91_cf_socket *cf = dev_get_drvdata(dev);
|
||||
struct at91_cf_socket *cf = platform_get_drvdata(pdev);
|
||||
struct at91_cf_data *board = cf->board;
|
||||
struct resource *io = cf->socket.io[0].res;
|
||||
unsigned int csa;
|
||||
|
||||
pcmcia_unregister_socket(&cf->socket);
|
||||
free_irq(cf->board->irq_pin, cf);
|
||||
free_irq(cf->board->det_pin, cf);
|
||||
if (board->irq_pin)
|
||||
free_irq(board->irq_pin, cf);
|
||||
free_irq(board->det_pin, cf);
|
||||
device_init_wakeup(&pdev->dev, 0);
|
||||
iounmap((void __iomem *) cf->socket.io_offset);
|
||||
release_mem_region(io->start, io->end + 1 - io->start);
|
||||
|
||||
@ -348,26 +352,65 @@ static int __exit at91_cf_remove(struct device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct device_driver at91_cf_driver = {
|
||||
.name = (char *) driver_name,
|
||||
.bus = &platform_bus_type,
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
static int at91_cf_suspend(struct platform_device *pdev, pm_message_t mesg)
|
||||
{
|
||||
struct at91_cf_socket *cf = platform_get_drvdata(pdev);
|
||||
struct at91_cf_data *board = cf->board;
|
||||
|
||||
pcmcia_socket_dev_suspend(&pdev->dev, mesg);
|
||||
if (device_may_wakeup(&pdev->dev))
|
||||
enable_irq_wake(board->det_pin);
|
||||
else {
|
||||
disable_irq_wake(board->det_pin);
|
||||
disable_irq(board->det_pin);
|
||||
}
|
||||
if (board->irq_pin)
|
||||
disable_irq(board->irq_pin);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int at91_cf_resume(struct platform_device *pdev)
|
||||
{
|
||||
struct at91_cf_socket *cf = platform_get_drvdata(pdev);
|
||||
struct at91_cf_data *board = cf->board;
|
||||
|
||||
if (board->irq_pin)
|
||||
enable_irq(board->irq_pin);
|
||||
if (!device_may_wakeup(&pdev->dev))
|
||||
enable_irq(board->det_pin);
|
||||
pcmcia_socket_dev_resume(&pdev->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
#define at91_cf_suspend NULL
|
||||
#define at91_cf_resume NULL
|
||||
#endif
|
||||
|
||||
static struct platform_driver at91_cf_driver = {
|
||||
.driver = {
|
||||
.name = (char *) driver_name,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = at91_cf_probe,
|
||||
.remove = __exit_p(at91_cf_remove),
|
||||
.suspend = pcmcia_socket_dev_suspend,
|
||||
.resume = pcmcia_socket_dev_resume,
|
||||
.suspend = at91_cf_suspend,
|
||||
.resume = at91_cf_resume,
|
||||
};
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
static int __init at91_cf_init(void)
|
||||
{
|
||||
return driver_register(&at91_cf_driver);
|
||||
return platform_driver_register(&at91_cf_driver);
|
||||
}
|
||||
module_init(at91_cf_init);
|
||||
|
||||
static void __exit at91_cf_exit(void)
|
||||
{
|
||||
driver_unregister(&at91_cf_driver);
|
||||
platform_driver_unregister(&at91_cf_driver);
|
||||
}
|
||||
module_exit(at91_cf_exit);
|
||||
|
||||
|
@ -296,7 +296,7 @@ struct pcmcia_low_level db1x00_pcmcia_ops = {
|
||||
.socket_suspend = db1x00_socket_suspend
|
||||
};
|
||||
|
||||
int __init au1x_board_init(struct device *dev)
|
||||
int au1x_board_init(struct device *dev)
|
||||
{
|
||||
int ret = -ENODEV;
|
||||
bcsr->pcmcia = 0; /* turn off power, if it's not already off */
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include <linux/pm.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <asm/system.h>
|
||||
#include <asm/irq.h>
|
||||
|
||||
@ -176,6 +177,7 @@ static int pccardd(void *__skt);
|
||||
*/
|
||||
int pcmcia_register_socket(struct pcmcia_socket *socket)
|
||||
{
|
||||
struct task_struct *tsk;
|
||||
int ret;
|
||||
|
||||
if (!socket || !socket->ops || !socket->dev.dev || !socket->resource_ops)
|
||||
@ -239,15 +241,18 @@ int pcmcia_register_socket(struct pcmcia_socket *socket)
|
||||
mutex_init(&socket->skt_mutex);
|
||||
spin_lock_init(&socket->thread_lock);
|
||||
|
||||
ret = kernel_thread(pccardd, socket, CLONE_KERNEL);
|
||||
if (ret < 0)
|
||||
tsk = kthread_run(pccardd, socket, "pccardd");
|
||||
if (IS_ERR(tsk)) {
|
||||
ret = PTR_ERR(tsk);
|
||||
goto err;
|
||||
}
|
||||
|
||||
wait_for_completion(&socket->thread_done);
|
||||
if(!socket->thread) {
|
||||
if (!socket->thread) {
|
||||
printk(KERN_WARNING "PCMCIA: warning: socket thread for socket %p did not start\n", socket);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
pcmcia_parse_events(socket, SS_DETECT);
|
||||
|
||||
return 0;
|
||||
@ -272,10 +277,8 @@ void pcmcia_unregister_socket(struct pcmcia_socket *socket)
|
||||
cs_dbg(socket, 0, "pcmcia_unregister_socket(0x%p)\n", socket->ops);
|
||||
|
||||
if (socket->thread) {
|
||||
init_completion(&socket->thread_done);
|
||||
socket->thread = NULL;
|
||||
wake_up(&socket->thread_wait);
|
||||
wait_for_completion(&socket->thread_done);
|
||||
kthread_stop(socket->thread);
|
||||
}
|
||||
release_cis_mem(socket);
|
||||
|
||||
@ -630,8 +633,6 @@ static int pccardd(void *__skt)
|
||||
DECLARE_WAITQUEUE(wait, current);
|
||||
int ret;
|
||||
|
||||
daemonize("pccardd");
|
||||
|
||||
skt->thread = current;
|
||||
skt->socket = dead_socket;
|
||||
skt->ops->init(skt);
|
||||
@ -643,7 +644,8 @@ static int pccardd(void *__skt)
|
||||
printk(KERN_WARNING "PCMCIA: unable to register socket 0x%p\n",
|
||||
skt);
|
||||
skt->thread = NULL;
|
||||
complete_and_exit(&skt->thread_done, 0);
|
||||
complete(&skt->thread_done);
|
||||
return 0;
|
||||
}
|
||||
|
||||
add_wait_queue(&skt->thread_wait, &wait);
|
||||
@ -674,7 +676,7 @@ static int pccardd(void *__skt)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!skt->thread)
|
||||
if (kthread_should_stop())
|
||||
break;
|
||||
|
||||
schedule();
|
||||
@ -688,7 +690,7 @@ static int pccardd(void *__skt)
|
||||
/* remove from the device core */
|
||||
class_device_unregister(&skt->dev);
|
||||
|
||||
complete_and_exit(&skt->thread_done, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -697,11 +699,12 @@ static int pccardd(void *__skt)
|
||||
*/
|
||||
void pcmcia_parse_events(struct pcmcia_socket *s, u_int events)
|
||||
{
|
||||
unsigned long flags;
|
||||
cs_dbg(s, 4, "parse_events: events %08x\n", events);
|
||||
if (s->thread) {
|
||||
spin_lock(&s->thread_lock);
|
||||
spin_lock_irqsave(&s->thread_lock, flags);
|
||||
s->thread_events |= events;
|
||||
spin_unlock(&s->thread_lock);
|
||||
spin_unlock_irqrestore(&s->thread_lock, flags);
|
||||
|
||||
wake_up(&s->thread_wait);
|
||||
}
|
||||
|
@ -788,6 +788,7 @@ int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req)
|
||||
struct pcmcia_socket *s = p_dev->socket;
|
||||
config_t *c;
|
||||
int ret = CS_IN_USE, irq = 0;
|
||||
int type;
|
||||
|
||||
if (!(s->state & SOCKET_PRESENT))
|
||||
return CS_NO_CARD;
|
||||
@ -797,6 +798,13 @@ int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req)
|
||||
if (c->state & CONFIG_IRQ_REQ)
|
||||
return CS_IN_USE;
|
||||
|
||||
/* Decide what type of interrupt we are registering */
|
||||
type = 0;
|
||||
if (s->functions > 1) /* All of this ought to be handled higher up */
|
||||
type = SA_SHIRQ;
|
||||
if (req->Attributes & IRQ_TYPE_DYNAMIC_SHARING)
|
||||
type = SA_SHIRQ;
|
||||
|
||||
#ifdef CONFIG_PCMCIA_PROBE
|
||||
if (s->irq.AssignedIRQ != 0) {
|
||||
/* If the interrupt is already assigned, it must be the same */
|
||||
@ -822,9 +830,7 @@ int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req)
|
||||
* marked as used by the kernel resource management core */
|
||||
ret = request_irq(irq,
|
||||
(req->Attributes & IRQ_HANDLE_PRESENT) ? req->Handler : test_action,
|
||||
((req->Attributes & IRQ_TYPE_DYNAMIC_SHARING) ||
|
||||
(s->functions > 1) ||
|
||||
(irq == s->pci_irq)) ? SA_SHIRQ : 0,
|
||||
type,
|
||||
p_dev->devname,
|
||||
(req->Attributes & IRQ_HANDLE_PRESENT) ? req->Instance : data);
|
||||
if (!ret) {
|
||||
@ -839,18 +845,21 @@ int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req)
|
||||
if (ret && !s->irq.AssignedIRQ) {
|
||||
if (!s->pci_irq)
|
||||
return ret;
|
||||
type = SA_SHIRQ;
|
||||
irq = s->pci_irq;
|
||||
}
|
||||
|
||||
if (ret && req->Attributes & IRQ_HANDLE_PRESENT) {
|
||||
if (request_irq(irq, req->Handler,
|
||||
((req->Attributes & IRQ_TYPE_DYNAMIC_SHARING) ||
|
||||
(s->functions > 1) ||
|
||||
(irq == s->pci_irq)) ? SA_SHIRQ : 0,
|
||||
p_dev->devname, req->Instance))
|
||||
if (ret && (req->Attributes & IRQ_HANDLE_PRESENT)) {
|
||||
if (request_irq(irq, req->Handler, type, p_dev->devname, req->Instance))
|
||||
return CS_IN_USE;
|
||||
}
|
||||
|
||||
/* Make sure the fact the request type was overridden is passed back */
|
||||
if (type == SA_SHIRQ && !(req->Attributes & IRQ_TYPE_DYNAMIC_SHARING)) {
|
||||
req->Attributes |= IRQ_TYPE_DYNAMIC_SHARING;
|
||||
printk(KERN_WARNING "pcmcia: request for exclusive IRQ could not be fulfilled.\n");
|
||||
printk(KERN_WARNING "pcmcia: the driver needs updating to supported shared IRQ lines.\n");
|
||||
}
|
||||
c->irq.Attributes = req->Attributes;
|
||||
s->irq.AssignedIRQ = req->AssignedIRQ = irq;
|
||||
s->irq.Config++;
|
||||
|
@ -647,6 +647,7 @@ static int ti12xx_2nd_slot_empty(struct yenta_socket *socket)
|
||||
*/
|
||||
break;
|
||||
|
||||
case PCI_DEVICE_ID_TI_XX12:
|
||||
case PCI_DEVICE_ID_TI_X515:
|
||||
case PCI_DEVICE_ID_TI_X420:
|
||||
case PCI_DEVICE_ID_TI_X620:
|
||||
|
@ -287,7 +287,10 @@ static int yenta_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
|
||||
struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket);
|
||||
u16 bridge;
|
||||
|
||||
yenta_set_power(socket, state);
|
||||
/* if powering down: do it immediately */
|
||||
if (state->Vcc == 0)
|
||||
yenta_set_power(socket, state);
|
||||
|
||||
socket->io_irq = state->io_irq;
|
||||
bridge = config_readw(socket, CB_BRIDGE_CONTROL) & ~(CB_BRIDGE_CRST | CB_BRIDGE_INTR);
|
||||
if (cb_readl(socket, CB_SOCKET_STATE) & CB_CBCARD) {
|
||||
@ -339,6 +342,10 @@ static int yenta_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
|
||||
/* Socket event mask: get card insert/remove events.. */
|
||||
cb_writel(socket, CB_SOCKET_EVENT, -1);
|
||||
cb_writel(socket, CB_SOCKET_MASK, CB_CDMASK);
|
||||
|
||||
/* if powering up: do it as the last step when the socket is configured */
|
||||
if (state->Vcc != 0)
|
||||
yenta_set_power(socket, state);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -998,6 +1005,77 @@ static void yenta_config_init(struct yenta_socket *socket)
|
||||
config_writew(socket, CB_BRIDGE_CONTROL, bridge);
|
||||
}
|
||||
|
||||
/**
|
||||
* yenta_fixup_parent_bridge - Fix subordinate bus# of the parent bridge
|
||||
* @cardbus_bridge: The PCI bus which the CardBus bridge bridges to
|
||||
*
|
||||
* Checks if devices on the bus which the CardBus bridge bridges to would be
|
||||
* invisible during PCI scans because of a misconfigured subordinate number
|
||||
* of the parent brige - some BIOSes seem to be too lazy to set it right.
|
||||
* Does the fixup carefully by checking how far it can go without conflicts.
|
||||
* See http://bugzilla.kernel.org/show_bug.cgi?id=2944 for more information.
|
||||
*/
|
||||
static void yenta_fixup_parent_bridge(struct pci_bus *cardbus_bridge)
|
||||
{
|
||||
struct list_head *tmp;
|
||||
unsigned char upper_limit;
|
||||
/*
|
||||
* We only check and fix the parent bridge: All systems which need
|
||||
* this fixup that have been reviewed are laptops and the only bridge
|
||||
* which needed fixing was the parent bridge of the CardBus bridge:
|
||||
*/
|
||||
struct pci_bus *bridge_to_fix = cardbus_bridge->parent;
|
||||
|
||||
/* Check bus numbers are already set up correctly: */
|
||||
if (bridge_to_fix->subordinate >= cardbus_bridge->subordinate)
|
||||
return; /* The subordinate number is ok, nothing to do */
|
||||
|
||||
if (!bridge_to_fix->parent)
|
||||
return; /* Root bridges are ok */
|
||||
|
||||
/* stay within the limits of the bus range of the parent: */
|
||||
upper_limit = bridge_to_fix->parent->subordinate;
|
||||
|
||||
/* check the bus ranges of all silbling bridges to prevent overlap */
|
||||
list_for_each(tmp, &bridge_to_fix->parent->children) {
|
||||
struct pci_bus * silbling = pci_bus_b(tmp);
|
||||
/*
|
||||
* If the silbling has a higher secondary bus number
|
||||
* and it's secondary is equal or smaller than our
|
||||
* current upper limit, set the new upper limit to
|
||||
* the bus number below the silbling's range:
|
||||
*/
|
||||
if (silbling->secondary > bridge_to_fix->subordinate
|
||||
&& silbling->secondary <= upper_limit)
|
||||
upper_limit = silbling->secondary - 1;
|
||||
}
|
||||
|
||||
/* Show that the wanted subordinate number is not possible: */
|
||||
if (cardbus_bridge->subordinate > upper_limit)
|
||||
printk(KERN_WARNING "Yenta: Upper limit for fixing this "
|
||||
"bridge's parent bridge: #%02x\n", upper_limit);
|
||||
|
||||
/* If we have room to increase the bridge's subordinate number, */
|
||||
if (bridge_to_fix->subordinate < upper_limit) {
|
||||
|
||||
/* use the highest number of the hidden bus, within limits */
|
||||
unsigned char subordinate_to_assign =
|
||||
min(cardbus_bridge->subordinate, upper_limit);
|
||||
|
||||
printk(KERN_INFO "Yenta: Raising subordinate bus# of parent "
|
||||
"bus (#%02x) from #%02x to #%02x\n",
|
||||
bridge_to_fix->number,
|
||||
bridge_to_fix->subordinate, subordinate_to_assign);
|
||||
|
||||
/* Save the new subordinate in the bus struct of the bridge */
|
||||
bridge_to_fix->subordinate = subordinate_to_assign;
|
||||
|
||||
/* and update the PCI config space with the new subordinate */
|
||||
pci_write_config_byte(bridge_to_fix->self,
|
||||
PCI_SUBORDINATE_BUS, bridge_to_fix->subordinate);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize a cardbus controller. Make sure we have a usable
|
||||
* interrupt, and that we can map the cardbus area. Fill in the
|
||||
@ -1113,6 +1191,8 @@ static int __devinit yenta_probe (struct pci_dev *dev, const struct pci_device_i
|
||||
yenta_get_socket_capabilities(socket, isa_interrupts);
|
||||
printk(KERN_INFO "Socket status: %08x\n", cb_readl(socket, CB_SOCKET_STATE));
|
||||
|
||||
yenta_fixup_parent_bridge(dev->subordinate);
|
||||
|
||||
/* Register it with the pcmcia layer.. */
|
||||
ret = pcmcia_register_socket(&socket->socket);
|
||||
if (ret == 0) {
|
||||
@ -1232,6 +1312,7 @@ static struct pci_device_id yenta_table [] = {
|
||||
|
||||
CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_XX21_XX11, TI12XX),
|
||||
CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_X515, TI12XX),
|
||||
CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_XX12, TI12XX),
|
||||
CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_X420, TI12XX),
|
||||
CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_X620, TI12XX),
|
||||
CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_7410, TI12XX),
|
||||
|
@ -786,6 +786,7 @@ static struct pcmcia_device_id serial_ids[] = {
|
||||
PCMCIA_DEVICE_CIS_PROD_ID12("ADVANTECH", "COMpad-32/85B-4", 0x96913a85, 0xcec8f102, "COMpad4.cis"),
|
||||
PCMCIA_DEVICE_CIS_PROD_ID123("ADVANTECH", "COMpad-32/85", "1.0", 0x96913a85, 0x8fbe92ae, 0x0877b627, "COMpad2.cis"),
|
||||
PCMCIA_DEVICE_CIS_PROD_ID2("RS-COM 2P", 0xad20b156, "RS-COM-2P.cis"),
|
||||
PCMCIA_DEVICE_CIS_MANF_CARD(0x0013, 0x0000, "GLOBETROTTER.cis"),
|
||||
/* too generic */
|
||||
/* PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0160, 0x0002), */
|
||||
/* PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x0160, 0x0002), */
|
||||
|
@ -729,6 +729,7 @@
|
||||
#define PCI_DEVICE_ID_TI_4450 0x8011
|
||||
#define PCI_DEVICE_ID_TI_XX21_XX11 0x8031
|
||||
#define PCI_DEVICE_ID_TI_X515 0x8036
|
||||
#define PCI_DEVICE_ID_TI_XX12 0x8039
|
||||
#define PCI_DEVICE_ID_TI_1130 0xac12
|
||||
#define PCI_DEVICE_ID_TI_1031 0xac13
|
||||
#define PCI_DEVICE_ID_TI_1131 0xac15
|
||||
|
Loading…
Reference in New Issue
Block a user