Commit b5fb5d39 authored by Geert Uytterhoeven's avatar Geert Uytterhoeven Committed by Linus Torvalds

[PATCH] m68k: HP300: Convert DIO bus and its drivers to the new driver model

HP300: Convert DIO bus and its drivers to the new driver model (from Jochen
Friedrich).
Signed-off-by: default avatarJochen Friedrich <jochen@scram.de>
Signed-off-by: default avatarKars de Jong <jongk@linux-m68k.org>
Signed-off-by: default avatarGeert Uytterhoeven <geert@linux-m68k.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent d0ee7865
...@@ -2,4 +2,4 @@ ...@@ -2,4 +2,4 @@
# Makefile for the linux kernel. # Makefile for the linux kernel.
# #
obj-y := dio.o obj-y := dio.o dio-driver.o dio-sysfs.o
/*
* DIO Driver Services
*
* Copyright (C) 2004 Jochen Friedrich
*
* Loosely based on drivers/pci/pci-driver.c and drivers/zorro/zorro-driver.c
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive
* for more details.
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/dio.h>
/**
* dio_match_device - Tell if a DIO device structure has a matching
* DIO device id structure
* @ids: array of DIO device id structures to search in
* @dev: the DIO device structure to match against
*
* Used by a driver to check whether a DIO device present in the
* system is in its list of supported devices. Returns the matching
* dio_device_id structure or %NULL if there is no match.
*/
const struct dio_device_id *
dio_match_device(const struct dio_device_id *ids,
const struct dio_dev *d)
{
while (ids->id) {
if (ids->id == DIO_WILDCARD)
return ids;
if (DIO_NEEDSSECID(ids->id & 0xff)) {
if (ids->id == d->id)
return ids;
} else {
if ((ids->id & 0xff) == (d->id & 0xff))
return ids;
}
ids++;
}
return NULL;
}
static int dio_device_probe(struct device *dev)
{
int error = 0;
struct dio_driver *drv = to_dio_driver(dev->driver);
struct dio_dev *d = to_dio_dev(dev);
if (!d->driver && drv->probe) {
const struct dio_device_id *id;
id = dio_match_device(drv->id_table, d);
if (id)
error = drv->probe(d, id);
if (error >= 0) {
d->driver = drv;
error = 0;
}
}
return error;
}
/**
* dio_register_driver - register a new DIO driver
* @drv: the driver structure to register
*
* Adds the driver structure to the list of registered drivers
* Returns the number of DIO devices which were claimed by the driver
* during registration. The driver remains registered even if the
* return value is zero.
*/
int dio_register_driver(struct dio_driver *drv)
{
int count = 0;
/* initialize common driver fields */
drv->driver.name = drv->name;
drv->driver.bus = &dio_bus_type;
drv->driver.probe = dio_device_probe;
/* register with core */
count = driver_register(&drv->driver);
return count ? count : 1;
}
/**
* dio_unregister_driver - unregister a DIO driver
* @drv: the driver structure to unregister
*
* Deletes the driver structure from the list of registered DIO drivers,
* gives it a chance to clean up by calling its remove() function for
* each device it was responsible for, and marks those devices as
* driverless.
*/
void dio_unregister_driver(struct dio_driver *drv)
{
driver_unregister(&drv->driver);
}
/**
* dio_bus_match - Tell if a DIO device structure has a matching DIO
* device id structure
* @ids: array of DIO device id structures to search in
* @dev: the DIO device structure to match against
*
* Used by a driver to check whether a DIO device present in the
* system is in its list of supported devices. Returns the matching
* dio_device_id structure or %NULL if there is no match.
*/
static int dio_bus_match(struct device *dev, struct device_driver *drv)
{
struct dio_dev *d = to_dio_dev(dev);
struct dio_driver *dio_drv = to_dio_driver(drv);
const struct dio_device_id *ids = dio_drv->id_table;
if (!ids)
return 0;
while (ids->id) {
if (ids->id == DIO_WILDCARD)
return 1;
if (DIO_NEEDSSECID(ids->id & 0xff)) {
if (ids->id == d->id)
return 1;
} else {
if ((ids->id & 0xff) == (d->id & 0xff))
return 1;
}
ids++;
}
return 0;
}
struct bus_type dio_bus_type = {
.name = "dio",
.match = dio_bus_match
};
static int __init dio_driver_init(void)
{
return bus_register(&dio_bus_type);
}
postcore_initcall(dio_driver_init);
EXPORT_SYMBOL(dio_match_device);
EXPORT_SYMBOL(dio_register_driver);
EXPORT_SYMBOL(dio_unregister_driver);
EXPORT_SYMBOL(dio_dev_driver);
EXPORT_SYMBOL(dio_bus_type);
/*
* File Attributes for DIO Devices
*
* Copyright (C) 2004 Jochen Friedrich
*
* Loosely based on drivers/pci/pci-sysfs.c and drivers/zorro/zorro-sysfs.c
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive
* for more details.
*/
#include <linux/kernel.h>
#include <linux/dio.h>
#include <linux/stat.h>
/* show configuration fields */
static ssize_t dio_show_id(struct device *dev, char *buf)
{
struct dio_dev *d;
d = to_dio_dev(dev);
return sprintf(buf, "0x%02x\n", (d->id & 0xff));
}
static DEVICE_ATTR(id, S_IRUGO, dio_show_id, NULL);
static ssize_t dio_show_ipl(struct device *dev, char *buf)
{
struct dio_dev *d;
d = to_dio_dev(dev);
return sprintf(buf, "0x%02x\n", d->ipl);
}
static DEVICE_ATTR(ipl, S_IRUGO, dio_show_ipl, NULL);
static ssize_t dio_show_secid(struct device *dev, char *buf)
{
struct dio_dev *d;
d = to_dio_dev(dev);
return sprintf(buf, "0x%02x\n", ((d->id >> 8)& 0xff));
}
static DEVICE_ATTR(secid, S_IRUGO, dio_show_secid, NULL);
static ssize_t dio_show_name(struct device *dev, char *buf)
{
struct dio_dev *d;
d = to_dio_dev(dev);
return sprintf(buf, "%s\n", d->name);
}
static DEVICE_ATTR(name, S_IRUGO, dio_show_name, NULL);
static ssize_t dio_show_resource(struct device *dev, char *buf)
{
struct dio_dev *d = to_dio_dev(dev);
return sprintf(buf, "0x%08lx 0x%08lx 0x%08lx\n",
dio_resource_start(d), dio_resource_end(d),
dio_resource_flags(d));
}
static DEVICE_ATTR(resource, S_IRUGO, dio_show_resource, NULL);
void dio_create_sysfs_dev_files(struct dio_dev *d)
{
struct device *dev = &d->dev;
/* current configuration's attributes */
device_create_file(dev, &dev_attr_id);
device_create_file(dev, &dev_attr_ipl);
device_create_file(dev, &dev_attr_secid);
device_create_file(dev, &dev_attr_name);
device_create_file(dev, &dev_attr_resource);
}
/* Code to support devices on the DIO and DIO-II bus /* Code to support devices on the DIO and DIO-II bus
* Copyright (C) 05/1998 Peter Maydell <pmaydell@chiark.greenend.org.uk> * Copyright (C) 05/1998 Peter Maydell <pmaydell@chiark.greenend.org.uk>
* Copyright (C) 2004 Jochen Friedrich <jochen@scram.de>
* *
* This code has basically these routines at the moment: * This code has basically these routines at the moment:
* int dio_find(u_int deviceid) * int dio_find(u_int deviceid)
...@@ -23,15 +24,26 @@ ...@@ -23,15 +24,26 @@
* This file is based on the way the Amiga port handles Zorro II cards, * This file is based on the way the Amiga port handles Zorro II cards,
* although we aren't so complicated... * although we aren't so complicated...
*/ */
#include <linux/config.h> #include <linux/module.h>
#include <linux/kernel.h> #include <linux/string.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/dio.h> #include <linux/dio.h>
#include <linux/slab.h> /* kmalloc() */ #include <linux/slab.h> /* kmalloc() */
#include <linux/init.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/io.h> /* readb() */ #include <asm/io.h> /* readb() */
struct dio_bus dio_bus = {
.resources = {
/* DIO range */
{ .name = "DIO mem", .start = 0x00600000, .end = 0x007fffff },
/* DIO-II range */
{ .name = "DIO-II mem", .start = 0x01000000, .end = 0x1fffffff }
},
.name = "DIO bus"
};
/* not a real config option yet! */ /* not a real config option yet! */
#define CONFIG_DIO_CONSTANTS #define CONFIG_DIO_CONSTANTS
...@@ -99,30 +111,16 @@ static char dio_no_name[] = { 0 }; ...@@ -99,30 +111,16 @@ static char dio_no_name[] = { 0 };
#endif /* CONFIG_DIO_CONSTANTS */ #endif /* CONFIG_DIO_CONSTANTS */
/* We represent all the DIO boards in the system with a linked list of these structs. */ int __init dio_find(int deviceid)
struct dioboard
{ {
struct dioboard *next; /* link to next struct in list */ /* Called to find a DIO device before the full bus scan has run.
int ipl; /* IPL of this board */ * Only used by the console driver.
int configured; /* has this board been configured? */
int scode; /* select code of this board */
int id; /* encoded ID */
const char *name;
};
static struct dioboard *blist = NULL;
static int __init dio_find_slow(int deviceid)
{
/* Called to find a DIO device before the full bus scan has run. Basically
* only used by the console driver.
*/ */
int scode, id; int scode, id;
u_char prid, secid, i; u_char prid, secid, i;
mm_segment_t fs; mm_segment_t fs;
for (scode = 0; scode < DIO_SCMAX; scode++) for (scode = 0; scode < DIO_SCMAX; scode++) {
{
void *va; void *va;
unsigned long pa; unsigned long pa;
...@@ -142,8 +140,7 @@ static int __init dio_find_slow(int deviceid) ...@@ -142,8 +140,7 @@ static int __init dio_find_slow(int deviceid)
fs = get_fs(); fs = get_fs();
set_fs(KERNEL_DS); set_fs(KERNEL_DS);
if (get_user(i, (unsigned char *)va + DIO_IDOFF)) if (get_user(i, (unsigned char *)va + DIO_IDOFF)) {
{
set_fs(fs); set_fs(fs);
if (scode >= DIOII_SCBASE) if (scode >= DIOII_SCBASE)
iounmap(va); iounmap(va);
...@@ -153,16 +150,13 @@ static int __init dio_find_slow(int deviceid) ...@@ -153,16 +150,13 @@ static int __init dio_find_slow(int deviceid)
set_fs(fs); set_fs(fs);
prid = DIO_ID(va); prid = DIO_ID(va);
if (DIO_NEEDSSECID(prid)) if (DIO_NEEDSSECID(prid)) {
{
secid = DIO_SECID(va); secid = DIO_SECID(va);
id = DIO_ENCODE_ID(prid, secid); id = DIO_ENCODE_ID(prid, secid);
} } else
else
id = prid; id = prid;
if (id == deviceid) if (id == deviceid) {
{
if (scode >= DIOII_SCBASE) if (scode >= DIOII_SCBASE)
iounmap(va); iounmap(va);
return scode; return scode;
...@@ -172,35 +166,32 @@ static int __init dio_find_slow(int deviceid) ...@@ -172,35 +166,32 @@ static int __init dio_find_slow(int deviceid)
return -1; return -1;
} }
int dio_find(int deviceid)
{
if (blist)
{
/* fast way */
struct dioboard *b;
for (b = blist; b; b = b->next)
if (b->id == deviceid && b->configured == 0)
return b->scode;
return -1;
}
else
{
return dio_find_slow(deviceid);
}
}
/* This is the function that scans the DIO space and works out what /* This is the function that scans the DIO space and works out what
* hardware is actually present. * hardware is actually present.
*/ */
static int __init dio_init(void) static int __init dio_init(void)
{ {
int scode; int scode;
struct dioboard *b, *bprev = NULL;
mm_segment_t fs; mm_segment_t fs;
char i; int i;
struct dio_dev *dev;
if (!MACH_IS_HP300)
return 0;
printk(KERN_INFO "Scanning for DIO devices...\n"); printk(KERN_INFO "Scanning for DIO devices...\n");
/* Initialize the DIO bus */
INIT_LIST_HEAD(&dio_bus.devices);
strcpy(dio_bus.dev.bus_id, "dio");
device_register(&dio_bus.dev);
/* Request all resources */
dio_bus.num_resources = (hp300_model == HP_320 ? 1 : 2);
for (i = 0; i < dio_bus.num_resources; i++)
request_resource(&iomem_resource, &dio_bus.resources[i]);
/* Register all devices */
for (scode = 0; scode < DIO_SCMAX; ++scode) for (scode = 0; scode < DIO_SCMAX; ++scode)
{ {
u_char prid, secid = 0; /* primary, secondary ID bytes */ u_char prid, secid = 0; /* primary, secondary ID bytes */
...@@ -223,8 +214,7 @@ static int __init dio_init(void) ...@@ -223,8 +214,7 @@ static int __init dio_init(void)
fs = get_fs(); fs = get_fs();
set_fs(KERNEL_DS); set_fs(KERNEL_DS);
if (get_user(i, (unsigned char *)va + DIO_IDOFF)) if (get_user(i, (unsigned char *)va + DIO_IDOFF)) {
{
set_fs(fs); set_fs(fs);
if (scode >= DIOII_SCBASE) if (scode >= DIOII_SCBASE)
iounmap(va); iounmap(va);
...@@ -234,40 +224,40 @@ static int __init dio_init(void) ...@@ -234,40 +224,40 @@ static int __init dio_init(void)
set_fs(fs); set_fs(fs);
/* Found a board, allocate it an entry in the list */ /* Found a board, allocate it an entry in the list */
b = kmalloc(sizeof(struct dioboard), GFP_KERNEL); dev = kmalloc(sizeof(struct dio_dev), GFP_KERNEL);
if (!dev)
return 0;
memset(dev, 0, sizeof(struct dio_dev));
dev->bus = &dio_bus;
dev->dev.parent = &dio_bus.dev;
dev->dev.bus = &dio_bus_type;
dev->scode = scode;
dev->resource.start = pa;
dev->resource.end = pa + DIO_SIZE(scode, va);
sprintf(dev->dev.bus_id,"%02x", scode);
/* read the ID byte(s) and encode if necessary. */ /* read the ID byte(s) and encode if necessary. */
prid = DIO_ID(va); prid = DIO_ID(va);
if (DIO_NEEDSSECID(prid)) if (DIO_NEEDSSECID(prid)) {
{
secid = DIO_SECID(va); secid = DIO_SECID(va);
b->id = DIO_ENCODE_ID(prid, secid); dev->id = DIO_ENCODE_ID(prid, secid);
} } else
else dev->id = prid;
b->id = prid;
dev->ipl = DIO_IPL(va);
b->configured = 0; strcpy(dev->name,dio_getname(dev->id));
b->scode = scode; printk(KERN_INFO "select code %3d: ipl %d: ID %02X", dev->scode, dev->ipl, prid);
b->ipl = DIO_IPL(va);
b->name = dio_getname(b->id);
printk(KERN_INFO "select code %3d: ipl %d: ID %02X", b->scode, b->ipl, prid);
if (DIO_NEEDSSECID(prid)) if (DIO_NEEDSSECID(prid))
printk(":%02X", secid); printk(":%02X", secid);
printk(": %s\n", b->name); printk(": %s\n", dev->name);
if (scode >= DIOII_SCBASE) if (scode >= DIOII_SCBASE)
iounmap(va); iounmap(va);
device_register(&dev->dev);
b->next = NULL; dio_create_sysfs_dev_files(dev);
if (bprev)
bprev->next = b;
else
blist = b;
bprev = b;
} }
return 0; return 0;
} }
...@@ -278,77 +268,12 @@ subsys_initcall(dio_init); ...@@ -278,77 +268,12 @@ subsys_initcall(dio_init);
*/ */
unsigned long dio_scodetophysaddr(int scode) unsigned long dio_scodetophysaddr(int scode)
{ {
if (scode >= DIOII_SCBASE) if (scode >= DIOII_SCBASE) {
{
return (DIOII_BASE + (scode - 132) * DIOII_DEVSIZE); return (DIOII_BASE + (scode - 132) * DIOII_DEVSIZE);
} } else if (scode > DIO_SCMAX || scode < 0)
else if (scode > DIO_SCMAX || scode < 0)
return 0; return 0;
else if (DIO_SCINHOLE(scode)) else if (DIO_SCINHOLE(scode))
return 0; return 0;
return (DIO_BASE + scode * DIO_DEVSIZE); return (DIO_BASE + scode * DIO_DEVSIZE);
} }
int dio_scodetoipl(int scode)
{
struct dioboard *b;
for (b = blist; b; b = b->next)
if (b->scode == scode)
break;
if (!b)
{
printk(KERN_ERR "dio_scodetoipl: bad select code %d\n", scode);
return 0;
}
else
return b->ipl;
}
const char *dio_scodetoname(int scode)
{
struct dioboard *b;
for (b = blist; b; b = b->next)
if (b->scode == scode)
break;
if (!b)
{
printk(KERN_ERR "dio_scodetoname: bad select code %d\n", scode);
return NULL;
}
else
return b->name;
}
void dio_config_board(int scode)
{
struct dioboard *b;
for (b = blist; b; b = b->next)
if (b->scode == scode)
break;
if (!b)
printk(KERN_ERR "dio_config_board: bad select code %d\n", scode);
else if (b->configured)
printk(KERN_WARNING "dio_config_board: board at select code %d already configured\n", scode);
else
b->configured = 1;
}
void dio_unconfig_board(int scode)
{
struct dioboard *b;
for (b = blist; b; b = b->next)
if (b->scode == scode)
break;
if (!b)
printk(KERN_ERR "dio_unconfig_board: bad select code %d\n", scode);
else if (!b->configured)
printk(KERN_WARNING "dio_unconfig_board: board at select code %d not configured\n",
scode);
else
b->configured = 0;
}
...@@ -284,9 +284,6 @@ static struct devprobe2 m68k_probes[] __initdata = { ...@@ -284,9 +284,6 @@ static struct devprobe2 m68k_probes[] __initdata = {
#ifdef CONFIG_ATARI_PAMSNET /* Atari PAMsNet Ethernet board */ #ifdef CONFIG_ATARI_PAMSNET /* Atari PAMsNet Ethernet board */
{pamsnet_probe, 0}, {pamsnet_probe, 0},
#endif #endif
#ifdef CONFIG_HPLANCE /* HP300 internal Ethernet */
{hplance_probe, 0},
#endif
#ifdef CONFIG_MVME147_NET /* MVME147 internal Ethernet */ #ifdef CONFIG_MVME147_NET /* MVME147 internal Ethernet */
{mvme147lance_probe, 0}, {mvme147lance_probe, 0},
#endif #endif
......
...@@ -40,8 +40,7 @@ ...@@ -40,8 +40,7 @@
/* Our private data structure */ /* Our private data structure */
struct hplance_private { struct hplance_private {
struct lance_private lance; struct lance_private lance;
unsigned int scode;
}; };
/* function prototypes... This is easy because all the grot is in the /* function prototypes... This is easy because all the grot is in the
...@@ -49,76 +48,71 @@ struct hplance_private { ...@@ -49,76 +48,71 @@ struct hplance_private {
* plus board-specific init, open and close actions. * plus board-specific init, open and close actions.
* Oh, and we need to tell the generic code how to read and write LANCE registers... * Oh, and we need to tell the generic code how to read and write LANCE registers...
*/ */
static void hplance_init(struct net_device *dev, int scode); static int __devinit hplance_init_one(struct dio_dev *d,
static int hplance_open(struct net_device *dev); const struct dio_device_id *ent);
static int hplance_close(struct net_device *dev); static void __devinit hplance_init(struct net_device *dev,
struct dio_dev *d);
static void __devexit hplance_remove_one(struct dio_dev *d);
static void hplance_writerap(void *priv, unsigned short value); static void hplance_writerap(void *priv, unsigned short value);
static void hplance_writerdp(void *priv, unsigned short value); static void hplance_writerdp(void *priv, unsigned short value);
static unsigned short hplance_readrdp(void *priv); static unsigned short hplance_readrdp(void *priv);
static int hplance_open(struct net_device *dev);
static int hplance_close(struct net_device *dev);
#ifdef MODULE static struct dio_device_id hplance_dio_tbl[] = {
static struct hplance_private *root_hplance_dev; { DIO_ID_LAN },
#endif { 0 }
};
static void cleanup_card(struct net_device *dev) static struct dio_driver hplance_driver = {
{ .name = "hplance",
struct hplance_private *lp = netdev_priv(dev); .id_table = hplance_dio_tbl,
dio_unconfig_board(lp->scode); .probe = hplance_init_one,
} .remove = __devexit_p(hplance_remove_one),
};
/* Find all the HP Lance boards and initialise them... */ /* Find all the HP Lance boards and initialise them... */
struct net_device * __init hplance_probe(int unit) static int __devinit hplance_init_one(struct dio_dev *d,
const struct dio_device_id *ent)
{ {
struct net_device *dev; struct net_device *dev;
int err;
if (!MACH_IS_HP300)
return ERR_PTR(-ENODEV);
dev = alloc_etherdev(sizeof(struct hplance_private)); dev = alloc_etherdev(sizeof(struct hplance_private));
if (!dev) if (!dev)
return ERR_PTR(-ENOMEM); return -ENOMEM;
if (unit >= 0) { if (!request_mem_region(d->resource.start, d->resource.end-d->resource.start, d->name))
sprintf(dev->name, "eth%d", unit); return -EBUSY;
netdev_boot_setup_check(dev);
}
SET_MODULE_OWNER(dev); SET_MODULE_OWNER(dev);
/* Isn't DIO nice? */ hplance_init(dev, d);
for(;;) err = register_netdev(dev);
{ if (err) {
int scode = dio_find(DIO_ID_LAN); free_netdev(dev);
return err;
if (scode < 0) }
break; dio_set_drvdata(d, dev);
return 0;
dio_config_board(scode); }
hplance_init(dev, scode);
if (!register_netdev(dev)) { static void __devexit hplance_remove_one(struct dio_dev *d)
#ifdef MODULE {
struct hplance_private *lp = netdev_priv(dev); struct net_device *dev = dio_get_drvdata(d);
lp->next_module = root_hplance_dev;
root_hplance_dev = lp; unregister_netdev(dev);
#endif
return dev;
}
cleanup_card(dev);
}
free_netdev(dev); free_netdev(dev);
return ERR_PTR(-ENODEV);
} }
/* Initialise a single lance board at the given select code */ /* Initialise a single lance board at the given DIO device */
static void __init hplance_init(struct net_device *dev, int scode) static void __init hplance_init(struct net_device *dev, struct dio_dev *d)
{ {
const char *name = dio_scodetoname(scode); unsigned long va = (d->resource.start + DIO_VIRADDRBASE);
unsigned long pa = dio_scodetophysaddr(scode);
unsigned long va = (pa + DIO_VIRADDRBASE);
struct hplance_private *lp; struct hplance_private *lp;
int i; int i;
printk(KERN_INFO "%s: %s; select code %d, addr", dev->name, name, scode); printk(KERN_INFO "%s: %s; select code %d, addr", dev->name, d->name, d->scode);
/* reset the board */ /* reset the board */
out_8(va+DIO_IDOFF, 0xff); out_8(va+DIO_IDOFF, 0xff);
...@@ -136,8 +130,7 @@ static void __init hplance_init(struct net_device *dev, int scode) ...@@ -136,8 +130,7 @@ static void __init hplance_init(struct net_device *dev, int scode)
dev->set_multicast_list = &lance_set_multicast; dev->set_multicast_list = &lance_set_multicast;
dev->dma = 0; dev->dma = 0;
for (i=0; i<6; i++) for (i=0; i<6; i++) {
{
/* The NVRAM holds our ethernet address, one nibble per byte, /* The NVRAM holds our ethernet address, one nibble per byte,
* at bytes NVRAMOFF+1,3,5,7,9... * at bytes NVRAMOFF+1,3,5,7,9...
*/ */
...@@ -147,12 +140,12 @@ static void __init hplance_init(struct net_device *dev, int scode) ...@@ -147,12 +140,12 @@ static void __init hplance_init(struct net_device *dev, int scode)
} }
lp = netdev_priv(dev); lp = netdev_priv(dev);
lp->lance.name = (char*)name; /* discards const, shut up gcc */ lp->lance.name = (char*)d->name; /* discards const, shut up gcc */
lp->lance.base = va; lp->lance.base = va;
lp->lance.init_block = (struct lance_init_block *)(va + HPLANCE_MEMOFF); /* CPU addr */ lp->lance.init_block = (struct lance_init_block *)(va + HPLANCE_MEMOFF); /* CPU addr */
lp->lance.lance_init_block = 0; /* LANCE addr of same RAM */ lp->lance.lance_init_block = 0; /* LANCE addr of same RAM */
lp->lance.busmaster_regval = LE_C3_BSWP; /* we're bigendian */ lp->lance.busmaster_regval = LE_C3_BSWP; /* we're bigendian */
lp->lance.irq = dio_scodetoipl(scode); lp->lance.irq = d->ipl;
lp->lance.writerap = hplance_writerap; lp->lance.writerap = hplance_writerap;
lp->lance.writerdp = hplance_writerdp; lp->lance.writerdp = hplance_writerdp;
lp->lance.readrdp = hplance_readrdp; lp->lance.readrdp = hplance_readrdp;
...@@ -160,7 +153,6 @@ static void __init hplance_init(struct net_device *dev, int scode) ...@@ -160,7 +153,6 @@ static void __init hplance_init(struct net_device *dev, int scode)
lp->lance.lance_log_tx_bufs = LANCE_LOG_TX_BUFFERS; lp->lance.lance_log_tx_bufs = LANCE_LOG_TX_BUFFERS;
lp->lance.rx_ring_mod_mask = RX_RING_MOD_MASK; lp->lance.rx_ring_mod_mask = RX_RING_MOD_MASK;
lp->lance.tx_ring_mod_mask = TX_RING_MOD_MASK; lp->lance.tx_ring_mod_mask = TX_RING_MOD_MASK;
lp->scode = scode;
printk(", irq %d\n", lp->lance.irq); printk(", irq %d\n", lp->lance.irq);
} }
...@@ -216,27 +208,17 @@ static int hplance_close(struct net_device *dev) ...@@ -216,27 +208,17 @@ static int hplance_close(struct net_device *dev)
return 0; return 0;
} }
#ifdef MODULE int __init hplance_init_module(void)
MODULE_LICENSE("GPL");
int init_module(void)
{ {
int found = 0; return dio_module_init(&hplance_driver);
while (!IS_ERR(hplance_probe(-1)))
found++;
return found ? 0 : -ENODEV;
} }
void cleanup_module(void) void __exit hplance_cleanup_module(void)
{ {
/* Walk the chain of devices, unregistering them */ dio_unregister_driver(&hplance_driver);
struct hplance_private *lp;
while (root_hplance_dev) {
lp = root_hplance_dev->next_module;
unregister_netdev(root_lance_dev->dev);
cleanup_card(root_lance_dev->dev);
free_netdev(root_lance_dev->dev);
root_lance_dev = lp;
}
} }
#endif /* MODULE */ module_init(hplance_init_module);
module_exit(hplance_cleanup_module);
MODULE_LICENSE("GPL");
...@@ -22,17 +22,40 @@ ...@@ -22,17 +22,40 @@
#warning CONFIG_8250 defined but neither CONFIG_HPDCA nor CONFIG_HPAPCI defined, are you sure? #warning CONFIG_8250 defined but neither CONFIG_HPDCA nor CONFIG_HPAPCI defined, are you sure?
#endif #endif
#ifdef CONFIG_HPAPCI
struct hp300_port struct hp300_port
{ {
struct hp300_port *next; /* next port */ struct hp300_port *next; /* next port */
unsigned long dio_base; /* start of DIO registers */
int scode; /* select code of this board */
int line; /* line (tty) number */ int line; /* line (tty) number */
}; };
extern int hp300_uart_scode;
static struct hp300_port *hp300_ports; static struct hp300_port *hp300_ports;
#endif
#ifdef CONFIG_HPDCA
static int __devinit hpdca_init_one(struct dio_dev *d,
const struct dio_device_id *ent);
static void __devexit hpdca_remove_one(struct dio_dev *d);
static struct dio_device_id hpdca_dio_tbl[] = {
{ DIO_ID_DCA0 },
{ DIO_ID_DCA0REM },
{ DIO_ID_DCA1 },
{ DIO_ID_DCA1REM },
{ 0 }
};
static struct dio_driver hpdca_driver = {
.name = "hpdca",
.id_table = hpdca_dio_tbl,
.probe = hpdca_init_one,
.remove = __devexit_p(hpdca_remove_one),
};
#endif
extern int hp300_uart_scode;
/* Offset to UART registers from base of DCA */ /* Offset to UART registers from base of DCA */
#define UART_OFFSET 17 #define UART_OFFSET 17
...@@ -73,7 +96,10 @@ int __init hp300_setup_serial_console(void) ...@@ -73,7 +96,10 @@ int __init hp300_setup_serial_console(void)
memset(&port, 0, sizeof(port)); memset(&port, 0, sizeof(port));
if (hp300_uart_scode < 0 || hp300_uart_scode > 256) if (hp300_uart_scode < 0 || hp300_uart_scode > DIO_SCMAX)
return 0;
if (DIO_SCINHOLE(hp300_uart_scode))
return 0; return 0;
scode = hp300_uart_scode; scode = hp300_uart_scode;
...@@ -84,8 +110,7 @@ int __init hp300_setup_serial_console(void) ...@@ -84,8 +110,7 @@ int __init hp300_setup_serial_console(void)
port.type = PORT_UNKNOWN; port.type = PORT_UNKNOWN;
/* Check for APCI console */ /* Check for APCI console */
if (scode == 256) if (scode == 256) {
{
#ifdef CONFIG_HPAPCI #ifdef CONFIG_HPAPCI
printk(KERN_INFO "Serial console is HP APCI 1\n"); printk(KERN_INFO "Serial console is HP APCI 1\n");
...@@ -99,8 +124,7 @@ int __init hp300_setup_serial_console(void) ...@@ -99,8 +124,7 @@ int __init hp300_setup_serial_console(void)
return 0; return 0;
#endif #endif
} }
else else {
{
#ifdef CONFIG_HPDCA #ifdef CONFIG_HPDCA
unsigned long pa = dio_scodetophysaddr(scode); unsigned long pa = dio_scodetophysaddr(scode);
if (!pa) { if (!pa) {
...@@ -135,47 +159,89 @@ int __init hp300_setup_serial_console(void) ...@@ -135,47 +159,89 @@ int __init hp300_setup_serial_console(void)
} }
#endif /* CONFIG_SERIAL_8250_CONSOLE */ #endif /* CONFIG_SERIAL_8250_CONSOLE */
#ifdef CONFIG_HPDCA
static int __devinit hpdca_init_one(struct dio_dev *d,
const struct dio_device_id *ent)
{
struct serial_struct serial_req;
int line;
#ifdef CONFIG_SERIAL_8250_CONSOLE
if (hp300_uart_scode == d->scode) {
/* Already got it. */
return 0;
}
#endif
memset(&serial_req, 0, sizeof(struct serial_struct));
/* Memory mapped I/O */
serial_req.io_type = SERIAL_IO_MEM;
serial_req.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF;
serial_req.irq = d->ipl;
serial_req.baud_base = HPDCA_BAUD_BASE;
serial_req.iomap_base = (d->resource.start + UART_OFFSET);
serial_req.iomem_base = (char *)(serial_req.iomap_base + DIO_VIRADDRBASE);
serial_req.iomem_reg_shift = 1;
line = register_serial(&serial_req);
if (line < 0) {
printk(KERN_NOTICE "8250_hp300: register_serial() DCA scode %d"
" irq %d failed\n", d->scode, serial_req.irq);
return -ENOMEM;
}
/* Enable board-interrupts */
out_8(d->resource.start + DIO_VIRADDRBASE + DCA_IC, DCA_IC_IE);
dio_set_drvdata(d, (void *)line);
/* Reset the DCA */
out_8(d->resource.start + DIO_VIRADDRBASE + DCA_ID, 0xff);
udelay(100);
return 0;
}
#endif
static int __init hp300_8250_init(void) static int __init hp300_8250_init(void)
{ {
static int called = 0; static int called = 0;
#ifdef CONFIG_HPDCA int num_ports;
int scode; #ifdef CONFIG_HPAPCI
#endif int line;
int line, num_ports;
unsigned long base; unsigned long base;
struct serial_struct serial_req; struct serial_struct serial_req;
struct hp300_port *port; struct hp300_port *port;
int i;
#endif
if (called) if (called)
return -ENODEV; return -ENODEV;
called = 1; called = 1;
num_ports = 0;
if (!MACH_IS_HP300) { if (!MACH_IS_HP300)
return -ENODEV; return -ENODEV;
}
#ifdef CONFIG_HPDCA num_ports = 0;
while (1) {
/* We detect boards by looking for DIO boards which match a
* given subset of IDs. dio_find() returns the board's scancode.
* The scancode to physaddr mapping is a property of the hardware,
* as is the scancode to IPL (interrupt priority) mapping.
*/
scode = dio_find(DIO_ID_DCA0);
if (scode < 0)
scode = dio_find(DIO_ID_DCA0REM);
if (scode < 0)
scode = dio_find(DIO_ID_DCA1);
if (scode < 0)
scode = dio_find(DIO_ID_DCA1REM);
if (scode < 0)
break; /* no, none at all */
#ifdef CONFIG_HPDCA
if (dio_module_init(&hpdca_driver) == 0)
num_ports++;
#endif
#ifdef CONFIG_HPAPCI
if (hp300_model < HP_400) {
if (!num_ports)
return -ENODEV;
return 0;
}
/* These models have the Frodo chip.
* Port 0 is reserved for the Apollo Domain keyboard.
* Port 1 is either the console or the DCA.
*/
for (i = 1; i < 4; i++) {
/* Port 1 is the console on a 425e, on other machines it's mapped to
* DCA.
*/
#ifdef CONFIG_SERIAL_8250_CONSOLE #ifdef CONFIG_SERIAL_8250_CONSOLE
if (hp300_uart_scode == scode) { if (i == 1) {
/* Already got it */
dio_config_board(scode);
continue; continue;
} }
#endif #endif
...@@ -186,109 +252,33 @@ static int __init hp300_8250_init(void) ...@@ -186,109 +252,33 @@ static int __init hp300_8250_init(void)
return -ENOMEM; return -ENOMEM;
memset(&serial_req, 0, sizeof(struct serial_struct)); memset(&serial_req, 0, sizeof(struct serial_struct));
base = dio_scodetophysaddr(scode);
/* If we want to tell the DIO code that this board is configured, base = (FRODO_BASE + FRODO_APCI_OFFSET(i));
* we should do that here.
*/
dio_config_board(scode);
/* Memory mapped I/O */ /* Memory mapped I/O */
serial_req.io_type = SERIAL_IO_MEM; serial_req.io_type = SERIAL_IO_MEM;
serial_req.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF; serial_req.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF;
serial_req.irq = dio_scodetoipl(scode); /* XXX - no interrupt support yet */
serial_req.baud_base = HPDCA_BAUD_BASE; serial_req.irq = 0;
serial_req.iomap_base = (base + UART_OFFSET); serial_req.baud_base = HPAPCI_BAUD_BASE;
serial_req.iomap_base = base;
serial_req.iomem_base = (char *)(serial_req.iomap_base + DIO_VIRADDRBASE); serial_req.iomem_base = (char *)(serial_req.iomap_base + DIO_VIRADDRBASE);
serial_req.iomem_reg_shift = 1; serial_req.iomem_reg_shift = 2;
#ifdef CONFIG_SERIAL_8250_CONSOLE
if (hp300_uart_scode != scode) {
#endif
/* Reset the DCA */
out_8(base + DIO_VIRADDRBASE + DCA_ID, 0xff);
udelay(100);
#ifdef CONFIG_SERIAL_8250_CONSOLE
}
#endif
line = register_serial(&serial_req); line = register_serial(&serial_req);
if (line < 0) { if (line < 0) {
printk(KERN_NOTICE "8250_hp300: register_serial() DCA scode %d" printk(KERN_NOTICE "8250_hp300: register_serial() APCI %d"
" irq %d failed\n", scode, serial_req.irq); " irq %d failed\n", i, serial_req.irq);
kfree(port); kfree(port);
continue; continue;
} }
/* Enable board-interrupts */
out_8(base + DIO_VIRADDRBASE + DCA_IC, DCA_IC_IE);
port->dio_base = base + DIO_VIRADDRBASE;
port->scode = scode;
port->line = line; port->line = line;
port->next = hp300_ports; port->next = hp300_ports;
hp300_ports = port; hp300_ports = port;
num_ports++; num_ports++;
}
#endif
#ifdef CONFIG_HPAPCI
if (hp300_model >= HP_400)
{
int i;
/* These models have the Frodo chip.
* Port 0 is reserved for the Apollo Domain keyboard.
* Port 1 is either the console or the DCA.
*/
for (i = 1; i < 4; i++) {
/* Port 1 is the console on a 425e, on other machines it's mapped to
* DCA.
*/
#ifdef CONFIG_SERIAL_8250_CONSOLE
if (i == 1) {
continue;
}
#endif
/* Create new serial device */
port = kmalloc(sizeof(struct hp300_port), GFP_KERNEL);
if (!port)
return -ENOMEM;
memset(&serial_req, 0, sizeof(struct serial_struct));
base = (FRODO_BASE + FRODO_APCI_OFFSET(i));
/* Memory mapped I/O */
serial_req.io_type = SERIAL_IO_MEM;
serial_req.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF;
/* XXX - no interrupt support yet */
serial_req.irq = 0;
serial_req.baud_base = HPAPCI_BAUD_BASE;
serial_req.iomap_base = base;
serial_req.iomem_base = (char *)(serial_req.iomap_base + DIO_VIRADDRBASE);
serial_req.iomem_reg_shift = 2;
line = register_serial(&serial_req);
if (line < 0) {
printk(KERN_NOTICE "8250_hp300: register_serial() APCI %d"
" irq %d failed\n", i, serial_req.irq);
kfree(port);
continue;
}
port->dio_base = 0;
port->line = line;
port->next = hp300_ports;
hp300_ports = port;
num_ports++;
}
} }
#endif #endif
...@@ -299,28 +289,37 @@ static int __init hp300_8250_init(void) ...@@ -299,28 +289,37 @@ static int __init hp300_8250_init(void)
return 0; return 0;
} }
#ifdef CONFIG_HPDCA
static void __devexit hpdca_remove_one(struct dio_dev *d)
{
int line;
line = (int) dio_get_drvdata(d);
if (d->resource.start) {
/* Disable board-interrupts */
out_8(d->resource.start + DIO_VIRADDRBASE + DCA_IC, 0);
}
unregister_serial(line);
}
#endif
static void __exit hp300_8250_exit(void) static void __exit hp300_8250_exit(void)
{ {
#ifdef CONFIG_HPAPCI
struct hp300_port *port, *to_free; struct hp300_port *port, *to_free;
for (port = hp300_ports; port; ) { for (port = hp300_ports; port; ) {
unregister_serial(port->line); unregister_serial(port->line);
#ifdef CONFIG_HPDCA
if (port->dio_base) {
/* Disable board-interrupts */
out_8(port->dio_base + DCA_IC, 0);
dio_unconfig_board(port->scode);
}
#endif
to_free = port; to_free = port;
port = port->next; port = port->next;
kfree(to_free); kfree(to_free);
} }
hp300_ports = NULL; hp300_ports = NULL;
#endif
#ifdef CONFIG_HPDCA
dio_unregister_driver(&hpdca_driver);
#endif
} }
module_init(hp300_8250_init); module_init(hp300_8250_init);
......
...@@ -127,14 +127,12 @@ static int hpfb_blank(int blank, struct fb_info *info) ...@@ -127,14 +127,12 @@ static int hpfb_blank(int blank, struct fb_info *info)
static void topcat_blit(int x0, int y0, int x1, int y1, int w, int h, int rr) static void topcat_blit(int x0, int y0, int x1, int y1, int w, int h, int rr)
{ {
if (rr >= 0) if (rr >= 0) {
{
while (in_8(fb_regs + BUSY) & fb_bitmask) while (in_8(fb_regs + BUSY) & fb_bitmask)
; ;
} }
out_8(fb_regs + TC_FBEN, fb_bitmask); out_8(fb_regs + TC_FBEN, fb_bitmask);
if (rr >= 0) if (rr >= 0) {
{
out_8(fb_regs + TC_WEN, fb_bitmask); out_8(fb_regs + TC_WEN, fb_bitmask);
out_8(fb_regs + WMRR, rr); out_8(fb_regs + WMRR, rr);
} }
...@@ -221,13 +219,11 @@ static int __init hpfb_init_one(unsigned long phys_base, unsigned long virt_base ...@@ -221,13 +219,11 @@ static int __init hpfb_init_one(unsigned long phys_base, unsigned long virt_base
fb_info.fix.smem_start = (in_8(fb_regs + fboff) << 16); fb_info.fix.smem_start = (in_8(fb_regs + fboff) << 16);
if (phys_base >= DIOII_BASE) if (phys_base >= DIOII_BASE) {
{
fb_info.fix.smem_start += phys_base; fb_info.fix.smem_start += phys_base;
} }
if (DIO_SECID(fb_regs) != DIO_ID2_TOPCAT) if (DIO_SECID(fb_regs) != DIO_ID2_TOPCAT) {
{
/* This is the magic incantation the HP X server uses to make Catseye boards work. */ /* This is the magic incantation the HP X server uses to make Catseye boards work. */
while (in_be16(fb_regs+0x4800) & 1) while (in_be16(fb_regs+0x4800) & 1)
; ;
...@@ -299,8 +295,7 @@ static int __init hpfb_init_one(unsigned long phys_base, unsigned long virt_base ...@@ -299,8 +295,7 @@ static int __init hpfb_init_one(unsigned long phys_base, unsigned long virt_base
fb_alloc_cmap(&fb_info.cmap, 1 << hpfb_defined.bits_per_pixel, 0); fb_alloc_cmap(&fb_info.cmap, 1 << hpfb_defined.bits_per_pixel, 0);
if (register_framebuffer(&fb_info) < 0) if (register_framebuffer(&fb_info) < 0) {
{
fb_dealloc_cmap(&fb_info.cmap); fb_dealloc_cmap(&fb_info.cmap);
return 1; return 1;
} }
...@@ -322,6 +317,51 @@ static int __init hpfb_init_one(unsigned long phys_base, unsigned long virt_base ...@@ -322,6 +317,51 @@ static int __init hpfb_init_one(unsigned long phys_base, unsigned long virt_base
/* /*
* Initialise the framebuffer * Initialise the framebuffer
*/ */
static int __devinit hpfb_dio_probe(struct dio_dev * d, const struct dio_device_id * ent)
{
unsigned long paddr, vaddr;
paddr = d->resource.start;
if (!request_mem_region(d->resource.start, d->resource.end - d->resource.start, d->name))
return -EBUSY;
if (d->scode >= DIOII_SCBASE) {
vaddr = (unsigned long)ioremap(paddr, d->resource.end - d->resource.start);
} else {
vaddr = paddr + DIO_VIRADDRBASE;
}
printk(KERN_INFO "Topcat found at DIO select code %d "
"(secondary id %02x)\n", d->scode, (d->id >> 8) & 0xff);
if (hpfb_init_one(paddr, vaddr)) {
if (d->scode >= DIOII_SCBASE)
iounmap((void *)vaddr);
return -ENOMEM;
}
return 0;
}
static void __devexit hpfb_remove_one(struct dio_dev *d)
{
unregister_framebuffer(&fb_info);
if (d->scode >= DIOII_SCBASE)
iounmap((void *)fb_regs);
release_mem_region(d->resource.start, d->resource.end - d->resource.start);
}
static struct dio_device_id hpfb_dio_tbl[] = {
{ DIO_ENCODE_ID(DIO_ID_FBUFFER, DIO_ID2_LRCATSEYE) },
{ DIO_ENCODE_ID(DIO_ID_FBUFFER, DIO_ID2_HRCCATSEYE) },
{ DIO_ENCODE_ID(DIO_ID_FBUFFER, DIO_ID2_HRMCATSEYE) },
{ DIO_ENCODE_ID(DIO_ID_FBUFFER, DIO_ID2_TOPCAT) },
{ 0 }
};
static struct dio_driver hpfb_driver = {
.name = "hpfb",
.id_table = hpfb_dio_tbl,
.probe = hpfb_dio_probe,
.remove = __devexit_p(hpfb_remove_one),
};
int __init hpfb_init(void) int __init hpfb_init(void)
{ {
...@@ -347,63 +387,30 @@ int __init hpfb_init(void) ...@@ -347,63 +387,30 @@ int __init hpfb_init(void)
if (fb_get_options("hpfb", NULL)) if (fb_get_options("hpfb", NULL))
return -ENODEV; return -ENODEV;
dio_module_init(&hpfb_driver);
fs = get_fs(); fs = get_fs();
set_fs(KERNEL_DS); set_fs(KERNEL_DS);
err = get_user(i, (unsigned char *)INTFBVADDR + DIO_IDOFF); err = get_user(i, (unsigned char *)INTFBVADDR + DIO_IDOFF);
set_fs(fs); set_fs(fs);
if (!err && (i == DIO_ID_FBUFFER) && topcat_sid_ok(sid = DIO_SECID(INTFBVADDR))) if (!err && (i == DIO_ID_FBUFFER) && topcat_sid_ok(sid = DIO_SECID(INTFBVADDR))) {
{ if (!request_mem_region(INTFBPADDR, DIO_DEVSIZE, "Internal Topcat"))
return -EBUSY;
printk(KERN_INFO "Internal Topcat found (secondary id %02x)\n", sid); printk(KERN_INFO "Internal Topcat found (secondary id %02x)\n", sid);
if (hpfb_init_one(INTFBPADDR, INTFBVADDR)) if (hpfb_init_one(INTFBPADDR, INTFBVADDR)) {
{
return -ENOMEM; return -ENOMEM;
} }
} }
else
{
int sc, size;
unsigned long paddr, vaddr;
if ((sc = dio_find(DIO_ENCODE_ID(DIO_ID_FBUFFER, DIO_ID2_LRCATSEYE))) < 0 &&
(sc = dio_find(DIO_ENCODE_ID(DIO_ID_FBUFFER, DIO_ID2_HRCCATSEYE))) < 0 &&
(sc = dio_find(DIO_ENCODE_ID(DIO_ID_FBUFFER, DIO_ID2_HRMCATSEYE))) < 0 &&
(sc = dio_find(DIO_ENCODE_ID(DIO_ID_FBUFFER, DIO_ID2_TOPCAT))) < 0)
{
return -ENXIO;
}
dio_config_board(sc);
paddr = dio_scodetophysaddr(sc);
if (sc >= DIOII_SCBASE)
{
/* To find out the real size of the device we first need to map it. */
vaddr = (unsigned long)ioremap(paddr, PAGE_SIZE);
size = DIO_SIZE(sc, vaddr);
iounmap((void *)vaddr);
vaddr = (unsigned long)ioremap(paddr, size);
}
else
{
vaddr = paddr + DIO_VIRADDRBASE;
size = DIO_SIZE(sc, vaddr);
}
sid = DIO_SECID(vaddr);
printk(KERN_INFO "Topcat found at DIO select code %d "
"(secondary id %02x)\n", sc, sid);
if (hpfb_init_one(paddr, vaddr))
{
if (sc >= DIOII_SCBASE)
iounmap((void *)vaddr);
dio_unconfig_board(sc);
return -ENOMEM;
}
}
return 0; return 0;
} }
void __exit hpfb_cleanup_module(void)
{
dio_unregister_driver(&hpfb_driver);
}
module_init(hpfb_init); module_init(hpfb_init);
module_exit(hpfb_cleanup_module);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -3,11 +3,12 @@ ...@@ -3,11 +3,12 @@
* The general structure of this is vaguely based on how * The general structure of this is vaguely based on how
* the Amiga port handles Zorro boards. * the Amiga port handles Zorro boards.
* Copyright (C) Peter Maydell 05/1998 <pmaydell@chiark.greenend.org.uk> * Copyright (C) Peter Maydell 05/1998 <pmaydell@chiark.greenend.org.uk>
* Converted to driver model Jochen Friedrich <jochen@scram.de>
* *
* The board IDs are from the NetBSD kernel, which for once provided * The board IDs are from the NetBSD kernel, which for once provided
* helpful comments... * helpful comments...
* *
* This goes with arch/m68k/hp300/dio.c * This goes with drivers/dio/dio.c
*/ */
#ifndef _LINUX_DIO_H #ifndef _LINUX_DIO_H
...@@ -27,18 +28,80 @@ ...@@ -27,18 +28,80 @@
* so currently we just don't handle DIO-II boards. It wouldn't be hard to * so currently we just don't handle DIO-II boards. It wouldn't be hard to
* do with ioremap() though. * do with ioremap() though.
*/ */
#include <linux/device.h>
#ifdef __KERNEL__ #ifdef __KERNEL__
#include <asm/hp300hw.h> #include <asm/hp300hw.h>
typedef __u16 dio_id;
/*
* DIO devices
*/
struct dio_dev {
struct dio_bus *bus;
dio_id id;
int scode;
struct dio_driver *driver; /* which driver has allocated this device */
struct device dev; /* Generic device interface */
u8 ipl;
char name[64];
struct resource resource;
};
#define to_dio_dev(n) container_of(n, struct dio_dev, dev)
/*
* DIO bus
*/
struct dio_bus {
struct list_head devices; /* list of devices on this bus */
unsigned int num_resources; /* number of resources */
struct resource resources[2]; /* address space routed to this bus */
struct device dev;
char name[10];
};
extern struct dio_bus dio_bus; /* Single DIO bus */
extern struct bus_type dio_bus_type;
/*
* DIO device IDs
*/
struct dio_device_id {
dio_id id; /* Device ID or DIO_WILDCARD */
unsigned long driver_data; /* Data private to the driver */
};
/*
* DIO device drivers
*/
struct dio_driver {
struct list_head node;
char *name;
const struct dio_device_id *id_table; /* NULL if wants all devices */
int (*probe)(struct dio_dev *z, const struct dio_device_id *id);
/* New device inserted */
void (*remove)(struct dio_dev *z); /* Device removed (NULL if not a hot-plug capable driver) */
struct device_driver driver;
};
#define to_dio_driver(drv) container_of(drv, struct dio_driver, driver)
/* DIO/DIO-II boards all have the following 8bit registers. /* DIO/DIO-II boards all have the following 8bit registers.
* These are offsets from the base of the device. * These are offsets from the base of the device.
*/ */
#define DIO_IDOFF 0x01 /* primary device ID */ #define DIO_IDOFF 0x01 /* primary device ID */
#define DIO_IPLOFF 0x03 /* interrupt priority level */ #define DIO_IPLOFF 0x03 /* interrupt priority level */
#define DIO_SECIDOFF 0x15 /* secondary device ID */ #define DIO_SECIDOFF 0x15 /* secondary device ID */
#define DIOII_SIZEOFF 0x101 /* device size, DIO-II only */ #define DIOII_SIZEOFF 0x101 /* device size, DIO-II only */
#define DIO_VIRADDRBASE 0xf0000000UL /* vir addr where IOspace is mapped */ #define DIO_VIRADDRBASE 0xf0000000UL /* vir addr where IOspace is mapped */
#define DIO_BASE 0x600000 /* start of DIO space */ #define DIO_BASE 0x600000 /* start of DIO space */
#define DIO_END 0x1000000 /* end of DIO space */ #define DIO_END 0x1000000 /* end of DIO space */
...@@ -79,6 +142,7 @@ ...@@ -79,6 +142,7 @@
#define DIO_ENCODE_ID(pr,sec) ((((int)sec & 0xff) << 8) | ((int)pr & 0xff)) #define DIO_ENCODE_ID(pr,sec) ((((int)sec & 0xff) << 8) | ((int)pr & 0xff))
/* macro to determine whether a given primary ID requires a secondary ID byte */ /* macro to determine whether a given primary ID requires a secondary ID byte */
#define DIO_NEEDSSECID(id) ((id) == DIO_ID_FBUFFER) #define DIO_NEEDSSECID(id) ((id) == DIO_ID_FBUFFER)
#define DIO_WILDCARD 0xff
/* Now a whole slew of macros giving device IDs and descriptive strings: */ /* Now a whole slew of macros giving device IDs and descriptive strings: */
#define DIO_ID_DCA0 0x02 /* 98644A serial */ #define DIO_ID_DCA0 0x02 /* 98644A serial */
...@@ -177,11 +241,72 @@ ...@@ -177,11 +241,72 @@
extern int dio_find(int deviceid); extern int dio_find(int deviceid);
extern unsigned long dio_scodetophysaddr(int scode); extern unsigned long dio_scodetophysaddr(int scode);
extern int dio_scodetoipl(int scode); extern void dio_create_sysfs_dev_files(struct dio_dev *);
extern const char *dio_scodetoname(int scode);
extern void dio_config_board(int scode); /* New-style probing */
extern void dio_unconfig_board(int scode); extern int dio_register_driver(struct dio_driver *);
extern void dio_unregister_driver(struct dio_driver *);
extern const struct dio_device_id *dio_match_device(const struct dio_device_id *ids, const struct dio_dev *z);
static inline struct dio_driver *dio_dev_driver(const struct dio_dev *d)
{
return d->driver;
}
#define dio_resource_start(d) ((d)->resource.start)
#define dio_resource_end(d) ((d)->resource.end)
#define dio_resource_len(d) ((d)->resource.end-(z)->resource.start+1)
#define dio_resource_flags(d) ((d)->resource.flags)
#define dio_request_device(d, name) \
request_mem_region(dio_resource_start(d), dio_resource_len(d), name)
#define dio_release_device(d) \
release_mem_region(dio_resource_start(d), dio_resource_len(d))
/* Similar to the helpers above, these manipulate per-dio_dev
* driver-specific data. They are really just a wrapper around
* the generic device structure functions of these calls.
*/
static inline void *dio_get_drvdata (struct dio_dev *d)
{
return dev_get_drvdata(&d->dev);
}
static inline void dio_set_drvdata (struct dio_dev *d, void *data)
{
dev_set_drvdata(&d->dev, data);
}
/*
* A helper function which helps ensure correct dio_driver
* setup and cleanup for commonly-encountered hotplug/modular cases
*
* This MUST stay in a header, as it checks for -DMODULE
*/
static inline int dio_module_init(struct dio_driver *drv)
{
int rc = dio_register_driver(drv);
if (rc > 0)
return 0;
/* iff CONFIG_HOTPLUG and built into kernel, we should
* leave the driver around for future hotplug events.
* For the module case, a hotplug daemon of some sort
* should load a module in response to an insert event. */
#if defined(CONFIG_HOTPLUG) && !defined(MODULE)
if (rc == 0)
return 0;
#else
if (rc == 0)
rc = -ENODEV;
#endif
/* if we get here, we need to clean up DIO driver instance
* and return some sort of error */
dio_unregister_driver(drv);
return rc;
}
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
#endif /* ndef _LINUX_DIO_H */ #endif /* ndef _LINUX_DIO_H */
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