Experimenting with sysfs to figure out how it works. So I'm attempting to
port the TurboChannel bus code to sysfs. Its a test of concept and a
learning experience. Comments welcomed.
diff -urN -X /home/jsimmons/dontdiff linus-2.6/drivers/tc/Makefile fbdev-2.6/drivers/tc/Makefile
--- linus-2.6/drivers/tc/Makefile 2005-01-21 10:23:32.000000000 -0800
+++ fbdev-2.6/drivers/tc/Makefile 2005-01-20 14:14:54.000000000 -0800
@@ -4,7 +4,7 @@
# Object file lists.
-obj-$(CONFIG_TC) += tc.o
+obj-$(CONFIG_TC) += tc.o tc-driver.o
obj-$(CONFIG_ZS) += zs.o
obj-$(CONFIG_VT) += lk201.o lk201-map.o lk201-remap.o
diff -urN -X /home/jsimmons/dontdiff linus-2.6/drivers/tc/tc-driver.c fbdev-2.6/drivers/tc/tc-driver.c
--- linus-2.6/drivers/tc/tc-driver.c 1969-12-31 16:00:00.000000000 -0800
+++ fbdev-2.6/drivers/tc/tc-driver.c 2005-01-21 10:22:29.000000000 -0800
@@ -0,0 +1,92 @@
+/*
+ * TURBO Channel Driver Services
+ *
+ * Copyright (C) 2005 James Simmons
+ *
+ * Loosely based on drivers/tc/dio-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/tc.h>
+
+ /**
+ * tc_register_driver - register a new TC driver
+ * @drv: the driver structure to register
+ *
+ * Adds the driver structure to the list of registered drivers
+ * Returns the number of TC devices which were claimed by the driver
+ * during registration. The driver remains registered even if the
+ * return value is zero.
+ */
+
+int tc_register_driver(struct tc_driver *drv)
+{
+ int count = 0;
+
+ /* initialize common driver fields */
+ drv->driver.name = drv->name;
+ drv->driver.bus = &tc_bus_type;
+
+ /* register with core */
+ count = driver_register(&drv->driver);
+ return count ? count : 1;
+}
+
+ /**
+ * tc_unregister_driver - unregister a TC driver
+ * @drv: the driver structure to unregister
+ *
+ * Deletes the driver structure from the list of registered TC 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 tc_unregister_driver(struct tc_driver *drv)
+{
+ driver_unregister(&drv->driver);
+}
+
+
+ /**
+ * tc_bus_match - Tell if a TC device structure has a matching TC
+ * device id structure
+ * @ids: array of TC device id structures to search in
+ * @dev: the TC device structure to match against
+ *
+ * Used by a driver to check whether a TC device present in the
+ * system is in its list of supported devices. Returns the matching
+ * tc_device_id structure or %NULL if there is no match.
+ */
+
+static int tc_bus_match(struct device *dev, struct device_driver *drv)
+{
+ struct tc_driver *tc_drv = to_tc_driver(drv);
+ struct tc_dev *tdev = to_tc_dev(dev);
+
+ return (strncmp(tdev->name, drv->name, 9) == 0);
+}
+
+struct bus_type tc_bus_type = {
+ .name = "tc",
+ .match = tc_bus_match
+};
+
+
+static int __init tc_driver_init(void)
+{
+ return bus_register(&tc_bus_type);
+}
+
+postcore_initcall(tc_driver_init);
+
+EXPORT_SYMBOL(tc_match_device);
+EXPORT_SYMBOL(tc_register_driver);
+EXPORT_SYMBOL(tc_unregister_driver);
+EXPORT_SYMBOL(tc_dev_driver);
+EXPORT_SYMBOL(tc_bus_type);
diff -urN -X /home/jsimmons/dontdiff linus-2.6/drivers/tc/tc.c fbdev-2.6/drivers/tc/tc.c
--- linus-2.6/drivers/tc/tc.c 2005-01-21 10:23:32.000000000 -0800
+++ fbdev-2.6/drivers/tc/tc.c 2005-01-21 10:28:15.000000000 -0800
@@ -26,9 +26,6 @@
#define TC_DEBUG
MODULE_LICENSE("GPL");
-slot_info tc_bus[MAX_SLOT];
-static int max_tcslot;
-static tcinfo *info;
unsigned long system_base;
@@ -40,54 +37,14 @@
* Interface to the world. Read comment in include/asm-mips/tc.h.
*/
-int search_tc_card(char *name)
-{
- int slot;
- slot_info *sip;
-
- for (slot = 0; slot <= max_tcslot; slot++) {
- sip = &tc_bus[slot];
- if ((sip->flags & FREE) && (strncmp(sip->name, name, strlen(name)) == 0)) {
- return slot;
- }
- }
-
- return -ENODEV;
-}
-
-void claim_tc_card(int slot)
-{
- if (tc_bus[slot].flags & IN_USE) {
- printk("claim_tc_card: attempting to claim a card already in use\n");
- return;
- }
- tc_bus[slot].flags &= ~FREE;
- tc_bus[slot].flags |= IN_USE;
-}
-
-void release_tc_card(int slot)
-{
- if (tc_bus[slot].flags & FREE) {
- printk("release_tc_card: attempting to release a card already free\n");
- return;
- }
- tc_bus[slot].flags &= ~IN_USE;
- tc_bus[slot].flags |= FREE;
-}
-
-unsigned long get_tc_base_addr(int slot)
-{
- return tc_bus[slot].base_addr;
-}
-
unsigned long get_tc_irq_nr(int slot)
{
- return tc_bus[slot].interrupt;
+ return tc_devices[slot].interrupt;
}
unsigned long get_tc_speed(void)
{
- return 100000 * (10000 / (unsigned long)info->clk_period);
+ return 100000 * (10000 / (unsigned long)tc_bus.info->clk_period);
}
/*
@@ -98,138 +55,144 @@
regs->cp0_epc += 4;
}
-static void __init tc_probe(unsigned long startaddr, unsigned long size, int max_slot)
+static void __init tc_bus_add_devices(struct tc_bus *bus, unsigned long startaddr)
{
- int i, slot;
- long offset;
- unsigned char *module;
+ unsigned long size = bus->info->slot_size << 20;
void (*old_be_handler)(struct pt_regs *regs);
+ unsigned char *module;
+ struct tc_device *dev;
+ long offset;
+ int i, slot;
+ switch (mips_machtype) {
+ case MACH_DS5000_200:
+ bus->max_tcslot = 6;
+ break;
+ case MACH_DS5000_1XX:
+ case MACH_DS5000_2X0:
+ bus->max_tcslot = 2;
+ break;
+ case MACH_DS5000_XX:
+ default:
+ bus->max_tcslot = 1;
+ break;
+ }
+
/* Install our exception handler temporarily */
-
old_be_handler = dbe_board_handler;
dbe_board_handler = my_dbe_handler;
- for (slot = 0; slot <= max_slot; slot++) {
+
+ for (slot = 0; slot <= bus->max_slot; slot++) {
module = (char *)(startaddr + slot * size);
offset = -1;
- if (module[OLDCARD + TC_PATTERN0] == 0x55 && module[OLDCARD + TC_PATTERN1] == 0x00
- && module[OLDCARD + TC_PATTERN2] == 0xaa && module[OLDCARD + TC_PATTERN3] == 0xff)
+ if (module[OLDCARD + TC_PATTERN0] == 0x55 &&
+ module[OLDCARD + TC_PATTERN1] == 0x00 &&
+ module[OLDCARD + TC_PATTERN2] == 0xaa &&
+ module[OLDCARD + TC_PATTERN3] == 0xff)
offset = OLDCARD;
- if (module[TC_PATTERN0] == 0x55 && module[TC_PATTERN1] == 0x00
- && module[TC_PATTERN2] == 0xaa && module[TC_PATTERN3] == 0xff)
+ if (module[TC_PATTERN0] == 0x55 && module[TC_PATTERN1] == 0x00 &&
+ module[TC_PATTERN2] == 0xaa && module[TC_PATTERN3] == 0xff)
offset = 0;
if (offset != -1) {
- tc_bus[slot].base_addr = (unsigned long)module;
+ /* Found a board, allocate it an entry in the list */
+ dev = kmalloc(sizeof(struct tc_dev), GFP_KERNEL);
+ if (!dev)
+ return 0;
+ memset(dev, 0, sizeof(struct tc_dev));
+ dev->bus = &tc_bus;
+ dev->dev.parent = &tc_bus.dev;
+ dev->dev.bus = &tc_bus_type;
+ dev->slot = slot;
+
+ dev->base_addr = (unsigned long)module;
for(i = 0; i < 8; i++) {
- tc_bus[slot].firmware[i] = module[TC_FIRM_VER + offset + 4 * i];
- tc_bus[slot].vendor[i] = module[TC_VENDOR + offset + 4 * i];
- tc_bus[slot].name[i] = module[TC_MODULE + offset + 4 * i];
+ dev->firmware[i] = module[TC_FIRM_VER + offset + 4 * i];
+ dev->vendor[i] = module[TC_VENDOR + offset + 4 * i];
+ dev->name[i] = module[TC_MODULE + offset + 4 * i];
}
- tc_bus[slot].firmware[8] = 0;
- tc_bus[slot].vendor[8] = 0;
- tc_bus[slot].name[8] = 0;
+ dev->firmware[8] = 0;
+ dev->vendor[8] = 0;
+ dev->name[8] = 0;
+
/*
* Looks unneccesary, but we may change
* TC? in the future
*/
switch (slot) {
case 0:
- tc_bus[slot].interrupt = TC0;
+ dev->interrupt = TC0;
break;
case 1:
- tc_bus[slot].interrupt = TC1;
+ dev->interrupt = TC1;
break;
case 2:
- tc_bus[slot].interrupt = TC2;
+ dev->interrupt = TC2;
break;
/*
* Yuck! DS5000/200 onboard devices
*/
case 5:
- tc_bus[slot].interrupt = SCSI_INT;
+ dev->interrupt = SCSI_INT;
break;
case 6:
- tc_bus[slot].interrupt = ETHER;
+ dev->interrupt = ETHER;
break;
default:
- tc_bus[slot].interrupt = -1;
+ dev->interrupt = -1;
break;
- }
+ }
}
}
-
dbe_board_handler = old_be_handler;
+
+ /*
+ * All TURBOchannel DECstations have the onboard devices
+ * where the (max_tcslot + 1 or 2 on DS5k/xx) Option Module
+ * would be.
+ */
+ if (mips_machtype == MACH_DS5000_XX)
+ i = 2;
+ else
+ i = 1;
+ system_base = startaddr + size * (bus->max_tcslot + i);
}
/*
* the main entry
*/
-void __init tc_init(void)
+static int __init tc_init(void)
{
- int tc_clock;
- int i;
unsigned long slot0addr;
unsigned long slot_size;
-
+ int tc_clock;
+ int i;
+
if (!TURBOCHANNEL)
return;
- for (i = 0; i < MAX_SLOT; i++) {
- tc_bus[i].base_addr = 0;
- tc_bus[i].name[0] = 0;
- tc_bus[i].vendor[0] = 0;
- tc_bus[i].firmware[0] = 0;
- tc_bus[i].interrupt = -1;
- tc_bus[i].flags = FREE;
- }
+ /* Initialize the Turbo Channel bus */
+ INIT_LIST_HEAD(&tc_bus.devices);
+ strcpy(tc_bus.dev.bus_id, "TURBO Channel");
+ device_register(&tc_bus.dev);
- info = (tcinfo *) rex_gettcinfo();
+ tc_bus.info = (tcinfo *) rex_gettcinfo();
slot0addr = (unsigned long)KSEG1ADDR(rex_slot_address(0));
- switch (mips_machtype) {
- case MACH_DS5000_200:
- max_tcslot = 6;
- break;
- case MACH_DS5000_1XX:
- case MACH_DS5000_2X0:
- max_tcslot = 2;
- break;
- case MACH_DS5000_XX:
- default:
- max_tcslot = 1;
- break;
- }
-
- tc_clock = 10000 / info->clk_period;
+ tc_clock = 10000 / tc_bus.info->clk_period;
- if (TURBOCHANNEL && info->slot_size && slot0addr) {
- printk("TURBOchannel rev. %1d at %2d.%1d MHz ", info->revision,
+ if (tc_bus.info->slot_size && slot0addr) {
+ printk("TURBOchannel rev. %1d at %2d.%1d MHz", tc_bus.info->revision,
tc_clock / 10, tc_clock % 10);
- printk("(with%s parity)\n", info->parity ? "" : "out");
-
- slot_size = info->slot_size << 20;
-
- tc_probe(slot0addr, slot_size, max_tcslot);
-
- /*
- * All TURBOchannel DECstations have the onboard devices
- * where the (max_tcslot + 1 or 2 on DS5k/xx) Option Module
- * would be.
- */
- if(mips_machtype == MACH_DS5000_XX)
- i = 2;
- else
- i = 1;
-
- system_base = slot0addr + slot_size * (max_tcslot + i);
+ printk("(with%s parity)\n", tc_bus.info->parity ? "" : "out");
+ tc_bus_add_devices(&tc_bus, slot0addr);
#ifdef TC_DEBUG
- for (i = 0; i <= max_tcslot; i++)
- if (tc_bus[i].base_addr) {
+ for (i = 0; i <= tc_bus.max_tcslot; i++)
+ if (tc_devices[i].base_addr) {
printk(" slot %d: ", i);
- printk("%s %s %s\n", tc_bus[i].vendor,
- tc_bus[i].name, tc_bus[i].firmware);
+ printk("%s %s %s\n", tc_devices[i].vendor,
+ tc_devices[i].name, tc_devices[i].firmware);
}
#endif
ioport_resource.end = KSEG2 - 1;
@@ -238,9 +201,6 @@
subsys_initcall(tc_init);
-EXPORT_SYMBOL(search_tc_card);
-EXPORT_SYMBOL(claim_tc_card);
-EXPORT_SYMBOL(release_tc_card);
EXPORT_SYMBOL(get_tc_base_addr);
EXPORT_SYMBOL(get_tc_irq_nr);
EXPORT_SYMBOL(get_tc_speed);
diff -urN -X /home/jsimmons/dontdiff linus-2.6/drivers/video/pmag-ba-fb.c fbdev-2.6/drivers/video/pmag-ba-fb.c
--- linus-2.6/drivers/video/pmag-ba-fb.c 2005-01-21 10:23:49.000000000 -0800
+++ fbdev-2.6/drivers/video/pmag-ba-fb.c 2005-01-21 10:26:48.000000000 -0800
@@ -118,12 +118,12 @@
.fb_cursor = soft_cursor,
};
-int __init pmagbafb_init_one(int slot)
+static int __devinit pmagbafb_probe(struct tc_dev *dev)
{
- unsigned long base_addr = get_tc_base_addr(slot);
- struct fb_info *info = &pmagba_fb_info[slot];
+ struct fb_info *info = &pmagba_fb_info[dev->slot];
+ unsigned long base_addr = dev->base_addr;
- printk("PMAG-BA framebuffer in slot %d\n", slot);
+ printk("PMAG-BA framebuffer in slot %d\n", dev->slot);
/*
* Framebuffer display memory base address and friends
*/
@@ -155,24 +155,28 @@
* Initialise the framebuffer
*/
+static struct tc_device_id pmagbafb_tc_tbl[] = {
+ { "PMAG-BA" },
+ { 0 }
+};
+
+
+static struct tc_driver pmagbafb_driver = {
+ .name = "PMAG-BA",
+ .id_table = pmagbafb_tc_tbl,
+ .probe = pmagbafb_probe,
+};
+
int __init pmagbafb_init(void)
{
- int sid;
- int found = 0;
-
if (fb_get_options("pmagbafb", NULL))
return -ENODEV;
+ return tc_register_driver(&pmagbafb_driver);
+}
- if (TURBOCHANNEL) {
- while ((sid = search_tc_card("PMAG-BA")) >= 0) {
- found = 1;
- claim_tc_card(sid);
- pmagbafb_init_one(sid);
- }
- return found ? 0 : -ENODEV;
- } else {
- return -ENODEV;
- }
+void __exit pmagbafb_exit(void)
+{
+ tc_unregister_driver(&pmagbafb_driver);
}
module_init(pmagbafb_init);
diff -urN -X /home/jsimmons/dontdiff linus-2.6/include/asm-mips/dec/tc.h fbdev-2.6/include/asm-mips/dec/tc.h
--- linus-2.6/include/asm-mips/dec/tc.h 2005-01-21 10:25:17.000000000 -0800
+++ fbdev-2.6/include/asm-mips/dec/tc.h 2005-01-20 21:23:47.000000000 -0800
@@ -10,6 +10,47 @@
#ifndef ASM_TC_H
#define ASM_TC_H
+#include <linux/device.h>
+
+/*
+ * TURBOchannel Bus
+ */
+
+struct tc_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];
+ int max_tcslot;
+ tcinfo *info;
+};
+
+#define MAX_SLOT 7
+
+struct tc_dev {
+ struct tc_driver *driver;
+ struct tc_bus *bus;
+ struct device *dev;
+ unsigned long base_addr;
+ unsigned char name[9];
+ unsigned char vendor[9];
+ unsigned char firmware[9];
+ int interrupt;
+ int flags;
+ int slot;
+};
+
+/*
+ * * Values for flags
+ * */
+#define FREE 1<<0
+#define IN_USE 1<<1
+
+typedef char* tc_device_id;
+
+
extern unsigned long system_base;
/*
diff -urN -X /home/jsimmons/dontdiff linus-2.6/include/asm-mips/dec/tcinfo.h fbdev-2.6/include/asm-mips/dec/tcinfo.h
--- linus-2.6/include/asm-mips/dec/tcinfo.h 2005-01-21 10:25:17.000000000 -0800
+++ fbdev-2.6/include/asm-mips/dec/tcinfo.h 2005-01-20 20:34:25.000000000 -0800
@@ -27,21 +27,3 @@
int reserved[4];
} tcinfo;
-#define MAX_SLOT 7
-
-typedef struct {
- unsigned long base_addr;
- unsigned char name[9];
- unsigned char vendor[9];
- unsigned char firmware[9];
- int interrupt;
- int flags;
-} slot_info;
-
-/*
- * Values for flags
- */
-#define FREE 1<<0
-#define IN_USE 1<<1
-
-
On Sat, 2005-01-22 00:25:28 +0000, James Simmons <jsimmons@http://www.infradead.org>
wrote in message <[email protected]>:
>
> Experimenting with sysfs to figure out how it works. So I'm attempting to
> port the TurboChannel bus code to sysfs. Its a test of concept and a
> learning experience. Comments welcomed.
[...]
I haven't tested the code, but basically, it's a good step into the
right direction. The DECstations aren't yet really in the 2.6.x world,
but that doesn't degrade your good work :-) Also, it now seems easier
to me to integrate a different TC bus driver: this will be needed for
Linux' port to VAX computers, which may have TC busses, too.
MfG, JBG
--
Jan-Benedict Glaw [email protected] . +49-172-7608481 _ O _
"Eine Freie Meinung in einem Freien Kopf | Gegen Zensur | Gegen Krieg _ _ O
fuer einen Freien Staat voll Freier Bürger" | im Internet! | im Irak! O O O
ret = do_actions((curr | FREE_SPEECH) & ~(NEW_COPYRIGHT_LAW | DRM | TCPA));