diff options
191 files changed, 14716 insertions, 8527 deletions
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 144058cf849..5f96cb33743 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -183,18 +183,10 @@ Who: Jean Delvare <khali@linux-fr.org> --------------------------- -What: i2c_adapter.dev - i2c_adapter.list +What: i2c_adapter.list When: July 2007 -Why: Superfluous, given i2c_adapter.class_dev: - * The "dev" was a stand-in for the physical device node that legacy - drivers would not have; but now it's almost always present. Any - remaining legacy drivers must upgrade (they now trigger warnings). - * The "list" duplicates class device children. - The delay in removing this is so upgraded lm_sensors and libsensors - can get deployed. (Removal causes minor changes in the sysfs layout, - notably the location of the adapter type name and parenting the i2c - client hardware directly from their controller.) +Why: Superfluous, this list duplicates the one maintained by the driver + core. Who: Jean Delvare <khali@linux-fr.org>, David Brownell <dbrownell@users.sourceforge.net> @@ -307,3 +299,27 @@ Why: Code was merged, then submitter immediately disappeared leaving Who: David S. Miller <davem@davemloft.net> --------------------------- + +What: read_dev_chars(), read_conf_data{,_lpm}() (s390 common I/O layer) +When: December 2007 +Why: These functions are a leftover from 2.4 times. They have several + problems: + - Duplication of checks that are done in the device driver's + interrupt handler + - common I/O layer can't do device specific error recovery + - device driver can't be notified for conditions happening during + execution of the function + Device drivers should issue the read device characteristics and read + configuration data ccws and do the appropriate error handling + themselves. +Who: Cornelia Huck <cornelia.huck@de.ibm.com> + +--------------------------- + +What: i2c-ixp2000, i2c-ixp4xx and scx200_i2c drivers +When: September 2007 +Why: Obsolete. The new i2c-gpio driver replaces all hardware-specific + I2C-over-GPIO drivers. +Who: Jean Delvare <khali@linux-fr.org> + +--------------------------- diff --git a/Documentation/i2c/busses/i2c-nforce2 b/Documentation/i2c/busses/i2c-nforce2 index 7f61fbc03f7..fae3495bcba 100644 --- a/Documentation/i2c/busses/i2c-nforce2 +++ b/Documentation/i2c/busses/i2c-nforce2 @@ -9,6 +9,8 @@ Supported adapters: * nForce4 MCP-04 10de:0034 * nForce4 MCP51 10de:0264 * nForce4 MCP55 10de:0368 + * nForce4 MCP61 10de:03EB + * nForce4 MCP65 10de:0446 Datasheet: not publicly available, but seems to be similar to the AMD-8111 SMBus 2.0 adapter. diff --git a/Documentation/i2c/porting-clients b/Documentation/i2c/porting-clients index ca272b263a9..7bf82c08f6c 100644 --- a/Documentation/i2c/porting-clients +++ b/Documentation/i2c/porting-clients @@ -1,4 +1,4 @@ -Revision 6, 2005-11-20 +Revision 7, 2007-04-19 Jean Delvare <khali@linux-fr.org> Greg KH <greg@kroah.com> @@ -20,6 +20,10 @@ yours for best results. Technical changes: +* [Driver type] Any driver that was relying on i2c-isa has to be + converted to a proper isa, platform or pci driver. This is not + covered by this guide. + * [Includes] Get rid of "version.h" and <linux/i2c-proc.h>. Includes typically look like that: #include <linux/module.h> @@ -27,12 +31,10 @@ Technical changes: #include <linux/slab.h> #include <linux/jiffies.h> #include <linux/i2c.h> - #include <linux/i2c-isa.h> /* for ISA drivers */ #include <linux/hwmon.h> /* for hardware monitoring drivers */ #include <linux/hwmon-sysfs.h> #include <linux/hwmon-vid.h> /* if you need VRM support */ #include <linux/err.h> /* for class registration */ - #include <asm/io.h> /* if you have I/O operations */ Please respect this inclusion order. Some extra headers may be required for a given driver (e.g. "lm75.h"). @@ -69,20 +71,16 @@ Technical changes: sensors mailing list <lm-sensors@lm-sensors.org> by providing a patch to the Documentation/hwmon/sysfs-interface file. -* [Attach] For I2C drivers, the attach function should make sure - that the adapter's class has I2C_CLASS_HWMON (or whatever class is - suitable for your driver), using the following construct: +* [Attach] The attach function should make sure that the adapter's + class has I2C_CLASS_HWMON (or whatever class is suitable for your + driver), using the following construct: if (!(adapter->class & I2C_CLASS_HWMON)) return 0; - ISA-only drivers of course don't need this. Call i2c_probe() instead of i2c_detect(). * [Detect] As mentioned earlier, the flags parameter is gone. The type_name and client_name strings are replaced by a single name string, which will be filled with a lowercase, short string. - In i2c-only drivers, drop the i2c_is_isa_adapter check, it's - useless. Same for isa-only drivers, as the test would always be - true. Only hybrid drivers (which are quite rare) still need it. The labels used for error paths are reduced to the number needed. It is advised that the labels are given descriptive names such as exit and exit_free. Don't forget to properly set err before diff --git a/Documentation/i2c/summary b/Documentation/i2c/summary index 41dde877679..aea60bf7e8f 100644 --- a/Documentation/i2c/summary +++ b/Documentation/i2c/summary @@ -4,17 +4,23 @@ I2C and SMBus ============= I2C (pronounce: I squared C) is a protocol developed by Philips. It is a -slow two-wire protocol (10-400 kHz), but it suffices for many types of -devices. +slow two-wire protocol (variable speed, up to 400 kHz), with a high speed +extension (3.4 MHz). It provides an inexpensive bus for connecting many +types of devices with infrequent or low bandwidth communications needs. +I2C is widely used with embedded systems. Some systems use variants that +don't meet branding requirements, and so are not advertised as being I2C. -SMBus (System Management Bus) is a subset of the I2C protocol. Many -modern mainboards have a System Management Bus. There are a lot of -devices which can be connected to a SMBus; the most notable are modern -memory chips with EEPROM memories and chips for hardware monitoring. +SMBus (System Management Bus) is based on the I2C protocol, and is mostly +a subset of I2C protocols and signaling. Many I2C devices will work on an +SMBus, but some SMBus protocols add semantics beyond what is required to +achieve I2C branding. Modern PC mainboards rely on SMBus. The most common +devices connected through SMBus are RAM modules configured using I2C EEPROMs, +and hardware monitoring chips. -Because the SMBus is just a special case of the generalized I2C bus, we -can simulate the SMBus protocol on plain I2C busses. The reverse is -regretfully impossible. +Because the SMBus is mostly a subset of the generalized I2C bus, we can +use its protocols on many I2C systems. However, there are systems that don't +meet both SMBus and I2C electrical constraints; and others which can't +implement all the common SMBus protocol semantics or messages. Terminology @@ -29,6 +35,7 @@ When we talk about I2C, we use the following terms: An Algorithm driver contains general code that can be used for a whole class of I2C adapters. Each specific adapter driver depends on one algorithm driver. + A Driver driver (yes, this sounds ridiculous, sorry) contains the general code to access some type of device. Each detected device gets its own data in the Client structure. Usually, Driver and Client are more closely @@ -40,6 +47,10 @@ a separate Adapter and Algorithm driver), and drivers for your I2C devices in this package. See the lm_sensors project http://www.lm-sensors.nu for device drivers. +At this time, Linux only operates I2C (or SMBus) in master mode; you can't +use these APIs to make a Linux system behave as a slave/device, either to +speak a custom protocol or to emulate some other device. + Included Bus Drivers ==================== diff --git a/Documentation/i2c/writing-clients b/Documentation/i2c/writing-clients index fbcff96f4ca..3d8d36b0ad1 100644 --- a/Documentation/i2c/writing-clients +++ b/Documentation/i2c/writing-clients @@ -1,5 +1,5 @@ This is a small guide for those who want to write kernel drivers for I2C -or SMBus devices. +or SMBus devices, using Linux as the protocol host/master (not slave). To set up a driver, you need to do several things. Some are optional, and some things can be done slightly or completely different. Use this as a @@ -29,8 +29,16 @@ static struct i2c_driver foo_driver = { .driver = { .name = "foo", }, + + /* iff driver uses driver model ("new style") binding model: */ + .probe = foo_probe, + .remove = foo_remove, + + /* else, driver uses "legacy" binding model: */ .attach_adapter = foo_attach_adapter, .detach_client = foo_detach_client, + + /* these may be used regardless of the driver binding model */ .shutdown = foo_shutdown, /* optional */ .suspend = foo_suspend, /* optional */ .resume = foo_resume, /* optional */ @@ -40,7 +48,8 @@ static struct i2c_driver foo_driver = { The name field is the driver name, and must not contain spaces. It should match the module name (if the driver can be compiled as a module), although you can use MODULE_ALIAS (passing "foo" in this example) to add -another name for the module. +another name for the module. If the driver name doesn't match the module +name, the module won't be automatically loaded (hotplug/coldplug). All other fields are for call-back functions which will be explained below. @@ -65,16 +74,13 @@ An example structure is below. struct foo_data { struct i2c_client client; - struct semaphore lock; /* For ISA access in `sensors' drivers. */ - int sysctl_id; /* To keep the /proc directory entry for - `sensors' drivers. */ enum chips type; /* To keep the chips type for `sensors' drivers. */ /* Because the i2c bus is slow, it is often useful to cache the read information of a chip for some time (for example, 1 or 2 seconds). It depends of course on the device whether this is really worthwhile or even sensible. */ - struct semaphore update_lock; /* When we are reading lots of information, + struct mutex update_lock; /* When we are reading lots of information, another process should not update the below information */ char valid; /* != 0 if the following fields are valid. */ @@ -95,8 +101,7 @@ some obscure clients). But we need generic reading and writing routines. I have found it useful to define foo_read and foo_write function for this. For some cases, it will be easier to call the i2c functions directly, but many chips have some kind of register-value idea that can easily -be encapsulated. Also, some chips have both ISA and I2C interfaces, and -it useful to abstract from this (only for `sensors' drivers). +be encapsulated. The below functions are simple examples, and should not be copied literally. @@ -119,28 +124,101 @@ literally. return i2c_smbus_write_word_data(client,reg,value); } -For sensors code, you may have to cope with ISA registers too. Something -like the below often works. Note the locking! - - int foo_read_value(struct i2c_client *client, u8 reg) - { - int res; - if (i2c_is_isa_client(client)) { - down(&(((struct foo_data *) (client->data)) -> lock)); - outb_p(reg,client->addr + FOO_ADDR_REG_OFFSET); - res = inb_p(client->addr + FOO_DATA_REG_OFFSET); - up(&(((struct foo_data *) (client->data)) -> lock)); - return res; - } else - return i2c_smbus_read_byte_data(client,reg); - } - -Writing is done the same way. - Probing and attaching ===================== +The Linux I2C stack was originally written to support access to hardware +monitoring chips on PC motherboards, and thus it embeds some assumptions +that are more appropriate to SMBus (and PCs) than to I2C. One of these +assumptions is that most adapters and devices drivers support the SMBUS_QUICK +protocol to probe device presence. Another is that devices and their drivers +can be sufficiently configured using only such probe primitives. + +As Linux and its I2C stack became more widely used in embedded systems +and complex components such as DVB adapters, those assumptions became more +problematic. Drivers for I2C devices that issue interrupts need more (and +different) configuration information, as do drivers handling chip variants +that can't be distinguished by protocol probing, or which need some board +specific information to operate correctly. + +Accordingly, the I2C stack now has two models for associating I2C devices +with their drivers: the original "legacy" model, and a newer one that's +fully compatible with the Linux 2.6 driver model. These models do not mix, +since the "legacy" model requires drivers to create "i2c_client" device +objects after SMBus style probing, while the Linux driver model expects +drivers to be given such device objects in their probe() routines. + + +Standard Driver Model Binding ("New Style") +------------------------------------------- + +System infrastructure, typically board-specific initialization code or +boot firmware, reports what I2C devices exist. For example, there may be +a table, in the kernel or from the boot loader, identifying I2C devices +and linking them to board-specific configuration information about IRQs +and other wiring artifacts, chip type, and so on. That could be used to +create i2c_client objects for each I2C device. + +I2C device drivers using this binding model work just like any other +kind of driver in Linux: they provide a probe() method to bind to +those devices, and a remove() method to unbind. + + static int foo_probe(struct i2c_client *client); + static int foo_remove(struct i2c_client *client); + +Remember that the i2c_driver does not create those client handles. The +handle may be used during foo_probe(). If foo_probe() reports success +(zero not a negative status code) it may save the handle and use it until +foo_remove() returns. That binding model is used by most Linux drivers. + +Drivers match devices when i2c_client.driver_name and the driver name are +the same; this approach is used in several other busses that don't have +device typing support in the hardware. The driver and module name should +match, so hotplug/coldplug mechanisms will modprobe the driver. + + +Device Creation (Standard driver model) +--------------------------------------- + +If you know for a fact that an I2C device is connected to a given I2C bus, +you can instantiate that device by simply filling an i2c_board_info +structure with the device address and driver name, and calling +i2c_new_device(). This will create the device, then the driver core will +take care of finding the right driver and will call its probe() method. +If a driver supports different device types, you can specify the type you +want using the type field. You can also specify an IRQ and platform data +if needed. + +Sometimes you know that a device is connected to a given I2C bus, but you +don't know the exact address it uses. This happens on TV adapters for +example, where the same driver supports dozens of slightly different +models, and I2C device addresses change from one model to the next. In +that case, you can use the i2c_new_probed_device() variant, which is +similar to i2c_new_device(), except that it takes an additional list of +possible I2C addresses to probe. A device is created for the first +responsive address in the list. If you expect more than one device to be +present in the address range, simply call i2c_new_probed_device() that +many times. + +The call to i2c_new_device() or i2c_new_probed_device() typically happens +in the I2C bus driver. You may want to save the returned i2c_client +reference for later use. + + +Device Deletion (Standard driver model) +--------------------------------------- + +Each I2C device which has been created using i2c_new_device() or +i2c_new_probed_device() can be unregistered by calling +i2c_unregister_device(). If you don't call it explicitly, it will be +called automatically before the underlying I2C bus itself is removed, as a +device can't survive its parent in the device driver model. + + +Legacy Driver Binding Model +--------------------------- + Most i2c devices can be present on several i2c addresses; for some this is determined in hardware (by soldering some chip pins to Vcc or Ground), for others this can be changed in software (by writing to specific client @@ -157,13 +235,9 @@ detection algorithm. You do not have to use this parameter interface; but don't try to use function i2c_probe() if you don't. -NOTE: If you want to write a `sensors' driver, the interface is slightly - different! See below. - - -Probing classes ---------------- +Probing classes (Legacy model) +------------------------------ All parameters are given as lists of unsigned 16-bit integers. Lists are terminated by I2C_CLIENT_END. @@ -210,8 +284,8 @@ Note that you *have* to call the defined variable `normal_i2c', without any prefix! -Attaching to an adapter ------------------------ +Attaching to an adapter (Legacy model) +-------------------------------------- Whenever a new adapter is inserted, or for all adapters if the driver is being registered, the callback attach_adapter() is called. Now is the @@ -237,17 +311,13 @@ them (unless a `force' parameter was used). In addition, addresses that are already in use (by some other registered client) are skipped. -The detect client function --------------------------- +The detect client function (Legacy model) +----------------------------------------- The detect client function is called by i2c_probe. The `kind' parameter contains -1 for a probed detection, 0 for a forced detection, or a positive number for a forced detection with a chip type forced. -Below, some things are only needed if this is a `sensors' driver. Those -parts are between /* SENSORS ONLY START */ and /* SENSORS ONLY END */ -markers. - Returning an error different from -ENODEV in a detect function will cause the detection to stop: other addresses and adapters won't be scanned. This should only be done on fatal or internal errors, such as a memory @@ -256,64 +326,20 @@ shortage or i2c_attach_client failing. For now, you can ignore the `flags' parameter. It is there for future use. int foo_detect_client(struct i2c_adapter *adapter, int address, - unsigned short flags, int kind) + int kind) { int err = 0; int i; - struct i2c_client *new_client; + struct i2c_client *client; struct foo_data *data; - const char *client_name = ""; /* For non-`sensors' drivers, put the real - name here! */ + const char *name = ""; /* Let's see whether this adapter can support what we need. - Please substitute the things you need here! - For `sensors' drivers, add `! is_isa &&' to the if statement */ + Please substitute the things you need here! */ if (!i2c_check_functionality(adapter,I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_WRITE_BYTE)) goto ERROR0; - /* SENSORS ONLY START */ - const char *type_name = ""; - int is_isa = i2c_is_isa_adapter(adapter); - - /* Do this only if the chip can additionally be found on the ISA bus - (hybrid chip). */ - - if (is_isa) { - - /* Discard immediately if this ISA range is already used */ - /* FIXME: never use check_region(), only request_region() */ - if (check_region(address,FOO_EXTENT)) - goto ERROR0; - - /* Probe whether there is anything on this address. - Some example code is below, but you will have to adapt this - for your own driver */ - - if (kind < 0) /* Only if no force parameter was used */ { - /* We may need long timeouts at least for some chips. */ - #define REALLY_SLOW_IO - i = inb_p(address + 1); - if (inb_p(address + 2) != i) - goto ERROR0; - if (inb_p(address + 3) != i) - goto ERROR0; - if (inb_p(address + 7) != i) - goto ERROR0; - #undef REALLY_SLOW_IO - - /* Let's just hope nothing breaks here */ - i = inb_p(address + 5) & 0x7f; - outb_p(~i & 0x7f,address+5); - if ((inb_p(address + 5) & 0x7f) != (~i & 0x7f)) { - outb_p(i,address+5); - return 0; - } - } - } - - /* SENSORS ONLY END */ - /* OK. For now, we presume we have a valid client. We now create the client structure, even though we cannot fill it completely yet. But it allows us to access several i2c functions safely */ @@ -323,13 +349,12 @@ For now, you can ignore the `flags' parameter. It is there for future use. goto ERROR0; } - new_client = &data->client; - i2c_set_clientdata(new_client, data); + client = &data->client; + i2c_set_clientdata(client, data); - new_client->addr = address; - new_client->adapter = adapter; - new_client->driver = &foo_driver; - new_client->flags = 0; + client->addr = address; + client->adapter = adapter; + client->driver = &foo_driver; /* Now, we do the remaining detection. If no `force' parameter is used. */ @@ -337,19 +362,17 @@ For now, you can ignore the `flags' parameter. It is there for future use. parameter was used. */ if (kind < 0) { /* The below is of course bogus */ - if (foo_read(new_client,FOO_REG_GENERIC) != FOO_GENERIC_VALUE) + if (foo_read(client, FOO_REG_GENERIC) != FOO_GENERIC_VALUE) goto ERROR1; } - /* SENSORS ONLY START */ - /* Next, specific detection. This is especially important for `sensors' devices. */ /* Determine the chip type. Not needed if a `force_CHIPTYPE' parameter was used. */ if (kind <= 0) { - i = foo_read(new_client,FOO_REG_CHIPTYPE); + i = foo_read(client, FOO_REG_CHIPTYPE); if (i == FOO_TYPE_1) kind = chip1; /* As defined in the enum */ else if (i == FOO_TYPE_2) @@ -363,63 +386,31 @@ For now, you can ignore the `flags' parameter. It is there for future use. /* Now set the type and chip names */ if (kind == chip1) { - type_name = "chip1"; /* For /proc entry */ - client_name = "CHIP 1"; + name = "chip1"; } else if (kind == chip2) { - type_name = "chip2"; /* For /proc entry */ - client_name = "CHIP 2"; + name = "chip2"; } - /* Reserve the ISA region */ - if (is_isa) - request_region(address,FOO_EXTENT,type_name); - - /* SENSORS ONLY END */ - /* Fill in the remaining client fields. */ - strcpy(new_client->name,client_name); - - /* SENSORS ONLY BEGIN */ + strlcpy(client->name, name, I2C_NAME_SIZE); data->type = kind; - /* SENSORS ONLY END */ - - data->valid = 0; /* Only if you use this field */ - init_MUTEX(&data->update_lock); /* Only if you use this field */ + mutex_init(&data->update_lock); /* Only if you use this field */ /* Any other initializations in data must be done here too. */ - /* Tell the i2c layer a new client has arrived */ - if ((err = i2c_attach_client(new_client))) - goto ERROR3; - - /* SENSORS ONLY BEGIN */ - /* Register a new directory entry with module sensors. See below for - the `template' structure. */ - if ((i = i2c_register_entry(new_client, type_name, - foo_dir_table_template,THIS_MODULE)) < 0) { - err = i; - goto ERROR4; - } - data->sysctl_id = i; - - /* SENSORS ONLY END */ - /* This function can write default values to the client registers, if needed. */ - foo_init_client(new_client); + foo_init_client(client); + + /* Tell the i2c layer a new client has arrived */ + if ((err = i2c_attach_client(client))) + goto ERROR1; + return 0; /* OK, this is not exactly good programming practice, usually. But it is very code-efficient in this case. */ - ERROR4: - i2c_detach_client(new_client); - ERROR3: - ERROR2: - /* SENSORS ONLY START */ - if (is_isa) - release_region(address,FOO_EXTENT); - /* SENSORS ONLY END */ ERROR1: kfree(data); ERROR0: @@ -427,8 +418,8 @@ For now, you can ignore the `flags' parameter. It is there for future use. } -Removing the client -=================== +Removing the client (Legacy model) +================================== The detach_client call back function is called when a client should be removed. It may actually fail, but only when panicking. This code is @@ -436,22 +427,12 @@ much simpler than the attachment code, fortunately! int foo_detach_client(struct i2c_client *client) { - int err,i; - - /* SENSORS ONLY START */ - /* Deregister with the `i2c-proc' module. */ - i2c_deregister_entry(((struct lm78_data *)(client->data))->sysctl_id); - /* SENSORS ONLY END */ + int err; /* Try to detach the client from i2c space */ if ((err = i2c_detach_client(client))) return err; - /* HYBRID SENSORS CHIP ONLY START */ - if i2c_is_isa_client(client) - release_region(client->addr,LM78_EXTENT); - /* HYBRID SENSORS CHIP ONLY END */ - kfree(i2c_get_clientdata(client)); return 0; } @@ -464,45 +445,34 @@ When the kernel is booted, or when your foo driver module is inserted, you have to do some initializing. Fortunately, just attaching (registering) the driver module is usually enough. - /* Keep track of how far we got in the initialization process. If several - things have to initialized, and we fail halfway, only those things - have to be cleaned up! */ - static int __initdata foo_initialized = 0; - static int __init foo_init(void) { int res; - printk("foo version %s (%s)\n",FOO_VERSION,FOO_DATE); if ((res = i2c_add_driver(&foo_driver))) { printk("foo: Driver registration failed, module not inserted.\n"); - foo_cleanup(); return res; } - foo_initialized ++; return 0; } - void foo_cleanup(void) + static void __exit foo_cleanup(void) { - if (foo_initialized == 1) { - if ((res = i2c_del_driver(&foo_driver))) { - printk("foo: Driver registration failed, module not removed.\n"); - return; - } - foo_initialized --; - } + i2c_del_driver(&foo_driver); } /* Substitute your own name and email address */ MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>" MODULE_DESCRIPTION("Driver for Barf Inc. Foo I2C devices"); + /* a few non-GPL license types are also allowed */ + MODULE_LICENSE("GPL"); + module_init(foo_init); module_exit(foo_cleanup); Note that some functions are marked by `__init', and some data structures -by `__init_data'. Hose functions and structures can be removed after +by `__initdata'. These functions and structures can be removed after kernel booting (or module loading) is completed. @@ -632,110 +602,7 @@ General purpose routines Below all general purpose routines are listed, that were not mentioned before. - /* This call returns a unique low identifier for each registered adapter, - * or -1 if the adapter was not registered. + /* This call returns a unique low identifier for each registered adapter. */ extern int i2c_adapter_id(struct i2c_adapter *adap); - -The sensors sysctl/proc interface -================================= - -This section only applies if you write `sensors' drivers. - -Each sensors driver creates a directory in /proc/sys/dev/sensors for each -registered client. The directory is called something like foo-i2c-4-65. -The sensors module helps you to do this as easily as possible. - -The template ------------- - -You will need to define a ctl_table template. This template will automatically -be copied to a newly allocated structure and filled in where necessary when -you call sensors_register_entry. - -First, I will give an example definition. - static ctl_table foo_dir_table_template[] = { - { FOO_SYSCTL_FUNC1, "func1", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real,NULL,&foo_func }, - { FOO_SYSCTL_FUNC2, "func2", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real,NULL,&foo_func }, - { FOO_SYSCTL_DATA, "data", NULL, 0, 0644, NULL, &i2c_proc_real, - &i2c_sysctl_real,NULL,&foo_data }, - { 0 } - }; - -In the above example, three entries are defined. They can either be -accessed through the /proc interface, in the /proc/sys/dev/sensors/* -directories, as files named func1, func2 and data, or alternatively -through the sysctl interface, in the appropriate table, with identifiers -FOO_SYSCTL_FUNC1, FOO_SYSCTL_FUNC2 and FOO_SYSCTL_DATA. - -The third, sixth and ninth parameters should always be NULL, and the -fourth should always be 0. The fifth is the mode of the /proc file; -0644 is safe, as the file will be owned by root:root. - -The seventh and eighth parameters should be &i2c_proc_real and -&i2c_sysctl_real if you want to export lists of reals (scaled -integers). You can also use your own function for them, as usual. -Finally, the last parameter is the call-back to gather the data -(see below) if you use the *_proc_real functions. - - -Gathering the data ------------------- - -The call back functions (foo_func and foo_data in the above example) -can be called in several ways; the operation parameter determines -what should be done: - - * If operation == SENSORS_PROC_REAL_INFO, you must return the - magnitude (scaling) in nrels_mag; - * If operation == SENSORS_PROC_REAL_READ, you must read information - from the chip and return it in results. The number of integers - to display should be put in nrels_mag; - * If operation == SENSORS_PROC_REAL_WRITE, you must write the - supplied information to the chip. nrels_mag will contain the number - of integers, results the integers themselves. - -The *_proc_real functions will display the elements as reals for the -/proc interface. If you set the magnitude to 2, and supply 345 for -SENSORS_PROC_REAL_READ, it would display 3.45; and if the user would -write 45.6 to the /proc file, it would be returned as 4560 for -SENSORS_PROC_REAL_WRITE. A magnitude may even be negative! - -An example function: - - /* FOO_FROM_REG and FOO_TO_REG translate between scaled values and - register values. Note the use of the read cache. */ - void foo_in(struct i2c_client *client, int operation, int ctl_name, - int *nrels_mag, long *results) - { - struct foo_data *data = client->data; - int nr = ctl_name - FOO_SYSCTL_FUNC1; /* reduce to 0 upwards */ - - if (operation == SENSORS_PROC_REAL_INFO) - *nrels_mag = 2; - else if (operation == SENSORS_PROC_REAL_READ) { - /* Update the readings cache (if necessary) */ - foo_update_client(client); - /* Get the readings from the cache */ - results[0] = FOO_FROM_REG(data->foo_func_base[nr]); - results[1] = FOO_FROM_REG(data->foo_func_more[nr]); - results[2] = FOO_FROM_REG(data->foo_func_readonly[nr]); - *nrels_mag = 2; - } else if (operation == SENSORS_PROC_REAL_WRITE) { - if (*nrels_mag >= 1) { - /* Update the cache */ - data->foo_base[nr] = FOO_TO_REG(results[0]); - /* Update the chip */ - foo_write_value(client,FOO_REG_FUNC_BASE(nr),data->foo_base[nr]); - } - if (*nrels_mag >= 2) { - /* Update the cache */ - data->foo_more[nr] = FOO_TO_REG(results[1]); - /* Update the chip */ - foo_write_value(client,FOO_REG_FUNC_MORE(nr),data->foo_more[nr]); - } - } - } diff --git a/Documentation/usb/usb-serial.txt b/Documentation/usb/usb-serial.txt index d61f6e7865d..b18e86a2250 100644 --- a/Documentation/usb/usb-serial.txt +++ b/Documentation/usb/usb-serial.txt @@ -42,7 +42,7 @@ ConnectTech WhiteHEAT 4 port converter http://www.connecttech.com For any questions or problems with this driver, please contact - Stuart MacDonald at stuartm@connecttech.com + Connect Tech's Support Department at support@connecttech.com HandSpring Visor, Palm USB, and Clié USB driver diff --git a/MAINTAINERS b/MAINTAINERS index af1c7926c15..1e8c37054ea 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -733,6 +733,13 @@ M: tigran@aivazian.fsnet.co.uk L: linux-kernel@vger.kernel.org S: Maintained +BLACKFIN I2C TWI DRIVER +P: Sonic Zhang +M: sonic.zhang@analog.com +L: uclinux-dist-devel@blackfin.uclinux.org (subscribers-only) +W: http://blackfin.uclinux.org/ +S: Supported + BLOCK LAYER P: Jens Axboe M: axboe@kernel.dk @@ -1459,6 +1466,11 @@ L: linux-scsi@vger.kernel.org W: http://www.icp-vortex.com/ S: Supported +GENERIC GPIO I2C DRIVER +P: Haavard Skinnemoen +M: hskinnemoen@atmel.com +S: Supported + GENERIC HDLC DRIVER, N2, C101, PCI200SYN and WANXL DRIVERS P: Krzysztof Halasa M: khc@pm.waw.pl @@ -1631,6 +1643,13 @@ L: i2c@lm-sensors.org T: quilt http://khali.linux-fr.org/devel/linux-2.6/jdelvare-i2c/ S: Maintained +I2C-TINY-USB DRIVER +P: Till Harbaum +M: till@harbaum.org +L: i2c@lm-sensors.org +T: http://www.harbaum.org/till/i2c_tiny_usb +S: Maintained + i386 BOOT CODE P: Riley H. Williams M: Riley@Williams.Name @@ -3627,8 +3646,8 @@ W: http://www.kroah.com/linux/ S: Maintained USB SERIAL WHITEHEAT DRIVER -P: Stuart MacDonald -M: stuartm@connecttech.com +P: Support Department +M: support@connecttech.com L: linux-usb-users@lists.sourceforge.net L: linux-usb-devel@lists.sourceforge.net W: http://www.connecttech.com diff --git a/arch/i386/kernel/cpu/cpufreq/longhaul.c b/arch/i386/kernel/cpu/cpufreq/longhaul.c index 2b030d6ccbf..a3df9c039bd 100644 --- a/arch/i386/kernel/cpu/cpufreq/longhaul.c +++ b/arch/i386/kernel/cpu/cpufreq/longhaul.c @@ -590,20 +590,23 @@ static acpi_status longhaul_walk_callback(acpi_handle obj_handle, static int enable_arbiter_disable(void) { struct pci_dev *dev; + int status; int reg; u8 pci_cmd; + status = 1; /* Find PLE133 host bridge */ reg = 0x78; - dev = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8601_0, NULL); + dev = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8601_0, + NULL); /* Find CLE266 host bridge */ if (dev == NULL) { reg = 0x76; - dev = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_862X_0, NULL); + dev = pci_get_device(PCI_VENDOR_ID_VIA, + PCI_DEVICE_ID_VIA_862X_0, NULL); /* Find CN400 V-Link host bridge */ if (dev == NULL) - dev = pci_find_device(PCI_VENDOR_ID_VIA, 0x7259, NULL); - + dev = pci_get_device(PCI_VENDOR_ID_VIA, 0x7259, NULL); } if (dev != NULL) { /* Enable access to port 0x22 */ @@ -615,10 +618,11 @@ static int enable_arbiter_disable(void) if (!(pci_cmd & 1<<7)) { printk(KERN_ERR PFX "Can't enable access to port 0x22.\n"); - return 0; + status = 0; } } - return 1; + pci_dev_put(dev); + return status; } return 0; } @@ -629,7 +633,7 @@ static int longhaul_setup_vt8235(void) u8 pci_cmd; /* Find VT8235 southbridge */ - dev = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235, NULL); + dev = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235, NULL); if (dev != NULL) { /* Set transition time to max */ pci_read_config_byte(dev, 0xec, &pci_cmd); @@ -641,6 +645,7 @@ static int longhaul_setup_vt8235(void) pci_read_config_byte(dev, 0xe5, &pci_cmd); pci_cmd |= 1 << 7; pci_write_config_byte(dev, 0xe5, pci_cmd); + pci_dev_put(dev); return 1; } return 0; @@ -678,7 +683,7 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy) sizeof(samuel2_eblcr)); break; case 1 ... 15: - longhaul_version = TYPE_LONGHAUL_V2; + longhaul_version = TYPE_LONGHAUL_V1; if (c->x86_mask < 8) { cpu_model = CPU_SAMUEL2; cpuname = "C3 'Samuel 2' [C5B]"; diff --git a/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c b/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c index 4786fedca6e..4c76b511e19 100644 --- a/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c +++ b/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c @@ -27,7 +27,6 @@ #include <linux/cpufreq.h> #include <linux/slab.h> #include <linux/cpumask.h> -#include <linux/sched.h> /* current / set_cpus_allowed() */ #include <asm/processor.h> #include <asm/msr.h> @@ -62,7 +61,7 @@ static int cpufreq_p4_setdc(unsigned int cpu, unsigned int newstate) if (!cpu_online(cpu) || (newstate > DC_DISABLE) || (newstate == DC_RESV)) return -EINVAL; - rdmsr(MSR_IA32_THERM_STATUS, l, h); + rdmsr_on_cpu(cpu, MSR_IA32_THERM_STATUS, &l, &h); if (l & 0x01) dprintk("CPU#%d currently thermal throttled\n", cpu); @@ -70,10 +69,10 @@ static int cpufreq_p4_setdc(unsigned int cpu, unsigned int newstate) if (has_N44_O17_errata[cpu] && (newstate == DC_25PT || newstate == DC_DFLT)) newstate = DC_38PT; - rdmsr(MSR_IA32_THERM_CONTROL, l, h); + rdmsr_on_cpu(cpu, MSR_IA32_THERM_CONTROL, &l, &h); if (newstate == DC_DISABLE) { dprintk("CPU#%d disabling modulation\n", cpu); - wrmsr(MSR_IA32_THERM_CONTROL, l & ~(1<<4), h); + wrmsr_on_cpu(cpu, MSR_IA32_THERM_CONTROL, l & ~(1<<4), h); } else { dprintk("CPU#%d setting duty cycle to %d%%\n", cpu, ((125 * newstate) / 10)); @@ -84,7 +83,7 @@ static int cpufreq_p4_setdc(unsigned int cpu, unsigned int newstate) */ l = (l & ~14); l = l | (1<<4) | ((newstate & 0x7)<<1); - wrmsr(MSR_IA32_THERM_CONTROL, l, h); + wrmsr_on_cpu(cpu, MSR_IA32_THERM_CONTROL, l, h); } return 0; @@ -111,7 +110,6 @@ static int cpufreq_p4_target(struct cpufreq_policy *policy, { unsigned int newstate = DC_RESV; struct cpufreq_freqs freqs; - cpumask_t cpus_allowed; int i; if (cpufreq_frequency_table_target(policy, &p4clockmod_table[0], target_freq, relation, &newstate)) @@ -132,17 +130,8 @@ static int cpufreq_p4_target(struct cpufreq_policy *policy, /* run on each logical CPU, see section 13.15.3 of IA32 Intel Architecture Software * Developer's Manual, Volume 3 */ - cpus_allowed = current->cpus_allowed; - - for_each_cpu_mask(i, policy->cpus) { - cpumask_t this_cpu = cpumask_of_cpu(i); - - set_cpus_allowed(current, this_cpu); - BUG_ON(smp_processor_id() != i); - + for_each_cpu_mask(i, policy->cpus) cpufreq_p4_setdc(i, p4clockmod_table[newstate].index); - } - set_cpus_allowed(current, cpus_allowed); /* notifiers */ for_each_cpu_mask(i, policy->cpus) { @@ -256,17 +245,9 @@ static int cpufreq_p4_cpu_exit(struct cpufreq_policy *policy) static unsigned int cpufreq_p4_get(unsigned int cpu) { - cpumask_t cpus_allowed; u32 l, h; - cpus_allowed = current->cpus_allowed; - - set_cpus_allowed(current, cpumask_of_cpu(cpu)); - BUG_ON(smp_processor_id() != cpu); - - rdmsr(MSR_IA32_THERM_CONTROL, l, h); - - set_cpus_allowed(current, cpus_allowed); + rdmsr_on_cpu(cpu, MSR_IA32_THERM_CONTROL, &l, &h); if (l & 0x10) { l = l >> 1; diff --git a/arch/i386/kernel/cpu/cpufreq/powernow-k8.c b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c index fe3b67005eb..7cf3d207b6b 100644 --- a/arch/i386/kernel/cpu/cpufreq/powernow-k8.c +++ b/arch/i386/kernel/cpu/cpufreq/powernow-k8.c @@ -661,7 +661,8 @@ static int fill_powernow_table(struct powernow_k8_data *data, struct pst_s *pst, dprintk("cfid 0x%x, cvid 0x%x\n", data->currfid, data->currvid); data->powernow_table = powernow_table; - print_basics(data); + if (first_cpu(cpu_core_map[data->cpu]) == data->cpu) + print_basics(data); for (j = 0; j < data->numps; j++) if ((pst[j].fid==data->currfid) && (pst[j].vid==data->currvid)) @@ -814,7 +815,8 @@ static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data) /* fill in data */ data->numps = data->acpi_data.state_count; - print_basics(data); + if (first_cpu(cpu_core_map[data->cpu]) == data->cpu) + print_basics(data); powernow_k8_acpi_pst_values(data, 0); /* notify BIOS that we exist */ diff --git a/arch/i386/kernel/cpu/cpufreq/powernow-k8.h b/arch/i386/kernel/cpu/cpufreq/powernow-k8.h index 0fb2a3001ba..95be5013c98 100644 --- a/arch/i386/kernel/cpu/cpufreq/powernow-k8.h +++ b/arch/i386/kernel/cpu/cpufreq/powernow-k8.h @@ -215,8 +215,10 @@ static int core_frequency_transition(struct powernow_k8_data *data, u32 reqfid); static void powernow_k8_acpi_pst_values(struct powernow_k8_data *data, unsigned int index); +#ifdef CONFIG_X86_POWERNOW_K8_ACPI static int fill_powernow_table_pstate(struct powernow_k8_data *data, struct cpufreq_frequency_table *powernow_table); static int fill_powernow_table_fidvid(struct powernow_k8_data *data, struct cpufreq_frequency_table *powernow_table); +#endif #ifdef CONFIG_SMP static inline void define_siblings(int cpu, cpumask_t cpu_sharedcore_mask[]) diff --git a/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c b/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c index f43b987f952..35489fd6885 100644 --- a/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c +++ b/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c @@ -720,6 +720,7 @@ static int centrino_target (struct cpufreq_policy *policy, cpu_set(j, set_mask); set_cpus_allowed(current, set_mask); + preempt_disable(); if (unlikely(!cpu_isset(smp_processor_id(), set_mask))) { dprintk("couldn't limit to CPUs in this domain\n"); retval = -EAGAIN; @@ -727,6 +728,7 @@ static int centrino_target (struct cpufreq_policy *policy, /* We haven't started the transition yet. */ goto migrate_end; } + preempt_enable(); break; } @@ -761,10 +763,13 @@ static int centrino_target (struct cpufreq_policy *policy, } wrmsr(MSR_IA32_PERF_CTL, oldmsr, h); - if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) + if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) { + preempt_enable(); break; + } cpu_set(j, covered_cpus); + preempt_enable(); } for_each_cpu_mask(k, online_policy_cpus) { @@ -796,8 +801,11 @@ static int centrino_target (struct cpufreq_policy *policy, cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); } } + set_cpus_allowed(current, saved_mask); + return 0; migrate_end: + preempt_enable(); set_cpus_allowed(current, saved_mask); return 0; } diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig index a8e1e604dfa..b8536c7c087 100644 --- a/arch/m68k/Kconfig +++ b/arch/m68k/Kconfig @@ -409,6 +409,9 @@ config STRAM_PROC help Say Y here to report ST-RAM usage statistics in /proc/stram. +config ATARI_KBD_CORE + bool + config HEARTBEAT bool "Use power LED as a heartbeat" if AMIGA || APOLLO || ATARI || MAC ||Q40 default y if !AMIGA && !APOLLO && !ATARI && !MAC && !Q40 && HP300 diff --git a/arch/m68k/Makefile b/arch/m68k/Makefile index 34d826d10f1..c20831a7e1a 100644 --- a/arch/m68k/Makefile +++ b/arch/m68k/Makefile @@ -21,7 +21,7 @@ AS += -m68020 LDFLAGS := -m m68kelf ifneq ($(COMPILE_ARCH),$(ARCH)) # prefix for cross-compiling binaries - CROSS_COMPILE = m68k-linux- + CROSS_COMPILE = m68k-linux-gnu- endif ifdef CONFIG_SUN3 diff --git a/arch/m68k/amiga/config.c b/arch/m68k/amiga/config.c index 3204f412cad..35748531327 100644 --- a/arch/m68k/amiga/config.c +++ b/arch/m68k/amiga/config.c @@ -22,9 +22,7 @@ #include <linux/vt_kern.h> #include <linux/delay.h> #include <linux/interrupt.h> -#ifdef CONFIG_ZORRO #include <linux/zorro.h> -#endif #include <asm/bootinfo.h> #include <asm/setup.h> @@ -62,55 +60,51 @@ static char s_cdtv[] __initdata = "CDTV"; static char s_cd32[] __initdata = "CD32"; static char s_draco[] __initdata = "Draco"; static char *amiga_models[] __initdata = { - [AMI_500-AMI_500] = s_a500, - [AMI_500PLUS-AMI_500] = s_a500p, - [AMI_600-AMI_500] = s_a600, - [AMI_1000-AMI_500] = s_a1000, - [AMI_1200-AMI_500] = s_a1200, - [AMI_2000-AMI_500] = s_a2000, - [AMI_2500-AMI_500] = s_a2500, - [AMI_3000-AMI_500] = s_a3000, - [AMI_3000T-AMI_500] = s_a3000t, - [AMI_3000PLUS-AMI_500] = s_a3000p, - [AMI_4000-AMI_500] = s_a4000, - [AMI_4000T-AMI_500] = s_a4000t, - [AMI_CDTV-AMI_500] = s_cdtv, - [AMI_CD32-AMI_500] = s_cd32, - [AMI_DRACO-AMI_500] = s_draco, + [AMI_500-AMI_500] = s_a500, + [AMI_500PLUS-AMI_500] = s_a500p, + [AMI_600-AMI_500] = s_a600, + [AMI_1000-AMI_500] = s_a1000, + [AMI_1200-AMI_500] = s_a1200, + [AMI_2000-AMI_500] = s_a2000, + [AMI_2500-AMI_500] = s_a2500, + [AMI_3000-AMI_500] = s_a3000, + [AMI_3000T-AMI_500] = s_a3000t, + [AMI_3000PLUS-AMI_500] = s_a3000p, + [AMI_4000-AMI_500] = s_a4000, + [AMI_4000T-AMI_500] = s_a4000t, + [AMI_CDTV-AMI_500] = s_cdtv, + [AMI_CD32-AMI_500] = s_cd32, + [AMI_DRACO-AMI_500] = s_draco, }; static char amiga_model_name[13] = "Amiga "; -extern char m68k_debug_device[]; - static void amiga_sched_init(irq_handler_t handler); /* amiga specific irq functions */ -extern void amiga_init_IRQ (void); +extern void amiga_init_IRQ(void); static void amiga_get_model(char *model); static int amiga_get_hardware_list(char *buffer); /* amiga specific timer functions */ -static unsigned long amiga_gettimeoffset (void); -static int a3000_hwclk (int, struct rtc_time *); -static int a2000_hwclk (int, struct rtc_time *); -static int amiga_set_clock_mmss (unsigned long); -static unsigned int amiga_get_ss (void); -extern void amiga_mksound( unsigned int count, unsigned int ticks ); -static void amiga_reset (void); +static unsigned long amiga_gettimeoffset(void); +static int a3000_hwclk(int, struct rtc_time *); +static int a2000_hwclk(int, struct rtc_time *); +static int amiga_set_clock_mmss(unsigned long); +static unsigned int amiga_get_ss(void); +extern void amiga_mksound(unsigned int count, unsigned int ticks); +static void amiga_reset(void); extern void amiga_init_sound(void); -static void amiga_savekmsg_init(void); static void amiga_mem_console_write(struct console *co, const char *b, unsigned int count); void amiga_serial_console_write(struct console *co, const char *s, unsigned int count); -static void amiga_debug_init(void); #ifdef CONFIG_HEARTBEAT static void amiga_heartbeat(int on); #endif static struct console amiga_console_driver = { - .name = "debug", - .flags = CON_PRINTBUFFER, - .index = -1, + .name = "debug", + .flags = CON_PRINTBUFFER, + .index = -1, }; @@ -119,24 +113,24 @@ static struct console amiga_console_driver = { */ static struct { - struct resource _ciab, _ciaa, _custom, _kickstart; + struct resource _ciab, _ciaa, _custom, _kickstart; } mb_resources = { - ._ciab = { - .name = "CIA B", .start = 0x00bfd000, .end = 0x00bfdfff - }, - ._ciaa = { - .name = "CIA A", .start = 0x00bfe000, .end = 0x00bfefff - }, - ._custom = { - .name = "Custom I/O", .start = 0x00dff000, .end = 0x00dfffff - }, - ._kickstart = { - .name = "Kickstart ROM", .start = 0x00f80000, .end = 0x00ffffff - } + ._ciab = { + .name = "CIA B", .start = 0x00bfd000, .end = 0x00bfdfff + }, + ._ciaa = { + .name = "CIA A", .start = 0x00bfe000, .end = 0x00bfefff + }, + ._custom = { + .name = "Custom I/O", .start = 0x00dff000, .end = 0x00dfffff + }, + ._kickstart = { + .name = "Kickstart ROM", .start = 0x00f80000, .end = 0x00ffffff + } }; static struct resource rtc_resource = { - .start = 0x00dc0000, .end = 0x00dcffff + .start = 0x00dc0000, .end = 0x00dcffff }; static struct resource ram_resource[NUM_MEMINFO]; @@ -148,57 +142,57 @@ static struct resource ram_resource[NUM_MEMINFO]; int amiga_parse_bootinfo(const struct bi_record *record) { - int unknown = 0; - const unsigned long *data = record->data; + int unknown = 0; + const unsigned long *data = record->data; - switch (record->tag) { + switch (record->tag) { case BI_AMIGA_MODEL: - amiga_model = *data; - break; + amiga_model = *data; + break; case BI_AMIGA_ECLOCK: - amiga_eclock = *data; - break; + amiga_eclock = *data; + break; case BI_AMIGA_CHIPSET: - amiga_chipset = *data; - break; + amiga_chipset = *data; + break; case BI_AMIGA_CHIP_SIZE: - amiga_chip_size = *(const int *)data; - break; + amiga_chip_size = *(const int *)data; + break; case BI_AMIGA_VBLANK: - amiga_vblank = *(const unsigned char *)data; - break; + amiga_vblank = *(const unsigned char *)data; + break; case BI_AMIGA_PSFREQ: - amiga_psfreq = *(const unsigned char *)data; - break; + amiga_psfreq = *(const unsigned char *)data; + break; case BI_AMIGA_AUTOCON: #ifdef CONFIG_ZORRO - if (zorro_num_autocon < ZORRO_NUM_AUTO) { - const struct ConfigDev *cd = (struct ConfigDev *)data; - struct zorro_dev *dev = &zorro_autocon[zorro_num_autocon++]; - dev->rom = cd->cd_Rom; - dev->slotaddr = cd->cd_SlotAddr; - dev->slotsize = cd->cd_SlotSize; - dev->resource.start = (unsigned long)cd->cd_BoardAddr; - dev->resource.end = dev->resource.start+cd->cd_BoardSize-1; - } else - printk("amiga_parse_bootinfo: too many AutoConfig devices\n"); + if (zorro_num_autocon < ZORRO_NUM_AUTO) { + const struct ConfigDev *cd = (struct ConfigDev *)data; + struct zorro_dev *dev = &zorro_autocon[zorro_num_autocon++]; + dev->rom = cd->cd_Rom; + dev->slotaddr = cd->cd_SlotAddr; + dev->slotsize = cd->cd_SlotSize; + dev->resource.start = (unsigned long)cd->cd_BoardAddr; + dev->resource.end = dev->resource.start + cd->cd_BoardSize - 1; + } else + printk("amiga_parse_bootinfo: too many AutoConfig devices\n"); #endif /* CONFIG_ZORRO */ - break; + break; case BI_AMIGA_SERPER: - /* serial port period: ignored here */ - break; + /* serial port period: ignored here */ + break; default: - unknown = 1; - } - return(unknown); + unknown = 1; + } + return unknown; } /* @@ -207,159 +201,159 @@ int amiga_parse_bootinfo(const struct bi_record *record) static void __init amiga_identify(void) { - /* Fill in some default values, if necessary */ - if (amiga_eclock == 0) - amiga_eclock = 709379; - - memset(&amiga_hw_present, 0, sizeof(amiga_hw_present)); - - printk("Amiga hardware found: "); - if (amiga_model >= AMI_500 && amiga_model <= AMI_DRACO) { - printk("[%s] ", amiga_models[amiga_model-AMI_500]); - strcat(amiga_model_name, amiga_models[amiga_model-AMI_500]); - } - - switch(amiga_model) { - case AMI_UNKNOWN: - goto Generic; - - case AMI_600: - case AMI_1200: - AMIGAHW_SET(A1200_IDE); - AMIGAHW_SET(PCMCIA); - case AMI_500: - case AMI_500PLUS: - case AMI_1000: - case AMI_2000: - case AMI_2500: - AMIGAHW_SET(A2000_CLK); /* Is this correct for all models? */ - goto Generic; - - case AMI_3000: - case AMI_3000T: - AMIGAHW_SET(AMBER_FF); - AMIGAHW_SET(MAGIC_REKICK); - /* fall through */ - case AMI_3000PLUS: - AMIGAHW_SET(A3000_SCSI); - AMIGAHW_SET(A3000_CLK); - AMIGAHW_SET(ZORRO3); - goto Generic; - - case AMI_4000T: - AMIGAHW_SET(A4000_SCSI); - /* fall through */ - case AMI_4000: - AMIGAHW_SET(A4000_IDE); - AMIGAHW_SET(A3000_CLK); - AMIGAHW_SET(ZORRO3); - goto Generic; - - case AMI_CDTV: - case AMI_CD32: - AMIGAHW_SET(CD_ROM); - AMIGAHW_SET(A2000_CLK); /* Is this correct? */ - goto Generic; - - Generic: - AMIGAHW_SET(AMI_VIDEO); - AMIGAHW_SET(AMI_BLITTER); - AMIGAHW_SET(AMI_AUDIO); - AMIGAHW_SET(AMI_FLOPPY); - AMIGAHW_SET(AMI_KEYBOARD); - AMIGAHW_SET(AMI_MOUSE); - AMIGAHW_SET(AMI_SERIAL); - AMIGAHW_SET(AMI_PARALLEL); - AMIGAHW_SET(CHIP_RAM); - AMIGAHW_SET(PAULA); - - switch(amiga_chipset) { - case CS_OCS: - case CS_ECS: - case CS_AGA: - switch (amiga_custom.deniseid & 0xf) { - case 0x0c: - AMIGAHW_SET(DENISE_HR); - break; - case 0x08: - AMIGAHW_SET(LISA); - break; - } - break; - default: - AMIGAHW_SET(DENISE); - break; - } - switch ((amiga_custom.vposr>>8) & 0x7f) { - case 0x00: - AMIGAHW_SET(AGNUS_PAL); - break; - case 0x10: - AMIGAHW_SET(AGNUS_NTSC); - break; - case 0x20: - case 0x21: - AMIGAHW_SET(AGNUS_HR_PAL); - break; - case 0x30: - case 0x31: - AMIGAHW_SET(AGNUS_HR_NTSC); - break; - case 0x22: - case 0x23: - AMIGAHW_SET(ALICE_PAL); - break; - case 0x32: - case 0x33: - AMIGAHW_SET(ALICE_NTSC); - break; - } - AMIGAHW_SET(ZORRO); - break; - - case AMI_DRACO: - panic("No support for Draco yet"); - - default: - panic("Unknown Amiga Model"); - } + /* Fill in some default values, if necessary */ + if (amiga_eclock == 0) + amiga_eclock = 709379; -#define AMIGAHW_ANNOUNCE(name, str) \ - if (AMIGAHW_PRESENT(name)) \ - printk(str) - - AMIGAHW_ANNOUNCE(AMI_VIDEO, "VIDEO "); - AMIGAHW_ANNOUNCE(AMI_BLITTER, "BLITTER "); - AMIGAHW_ANNOUNCE(AMBER_FF, "AMBER_FF "); - AMIGAHW_ANNOUNCE(AMI_AUDIO, "AUDIO "); - AMIGAHW_ANNOUNCE(AMI_FLOPPY, "FLOPPY "); - AMIGAHW_ANNOUNCE(A3000_SCSI, "A3000_SCSI "); - AMIGAHW_ANNOUNCE(A4000_SCSI, "A4000_SCSI "); - AMIGAHW_ANNOUNCE(A1200_IDE, "A1200_IDE "); - AMIGAHW_ANNOUNCE(A4000_IDE, "A4000_IDE "); - AMIGAHW_ANNOUNCE(CD_ROM, "CD_ROM "); - AMIGAHW_ANNOUNCE(AMI_KEYBOARD, "KEYBOARD "); - AMIGAHW_ANNOUNCE(AMI_MOUSE, "MOUSE "); - AMIGAHW_ANNOUNCE(AMI_SERIAL, "SERIAL "); - AMIGAHW_ANNOUNCE(AMI_PARALLEL, "PARALLEL "); - AMIGAHW_ANNOUNCE(A2000_CLK, "A2000_CLK "); - AMIGAHW_ANNOUNCE(A3000_CLK, "A3000_CLK "); - AMIGAHW_ANNOUNCE(CHIP_RAM, "CHIP_RAM "); - AMIGAHW_ANNOUNCE(PAULA, "PAULA "); - AMIGAHW_ANNOUNCE(DENISE, "DENISE "); - AMIGAHW_ANNOUNCE(DENISE_HR, "DENISE_HR "); - AMIGAHW_ANNOUNCE(LISA, "LISA "); - AMIGAHW_ANNOUNCE(AGNUS_PAL, "AGNUS_PAL "); - AMIGAHW_ANNOUNCE(AGNUS_NTSC, "AGNUS_NTSC "); - AMIGAHW_ANNOUNCE(AGNUS_HR_PAL, "AGNUS_HR_PAL "); - AMIGAHW_ANNOUNCE(AGNUS_HR_NTSC, "AGNUS_HR_NTSC "); - AMIGAHW_ANNOUNCE(ALICE_PAL, "ALICE_PAL "); - AMIGAHW_ANNOUNCE(ALICE_NTSC, "ALICE_NTSC "); - AMIGAHW_ANNOUNCE(MAGIC_REKICK, "MAGIC_REKICK "); - AMIGAHW_ANNOUNCE(PCMCIA, "PCMCIA "); - if (AMIGAHW_PRESENT(ZORRO)) - printk("ZORRO%s ", AMIGAHW_PRESENT(ZORRO3) ? "3" : ""); - printk("\n"); + memset(&amiga_hw_present, 0, sizeof(amiga_hw_present)); + + printk("Amiga hardware found: "); + if (amiga_model >= AMI_500 && amiga_model <= AMI_DRACO) { + printk("[%s] ", amiga_models[amiga_model-AMI_500]); + strcat(amiga_model_name, amiga_models[amiga_model-AMI_500]); + } + + switch (amiga_model) { + case AMI_UNKNOWN: + goto Generic; + + case AMI_600: + case AMI_1200: + AMIGAHW_SET(A1200_IDE); + AMIGAHW_SET(PCMCIA); + case AMI_500: + case AMI_500PLUS: + case AMI_1000: + case AMI_2000: + case AMI_2500: + AMIGAHW_SET(A2000_CLK); /* Is this correct for all models? */ + goto Generic; + + case AMI_3000: + case AMI_3000T: + AMIGAHW_SET(AMBER_FF); + AMIGAHW_SET(MAGIC_REKICK); + /* fall through */ + case AMI_3000PLUS: + AMIGAHW_SET(A3000_SCSI); + AMIGAHW_SET(A3000_CLK); + AMIGAHW_SET(ZORRO3); + goto Generic; + + case AMI_4000T: + AMIGAHW_SET(A4000_SCSI); + /* fall through */ + case AMI_4000: + AMIGAHW_SET(A4000_IDE); + AMIGAHW_SET(A3000_CLK); + AMIGAHW_SET(ZORRO3); + goto Generic; + + case AMI_CDTV: + case AMI_CD32: + AMIGAHW_SET(CD_ROM); + AMIGAHW_SET(A2000_CLK); /* Is this correct? */ + goto Generic; + + Generic: + AMIGAHW_SET(AMI_VIDEO); + AMIGAHW_SET(AMI_BLITTER); + AMIGAHW_SET(AMI_AUDIO); + AMIGAHW_SET(AMI_FLOPPY); + AMIGAHW_SET(AMI_KEYBOARD); + AMIGAHW_SET(AMI_MOUSE); + AMIGAHW_SET(AMI_SERIAL); + AMIGAHW_SET(AMI_PARALLEL); + AMIGAHW_SET(CHIP_RAM); + AMIGAHW_SET(PAULA); + + switch (amiga_chipset) { + case CS_OCS: + case CS_ECS: + case CS_AGA: + switch (amiga_custom.deniseid & 0xf) { + case 0x0c: + AMIGAHW_SET(DENISE_HR); + break; + case 0x08: + AMIGAHW_SET(LISA); + break; + } + break; + default: + AMIGAHW_SET(DENISE); + break; + } + switch ((amiga_custom.vposr>>8) & 0x7f) { + case 0x00: + AMIGAHW_SET(AGNUS_PAL); + break; + case 0x10: + AMIGAHW_SET(AGNUS_NTSC); + break; + case 0x20: + case 0x21: + AMIGAHW_SET(AGNUS_HR_PAL); + break; + case 0x30: + case 0x31: + AMIGAHW_SET(AGNUS_HR_NTSC); + break; + case 0x22: + case 0x23: + AMIGAHW_SET(ALICE_PAL); + break; + case 0x32: + case 0x33: + AMIGAHW_SET(ALICE_NTSC); + break; + } + AMIGAHW_SET(ZORRO); + break; + + case AMI_DRACO: + panic("No support for Draco yet"); + + default: + panic("Unknown Amiga Model"); + } + +#define AMIGAHW_ANNOUNCE(name, str) \ + if (AMIGAHW_PRESENT(name)) \ + printk(str) + + AMIGAHW_ANNOUNCE(AMI_VIDEO, "VIDEO "); + AMIGAHW_ANNOUNCE(AMI_BLITTER, "BLITTER "); + AMIGAHW_ANNOUNCE(AMBER_FF, "AMBER_FF "); + AMIGAHW_ANNOUNCE(AMI_AUDIO, "AUDIO "); + AMIGAHW_ANNOUNCE(AMI_FLOPPY, "FLOPPY "); + AMIGAHW_ANNOUNCE(A3000_SCSI, "A3000_SCSI "); + AMIGAHW_ANNOUNCE(A4000_SCSI, "A4000_SCSI "); + AMIGAHW_ANNOUNCE(A1200_IDE, "A1200_IDE "); + AMIGAHW_ANNOUNCE(A4000_IDE, "A4000_IDE "); + AMIGAHW_ANNOUNCE(CD_ROM, "CD_ROM "); + AMIGAHW_ANNOUNCE(AMI_KEYBOARD, "KEYBOARD "); + AMIGAHW_ANNOUNCE(AMI_MOUSE, "MOUSE "); + AMIGAHW_ANNOUNCE(AMI_SERIAL, "SERIAL "); + AMIGAHW_ANNOUNCE(AMI_PARALLEL, "PARALLEL "); + AMIGAHW_ANNOUNCE(A2000_CLK, "A2000_CLK "); + AMIGAHW_ANNOUNCE(A3000_CLK, "A3000_CLK "); + AMIGAHW_ANNOUNCE(CHIP_RAM, "CHIP_RAM "); + AMIGAHW_ANNOUNCE(PAULA, "PAULA "); + AMIGAHW_ANNOUNCE(DENISE, "DENISE "); + AMIGAHW_ANNOUNCE(DENISE_HR, "DENISE_HR "); + AMIGAHW_ANNOUNCE(LISA, "LISA "); + AMIGAHW_ANNOUNCE(AGNUS_PAL, "AGNUS_PAL "); + AMIGAHW_ANNOUNCE(AGNUS_NTSC, "AGNUS_NTSC "); + AMIGAHW_ANNOUNCE(AGNUS_HR_PAL, "AGNUS_HR_PAL "); + AMIGAHW_ANNOUNCE(AGNUS_HR_NTSC, "AGNUS_HR_NTSC "); + AMIGAHW_ANNOUNCE(ALICE_PAL, "ALICE_PAL "); + AMIGAHW_ANNOUNCE(ALICE_NTSC, "ALICE_NTSC "); + AMIGAHW_ANNOUNCE(MAGIC_REKICK, "MAGIC_REKICK "); + AMIGAHW_ANNOUNCE(PCMCIA, "PCMCIA "); + if (AMIGAHW_PRESENT(ZORRO)) + printk("ZORRO%s ", AMIGAHW_PRESENT(ZORRO3) ? "3" : ""); + printk("\n"); #undef AMIGAHW_ANNOUNCE } @@ -370,119 +364,105 @@ static void __init amiga_identify(void) void __init config_amiga(void) { - int i; - - amiga_debug_init(); - amiga_identify(); - - /* Yuk, we don't have PCI memory */ - iomem_resource.name = "Memory"; - for (i = 0; i < 4; i++) - request_resource(&iomem_resource, &((struct resource *)&mb_resources)[i]); - - mach_sched_init = amiga_sched_init; - mach_init_IRQ = amiga_init_IRQ; - mach_get_model = amiga_get_model; - mach_get_hardware_list = amiga_get_hardware_list; - mach_gettimeoffset = amiga_gettimeoffset; - if (AMIGAHW_PRESENT(A3000_CLK)){ - mach_hwclk = a3000_hwclk; - rtc_resource.name = "A3000 RTC"; - request_resource(&iomem_resource, &rtc_resource); - } - else{ /* if (AMIGAHW_PRESENT(A2000_CLK)) */ - mach_hwclk = a2000_hwclk; - rtc_resource.name = "A2000 RTC"; - request_resource(&iomem_resource, &rtc_resource); - } - - mach_max_dma_address = 0xffffffff; /* - * default MAX_DMA=0xffffffff - * on all machines. If we don't - * do so, the SCSI code will not - * be able to allocate any mem - * for transfers, unless we are - * dealing with a Z2 mem only - * system. /Jes - */ - - mach_set_clock_mmss = amiga_set_clock_mmss; - mach_get_ss = amiga_get_ss; - mach_reset = amiga_reset; + int i; + + amiga_identify(); + + /* Yuk, we don't have PCI memory */ + iomem_resource.name = "Memory"; + for (i = 0; i < 4; i++) + request_resource(&iomem_resource, &((struct resource *)&mb_resources)[i]); + + mach_sched_init = amiga_sched_init; + mach_init_IRQ = amiga_init_IRQ; + mach_get_model = amiga_get_model; + mach_get_hardware_list = amiga_get_hardware_list; + mach_gettimeoffset = amiga_gettimeoffset; + if (AMIGAHW_PRESENT(A3000_CLK)) { + mach_hwclk = a3000_hwclk; + rtc_resource.name = "A3000 RTC"; + request_resource(&iomem_resource, &rtc_resource); + } else /* if (AMIGAHW_PRESENT(A2000_CLK)) */ { + mach_hwclk = a2000_hwclk; + rtc_resource.name = "A2000 RTC"; + request_resource(&iomem_resource, &rtc_resource); + } + + /* + * default MAX_DMA=0xffffffff on all machines. If we don't do so, the SCSI + * code will not be able to allocate any mem for transfers, unless we are + * dealing with a Z2 mem only system. /Jes + */ + mach_max_dma_address = 0xffffffff; + + mach_set_clock_mmss = amiga_set_clock_mmss; + mach_get_ss = amiga_get_ss; + mach_reset = amiga_reset; #if defined(CONFIG_INPUT_M68K_BEEP) || defined(CONFIG_INPUT_M68K_BEEP_MODULE) - mach_beep = amiga_mksound; + mach_beep = amiga_mksound; #endif #ifdef CONFIG_HEARTBEAT - mach_heartbeat = amiga_heartbeat; + mach_heartbeat = amiga_heartbeat; #endif - /* Fill in the clock values (based on the 700 kHz E-Clock) */ - amiga_masterclock = 40*amiga_eclock; /* 28 MHz */ - amiga_colorclock = 5*amiga_eclock; /* 3.5 MHz */ - - /* clear all DMA bits */ - amiga_custom.dmacon = DMAF_ALL; - /* ensure that the DMA master bit is set */ - amiga_custom.dmacon = DMAF_SETCLR | DMAF_MASTER; - - /* don't use Z2 RAM as system memory on Z3 capable machines */ - if (AMIGAHW_PRESENT(ZORRO3)) { - int i, j; - u32 disabled_z2mem = 0; - for (i = 0; i < m68k_num_memory; i++) - if (m68k_memory[i].addr < 16*1024*1024) { - if (i == 0) { - /* don't cut off the branch we're sitting on */ - printk("Warning: kernel runs in Zorro II memory\n"); - continue; + /* Fill in the clock values (based on the 700 kHz E-Clock) */ + amiga_masterclock = 40*amiga_eclock; /* 28 MHz */ + amiga_colorclock = 5*amiga_eclock; /* 3.5 MHz */ + + /* clear all DMA bits */ + amiga_custom.dmacon = DMAF_ALL; + /* ensure that the DMA master bit is set */ + amiga_custom.dmacon = DMAF_SETCLR | DMAF_MASTER; + + /* don't use Z2 RAM as system memory on Z3 capable machines */ + if (AMIGAHW_PRESENT(ZORRO3)) { + int i, j; + u32 disabled_z2mem = 0; + + for (i = 0; i < m68k_num_memory; i++) { + if (m68k_memory[i].addr < 16*1024*1024) { + if (i == 0) { + /* don't cut off the branch we're sitting on */ + printk("Warning: kernel runs in Zorro II memory\n"); + continue; + } + disabled_z2mem += m68k_memory[i].size; + m68k_num_memory--; + for (j = i; j < m68k_num_memory; j++) + m68k_memory[j] = m68k_memory[j+1]; + i--; + } + } + if (disabled_z2mem) + printk("%dK of Zorro II memory will not be used as system memory\n", + disabled_z2mem>>10); } - disabled_z2mem += m68k_memory[i].size; - m68k_num_memory--; - for (j = i; j < m68k_num_memory; j++) - m68k_memory[j] = m68k_memory[j+1]; - i--; - } - if (disabled_z2mem) - printk("%dK of Zorro II memory will not be used as system memory\n", - disabled_z2mem>>10); - } - - /* request all RAM */ - for (i = 0; i < m68k_num_memory; i++) { - ram_resource[i].name = - (m68k_memory[i].addr >= 0x01000000) ? "32-bit Fast RAM" : - (m68k_memory[i].addr < 0x00c00000) ? "16-bit Fast RAM" : - "16-bit Slow RAM"; - ram_resource[i].start = m68k_memory[i].addr; - ram_resource[i].end = m68k_memory[i].addr+m68k_memory[i].size-1; - request_resource(&iomem_resource, &ram_resource[i]); - } - - /* initialize chipram allocator */ - amiga_chip_init (); - - /* debugging using chipram */ - if (!strcmp( m68k_debug_device, "mem" )){ - if (!AMIGAHW_PRESENT(CHIP_RAM)) - printk("Warning: no chipram present for debugging\n"); - else { - amiga_savekmsg_init(); - amiga_console_driver.write = amiga_mem_console_write; - register_console(&amiga_console_driver); - } - } - - /* our beloved beeper */ - if (AMIGAHW_PRESENT(AMI_AUDIO)) - amiga_init_sound(); - - /* - * if it is an A3000, set the magic bit that forces - * a hard rekick - */ - if (AMIGAHW_PRESENT(MAGIC_REKICK)) - *(unsigned char *)ZTWO_VADDR(0xde0002) |= 0x80; + + /* request all RAM */ + for (i = 0; i < m68k_num_memory; i++) { + ram_resource[i].name = + (m68k_memory[i].addr >= 0x01000000) ? "32-bit Fast RAM" : + (m68k_memory[i].addr < 0x00c00000) ? "16-bit Fast RAM" : + "16-bit Slow RAM"; + ram_resource[i].start = m68k_memory[i].addr; + ram_resource[i].end = m68k_memory[i].addr+m68k_memory[i].size-1; + request_resource(&iomem_resource, &ram_resource[i]); + } + + /* initialize chipram allocator */ + amiga_chip_init(); + + /* our beloved beeper */ + if (AMIGAHW_PRESENT(AMI_AUDIO)) + amiga_init_sound(); + + /* + * if it is an A3000, set the magic bit that forces + * a hard rekick + */ + if (AMIGAHW_PRESENT(MAGIC_REKICK)) + *(unsigned char *)ZTWO_VADDR(0xde0002) |= 0x80; } static unsigned short jiffy_ticks; @@ -490,12 +470,12 @@ static unsigned short jiffy_ticks; static void __init amiga_sched_init(irq_handler_t timer_routine) { static struct resource sched_res = { - .name = "timer", .start = 0x00bfd400, .end = 0x00bfd5ff, + .name = "timer", .start = 0x00bfd400, .end = 0x00bfd5ff, }; jiffy_ticks = (amiga_eclock+HZ/2)/HZ; if (request_resource(&mb_resources._ciab, &sched_res)) - printk("Cannot allocate ciab.ta{lo,hi}\n"); + printk("Cannot allocate ciab.ta{lo,hi}\n"); ciab.cra &= 0xC0; /* turn off timer A, continuous mode, from Eclk */ ciab.talo = jiffy_ticks % 256; ciab.tahi = jiffy_ticks / 256; @@ -513,7 +493,7 @@ static void __init amiga_sched_init(irq_handler_t timer_routine) #define TICK_SIZE 10000 /* This is always executed with interrupts disabled. */ -static unsigned long amiga_gettimeoffset (void) +static unsigned long amiga_gettimeoffset(void) { unsigned short hi, lo, hi2; unsigned long ticks, offset = 0; @@ -585,15 +565,15 @@ static int a2000_hwclk(int op, struct rtc_time *t) tod_2000.cntrl1 = TOD2000_CNTRL1_HOLD; - while ((tod_2000.cntrl1 & TOD2000_CNTRL1_BUSY) && cnt--) - { - tod_2000.cntrl1 &= ~TOD2000_CNTRL1_HOLD; - udelay(70); - tod_2000.cntrl1 |= TOD2000_CNTRL1_HOLD; + while ((tod_2000.cntrl1 & TOD2000_CNTRL1_BUSY) && cnt--) { + tod_2000.cntrl1 &= ~TOD2000_CNTRL1_HOLD; + udelay(70); + tod_2000.cntrl1 |= TOD2000_CNTRL1_HOLD; } if (!cnt) - printk(KERN_INFO "hwclk: timed out waiting for RTC (0x%x)\n", tod_2000.cntrl1); + printk(KERN_INFO "hwclk: timed out waiting for RTC (0x%x)\n", + tod_2000.cntrl1); if (!op) { /* read */ t->tm_sec = tod_2000.second1 * 10 + tod_2000.second2; @@ -606,7 +586,7 @@ static int a2000_hwclk(int op, struct rtc_time *t) if (t->tm_year <= 69) t->tm_year += 100; - if (!(tod_2000.cntrl3 & TOD2000_CNTRL3_24HMODE)){ + if (!(tod_2000.cntrl3 & TOD2000_CNTRL3_24HMODE)) { if (!(tod_2000.hour1 & TOD2000_HOUR1_PM) && t->tm_hour == 12) t->tm_hour = 0; else if ((tod_2000.hour1 & TOD2000_HOUR1_PM) && t->tm_hour != 12) @@ -642,7 +622,7 @@ static int a2000_hwclk(int op, struct rtc_time *t) return 0; } -static int amiga_set_clock_mmss (unsigned long nowtime) +static int amiga_set_clock_mmss(unsigned long nowtime) { short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60; @@ -660,8 +640,7 @@ static int amiga_set_clock_mmss (unsigned long nowtime) tod_2000.cntrl1 |= TOD2000_CNTRL1_HOLD; - while ((tod_2000.cntrl1 & TOD2000_CNTRL1_BUSY) && cnt--) - { + while ((tod_2000.cntrl1 & TOD2000_CNTRL1_BUSY) && cnt--) { tod_2000.cntrl1 &= ~TOD2000_CNTRL1_HOLD; udelay(70); tod_2000.cntrl1 |= TOD2000_CNTRL1_HOLD; @@ -681,7 +660,7 @@ static int amiga_set_clock_mmss (unsigned long nowtime) return 0; } -static unsigned int amiga_get_ss( void ) +static unsigned int amiga_get_ss(void) { unsigned int s; @@ -695,71 +674,72 @@ static unsigned int amiga_get_ss( void ) return s; } -static NORET_TYPE void amiga_reset( void ) +static NORET_TYPE void amiga_reset(void) ATTRIB_NORET; -static void amiga_reset (void) +static void amiga_reset(void) { - unsigned long jmp_addr040 = virt_to_phys(&&jmp_addr_label040); - unsigned long jmp_addr = virt_to_phys(&&jmp_addr_label); - - local_irq_disable(); - if (CPU_IS_040_OR_060) - /* Setup transparent translation registers for mapping - * of 16 MB kernel segment before disabling translation - */ - __asm__ __volatile__ - ("movel %0,%/d0\n\t" - "andl #0xff000000,%/d0\n\t" - "orw #0xe020,%/d0\n\t" /* map 16 MB, enable, cacheable */ - ".chip 68040\n\t" - "movec %%d0,%%itt0\n\t" - "movec %%d0,%%dtt0\n\t" - ".chip 68k\n\t" - "jmp %0@\n\t" - : /* no outputs */ - : "a" (jmp_addr040)); - else - /* for 680[23]0, just disable translation and jump to the physical - * address of the label - */ - __asm__ __volatile__ - ("pmove %/tc,%@\n\t" - "bclr #7,%@\n\t" - "pmove %@,%/tc\n\t" - "jmp %0@\n\t" - : /* no outputs */ - : "a" (jmp_addr)); - jmp_addr_label040: - /* disable translation on '040 now */ - __asm__ __volatile__ - ("moveq #0,%/d0\n\t" - ".chip 68040\n\t" - "movec %%d0,%%tc\n\t" /* disable MMU */ - ".chip 68k\n\t" - : /* no outputs */ - : /* no inputs */ - : "d0"); - - jmp_addr_label: - /* pickup reset address from AmigaOS ROM, reset devices and jump - * to reset address - */ - __asm__ __volatile__ - ("movew #0x2700,%/sr\n\t" - "leal 0x01000000,%/a0\n\t" - "subl %/a0@(-0x14),%/a0\n\t" - "movel %/a0@(4),%/a0\n\t" - "subql #2,%/a0\n\t" - "bra 1f\n\t" - /* align on a longword boundary */ - __ALIGN_STR "\n" - "1:\n\t" - "reset\n\t" - "jmp %/a0@" : /* Just that gcc scans it for % escapes */ ); - - for (;;); - + unsigned long jmp_addr040 = virt_to_phys(&&jmp_addr_label040); + unsigned long jmp_addr = virt_to_phys(&&jmp_addr_label); + + local_irq_disable(); + if (CPU_IS_040_OR_060) + /* Setup transparent translation registers for mapping + * of 16 MB kernel segment before disabling translation + */ + asm volatile ("\n" + " move.l %0,%%d0\n" + " and.l #0xff000000,%%d0\n" + " or.w #0xe020,%%d0\n" /* map 16 MB, enable, cacheable */ + " .chip 68040\n" + " movec %%d0,%%itt0\n" + " movec %%d0,%%dtt0\n" + " .chip 68k\n" + " jmp %0@\n" + : /* no outputs */ + : "a" (jmp_addr040) + : "d0"); + else + /* for 680[23]0, just disable translation and jump to the physical + * address of the label + */ + asm volatile ("\n" + " pmove %%tc,%@\n" + " bclr #7,%@\n" + " pmove %@,%%tc\n" + " jmp %0@\n" + : /* no outputs */ + : "a" (jmp_addr)); +jmp_addr_label040: + /* disable translation on '040 now */ + asm volatile ("\n" + " moveq #0,%%d0\n" + " .chip 68040\n" + " movec %%d0,%%tc\n" /* disable MMU */ + " .chip 68k\n" + : /* no outputs */ + : /* no inputs */ + : "d0"); + + jmp_addr_label: + /* pickup reset address from AmigaOS ROM, reset devices and jump + * to reset address + */ + asm volatile ("\n" + " move.w #0x2700,%sr\n" + " lea 0x01000000,%a0\n" + " sub.l %a0@(-0x14),%a0\n" + " move.l %a0@(4),%a0\n" + " subq.l #2,%a0\n" + " jra 1f\n" + /* align on a longword boundary */ + " " __ALIGN_STR "\n" + "1:\n" + " reset\n" + " jmp %a0@"); + + for (;;) + ; } @@ -773,11 +753,11 @@ static void amiga_reset (void) #define SAVEKMSG_MAGIC2 0x4B4D5347 /* 'KMSG' */ struct savekmsg { - unsigned long magic1; /* SAVEKMSG_MAGIC1 */ - unsigned long magic2; /* SAVEKMSG_MAGIC2 */ - unsigned long magicptr; /* address of magic1 */ - unsigned long size; - char data[0]; + unsigned long magic1; /* SAVEKMSG_MAGIC1 */ + unsigned long magic2; /* SAVEKMSG_MAGIC2 */ + unsigned long magicptr; /* address of magic1 */ + unsigned long size; + char data[0]; }; static struct savekmsg *savekmsg; @@ -785,113 +765,132 @@ static struct savekmsg *savekmsg; static void amiga_mem_console_write(struct console *co, const char *s, unsigned int count) { - if (savekmsg->size+count <= SAVEKMSG_MAXMEM-sizeof(struct savekmsg)) { - memcpy(savekmsg->data+savekmsg->size, s, count); - savekmsg->size += count; - } + if (savekmsg->size + count <= SAVEKMSG_MAXMEM-sizeof(struct savekmsg)) { + memcpy(savekmsg->data + savekmsg->size, s, count); + savekmsg->size += count; + } } -static void amiga_savekmsg_init(void) +static int __init amiga_savekmsg_setup(char *arg) { - static struct resource debug_res = { .name = "Debug" }; + static struct resource debug_res = { .name = "Debug" }; + + if (!MACH_IS_AMIGA || strcmp(arg, "mem")) + goto done; + + if (!AMIGAHW_PRESENT(CHIP_RAM)) { + printk("Warning: no chipram present for debugging\n"); + goto done; + } - savekmsg = amiga_chip_alloc_res(SAVEKMSG_MAXMEM, &debug_res); - savekmsg->magic1 = SAVEKMSG_MAGIC1; - savekmsg->magic2 = SAVEKMSG_MAGIC2; - savekmsg->magicptr = ZTWO_PADDR(savekmsg); - savekmsg->size = 0; + savekmsg = amiga_chip_alloc_res(SAVEKMSG_MAXMEM, &debug_res); + savekmsg->magic1 = SAVEKMSG_MAGIC1; + savekmsg->magic2 = SAVEKMSG_MAGIC2; + savekmsg->magicptr = ZTWO_PADDR(savekmsg); + savekmsg->size = 0; + + amiga_console_driver.write = amiga_mem_console_write; + register_console(&amiga_console_driver); + +done: + return 0; } +early_param("debug", amiga_savekmsg_setup); + static void amiga_serial_putc(char c) { - amiga_custom.serdat = (unsigned char)c | 0x100; - while (!(amiga_custom.serdatr & 0x2000)) - ; + amiga_custom.serdat = (unsigned char)c | 0x100; + while (!(amiga_custom.serdatr & 0x2000)) + ; } void amiga_serial_console_write(struct console *co, const char *s, - unsigned int count) + unsigned int count) { - while (count--) { - if (*s == '\n') - amiga_serial_putc('\r'); - amiga_serial_putc(*s++); - } + while (count--) { + if (*s == '\n') + amiga_serial_putc('\r'); + amiga_serial_putc(*s++); + } } #ifdef CONFIG_SERIAL_CONSOLE void amiga_serial_puts(const char *s) { - amiga_serial_console_write(NULL, s, strlen(s)); + amiga_serial_console_write(NULL, s, strlen(s)); } int amiga_serial_console_wait_key(struct console *co) { - int ch; - - while (!(amiga_custom.intreqr & IF_RBF)) - barrier(); - ch = amiga_custom.serdatr & 0xff; - /* clear the interrupt, so that another character can be read */ - amiga_custom.intreq = IF_RBF; - return ch; + int ch; + + while (!(amiga_custom.intreqr & IF_RBF)) + barrier(); + ch = amiga_custom.serdatr & 0xff; + /* clear the interrupt, so that another character can be read */ + amiga_custom.intreq = IF_RBF; + return ch; } void amiga_serial_gets(struct console *co, char *s, int len) { - int ch, cnt = 0; - - while (1) { - ch = amiga_serial_console_wait_key(co); - - /* Check for backspace. */ - if (ch == 8 || ch == 127) { - if (cnt == 0) { - amiga_serial_putc('\007'); - continue; - } - cnt--; - amiga_serial_puts("\010 \010"); - continue; - } + int ch, cnt = 0; + + while (1) { + ch = amiga_serial_console_wait_key(co); + + /* Check for backspace. */ + if (ch == 8 || ch == 127) { + if (cnt == 0) { + amiga_serial_putc('\007'); + continue; + } + cnt--; + amiga_serial_puts("\010 \010"); + continue; + } - /* Check for enter. */ - if (ch == 10 || ch == 13) - break; + /* Check for enter. */ + if (ch == 10 || ch == 13) + break; - /* See if line is too long. */ - if (cnt >= len + 1) { - amiga_serial_putc(7); - cnt--; - continue; - } + /* See if line is too long. */ + if (cnt >= len + 1) { + amiga_serial_putc(7); + cnt--; + continue; + } - /* Store and echo character. */ - s[cnt++] = ch; - amiga_serial_putc(ch); - } - /* Print enter. */ - amiga_serial_puts("\r\n"); - s[cnt] = 0; + /* Store and echo character. */ + s[cnt++] = ch; + amiga_serial_putc(ch); + } + /* Print enter. */ + amiga_serial_puts("\r\n"); + s[cnt] = 0; } #endif -static void __init amiga_debug_init(void) +static int __init amiga_debug_setup(char *arg) { - if (!strcmp( m68k_debug_device, "ser" )) { + if (MACH_IS_AMIGA && !strcmp(arg, "ser")) { /* no initialization required (?) */ amiga_console_driver.write = amiga_serial_console_write; register_console(&amiga_console_driver); } + return 0; } +early_param("debug", amiga_debug_setup); + #ifdef CONFIG_HEARTBEAT static void amiga_heartbeat(int on) { - if (on) - ciaa.pra &= ~2; - else - ciaa.pra |= 2; + if (on) + ciaa.pra &= ~2; + else + ciaa.pra |= 2; } #endif @@ -901,81 +900,81 @@ static void amiga_heartbeat(int on) static void amiga_get_model(char *model) { - strcpy(model, amiga_model_name); + strcpy(model, amiga_model_name); } static int amiga_get_hardware_list(char *buffer) { - int len = 0; - - if (AMIGAHW_PRESENT(CHIP_RAM)) - len += sprintf(buffer+len, "Chip RAM:\t%ldK\n", amiga_chip_size>>10); - len += sprintf(buffer+len, "PS Freq:\t%dHz\nEClock Freq:\t%ldHz\n", - amiga_psfreq, amiga_eclock); - if (AMIGAHW_PRESENT(AMI_VIDEO)) { - char *type; - switch(amiga_chipset) { - case CS_OCS: - type = "OCS"; - break; - case CS_ECS: - type = "ECS"; - break; - case CS_AGA: - type = "AGA"; - break; - default: - type = "Old or Unknown"; - break; + int len = 0; + + if (AMIGAHW_PRESENT(CHIP_RAM)) + len += sprintf(buffer+len, "Chip RAM:\t%ldK\n", amiga_chip_size>>10); + len += sprintf(buffer+len, "PS Freq:\t%dHz\nEClock Freq:\t%ldHz\n", + amiga_psfreq, amiga_eclock); + if (AMIGAHW_PRESENT(AMI_VIDEO)) { + char *type; + switch (amiga_chipset) { + case CS_OCS: + type = "OCS"; + break; + case CS_ECS: + type = "ECS"; + break; + case CS_AGA: + type = "AGA"; + break; + default: + type = "Old or Unknown"; + break; + } + len += sprintf(buffer+len, "Graphics:\t%s\n", type); } - len += sprintf(buffer+len, "Graphics:\t%s\n", type); - } #define AMIGAHW_ANNOUNCE(name, str) \ - if (AMIGAHW_PRESENT(name)) \ - len += sprintf (buffer+len, "\t%s\n", str) - - len += sprintf (buffer + len, "Detected hardware:\n"); - - AMIGAHW_ANNOUNCE(AMI_VIDEO, "Amiga Video"); - AMIGAHW_ANNOUNCE(AMI_BLITTER, "Blitter"); - AMIGAHW_ANNOUNCE(AMBER_FF, "Amber Flicker Fixer"); - AMIGAHW_ANNOUNCE(AMI_AUDIO, "Amiga Audio"); - AMIGAHW_ANNOUNCE(AMI_FLOPPY, "Floppy Controller"); - AMIGAHW_ANNOUNCE(A3000_SCSI, "SCSI Controller WD33C93 (A3000 style)"); - AMIGAHW_ANNOUNCE(A4000_SCSI, "SCSI Controller NCR53C710 (A4000T style)"); - AMIGAHW_ANNOUNCE(A1200_IDE, "IDE Interface (A1200 style)"); - AMIGAHW_ANNOUNCE(A4000_IDE, "IDE Interface (A4000 style)"); - AMIGAHW_ANNOUNCE(CD_ROM, "Internal CD ROM drive"); - AMIGAHW_ANNOUNCE(AMI_KEYBOARD, "Keyboard"); - AMIGAHW_ANNOUNCE(AMI_MOUSE, "Mouse Port"); - AMIGAHW_ANNOUNCE(AMI_SERIAL, "Serial Port"); - AMIGAHW_ANNOUNCE(AMI_PARALLEL, "Parallel Port"); - AMIGAHW_ANNOUNCE(A2000_CLK, "Hardware Clock (A2000 style)"); - AMIGAHW_ANNOUNCE(A3000_CLK, "Hardware Clock (A3000 style)"); - AMIGAHW_ANNOUNCE(CHIP_RAM, "Chip RAM"); - AMIGAHW_ANNOUNCE(PAULA, "Paula 8364"); - AMIGAHW_ANNOUNCE(DENISE, "Denise 8362"); - AMIGAHW_ANNOUNCE(DENISE_HR, "Denise 8373"); - AMIGAHW_ANNOUNCE(LISA, "Lisa 8375"); - AMIGAHW_ANNOUNCE(AGNUS_PAL, "Normal/Fat PAL Agnus 8367/8371"); - AMIGAHW_ANNOUNCE(AGNUS_NTSC, "Normal/Fat NTSC Agnus 8361/8370"); - AMIGAHW_ANNOUNCE(AGNUS_HR_PAL, "Fat Hires PAL Agnus 8372"); - AMIGAHW_ANNOUNCE(AGNUS_HR_NTSC, "Fat Hires NTSC Agnus 8372"); - AMIGAHW_ANNOUNCE(ALICE_PAL, "PAL Alice 8374"); - AMIGAHW_ANNOUNCE(ALICE_NTSC, "NTSC Alice 8374"); - AMIGAHW_ANNOUNCE(MAGIC_REKICK, "Magic Hard Rekick"); - AMIGAHW_ANNOUNCE(PCMCIA, "PCMCIA Slot"); + if (AMIGAHW_PRESENT(name)) \ + len += sprintf (buffer+len, "\t%s\n", str) + + len += sprintf (buffer + len, "Detected hardware:\n"); + + AMIGAHW_ANNOUNCE(AMI_VIDEO, "Amiga Video"); + AMIGAHW_ANNOUNCE(AMI_BLITTER, "Blitter"); + AMIGAHW_ANNOUNCE(AMBER_FF, "Amber Flicker Fixer"); + AMIGAHW_ANNOUNCE(AMI_AUDIO, "Amiga Audio"); + AMIGAHW_ANNOUNCE(AMI_FLOPPY, "Floppy Controller"); + AMIGAHW_ANNOUNCE(A3000_SCSI, "SCSI Controller WD33C93 (A3000 style)"); + AMIGAHW_ANNOUNCE(A4000_SCSI, "SCSI Controller NCR53C710 (A4000T style)"); + AMIGAHW_ANNOUNCE(A1200_IDE, "IDE Interface (A1200 style)"); + AMIGAHW_ANNOUNCE(A4000_IDE, "IDE Interface (A4000 style)"); + AMIGAHW_ANNOUNCE(CD_ROM, "Internal CD ROM drive"); + AMIGAHW_ANNOUNCE(AMI_KEYBOARD, "Keyboard"); + AMIGAHW_ANNOUNCE(AMI_MOUSE, "Mouse Port"); + AMIGAHW_ANNOUNCE(AMI_SERIAL, "Serial Port"); + AMIGAHW_ANNOUNCE(AMI_PARALLEL, "Parallel Port"); + AMIGAHW_ANNOUNCE(A2000_CLK, "Hardware Clock (A2000 style)"); + AMIGAHW_ANNOUNCE(A3000_CLK, "Hardware Clock (A3000 style)"); + AMIGAHW_ANNOUNCE(CHIP_RAM, "Chip RAM"); + AMIGAHW_ANNOUNCE(PAULA, "Paula 8364"); + AMIGAHW_ANNOUNCE(DENISE, "Denise 8362"); + AMIGAHW_ANNOUNCE(DENISE_HR, "Denise 8373"); + AMIGAHW_ANNOUNCE(LISA, "Lisa 8375"); + AMIGAHW_ANNOUNCE(AGNUS_PAL, "Normal/Fat PAL Agnus 8367/8371"); + AMIGAHW_ANNOUNCE(AGNUS_NTSC, "Normal/Fat NTSC Agnus 8361/8370"); + AMIGAHW_ANNOUNCE(AGNUS_HR_PAL, "Fat Hires PAL Agnus 8372"); + AMIGAHW_ANNOUNCE(AGNUS_HR_NTSC, "Fat Hires NTSC Agnus 8372"); + AMIGAHW_ANNOUNCE(ALICE_PAL, "PAL Alice 8374"); + AMIGAHW_ANNOUNCE(ALICE_NTSC, "NTSC Alice 8374"); + AMIGAHW_ANNOUNCE(MAGIC_REKICK, "Magic Hard Rekick"); + AMIGAHW_ANNOUNCE(PCMCIA, "PCMCIA Slot"); #ifdef CONFIG_ZORRO - if (AMIGAHW_PRESENT(ZORRO)) - len += sprintf(buffer+len, "\tZorro II%s AutoConfig: %d Expansion " - "Device%s\n", - AMIGAHW_PRESENT(ZORRO3) ? "I" : "", - zorro_num_autocon, zorro_num_autocon == 1 ? "" : "s"); + if (AMIGAHW_PRESENT(ZORRO)) + len += sprintf(buffer+len, "\tZorro II%s AutoConfig: %d Expansion " + "Device%s\n", + AMIGAHW_PRESENT(ZORRO3) ? "I" : "", + zorro_num_autocon, zorro_num_autocon == 1 ? "" : "s"); #endif /* CONFIG_ZORRO */ #undef AMIGAHW_ANNOUNCE - return(len); + return len; } diff --git a/arch/m68k/atari/Makefile b/arch/m68k/atari/Makefile index 8cb6236b39d..2cb86191f0a 100644 --- a/arch/m68k/atari/Makefile +++ b/arch/m68k/atari/Makefile @@ -8,3 +8,4 @@ obj-y := config.o time.o debug.o ataints.o stdma.o \ ifeq ($(CONFIG_PCI),y) obj-$(CONFIG_HADES) += hades-pci.o endif +obj-$(CONFIG_ATARI_KBD_CORE) += atakeyb.o diff --git a/arch/m68k/atari/atakeyb.c b/arch/m68k/atari/atakeyb.c new file mode 100644 index 00000000000..1c29603b16b --- /dev/null +++ b/arch/m68k/atari/atakeyb.c @@ -0,0 +1,730 @@ +/* + * linux/atari/atakeyb.c + * + * Atari Keyboard driver for 680x0 Linux + * + * 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. + */ + +/* + * Atari support by Robert de Vries + * enhanced by Bjoern Brauel and Roman Hodek + */ + +#include <linux/sched.h> +#include <linux/kernel.h> +#include <linux/interrupt.h> +#include <linux/errno.h> +#include <linux/keyboard.h> +#include <linux/delay.h> +#include <linux/timer.h> +#include <linux/kd.h> +#include <linux/random.h> +#include <linux/init.h> +#include <linux/kbd_kern.h> + +#include <asm/atariints.h> +#include <asm/atarihw.h> +#include <asm/atarikb.h> +#include <asm/atari_joystick.h> +#include <asm/irq.h> + +static void atakeyb_rep(unsigned long ignore); +extern unsigned int keymap_count; + +/* Hook for MIDI serial driver */ +void (*atari_MIDI_interrupt_hook) (void); +/* Hook for mouse driver */ +void (*atari_mouse_interrupt_hook) (char *); +/* Hook for keyboard inputdev driver */ +void (*atari_input_keyboard_interrupt_hook) (unsigned char, char); +/* Hook for mouse inputdev driver */ +void (*atari_input_mouse_interrupt_hook) (char *); + +/* variables for IKBD self test: */ + +/* state: 0: off; >0: in progress; >1: 0xf1 received */ +static volatile int ikbd_self_test; +/* timestamp when last received a char */ +static volatile unsigned long self_test_last_rcv; +/* bitmap of keys reported as broken */ +static unsigned long broken_keys[128/(sizeof(unsigned long)*8)] = { 0, }; + +#define BREAK_MASK (0x80) + +/* + * ++roman: The following changes were applied manually: + * + * - The Alt (= Meta) key works in combination with Shift and + * Control, e.g. Alt+Shift+a sends Meta-A (0xc1), Alt+Control+A sends + * Meta-Ctrl-A (0x81) ... + * + * - The parentheses on the keypad send '(' and ')' with all + * modifiers (as would do e.g. keypad '+'), but they cannot be used as + * application keys (i.e. sending Esc O c). + * + * - HELP and UNDO are mapped to be F21 and F24, resp, that send the + * codes "\E[M" and "\E[P". (This is better than the old mapping to + * F11 and F12, because these codes are on Shift+F1/2 anyway.) This + * way, applications that allow their own keyboard mappings + * (e.g. tcsh, X Windows) can be configured to use them in the way + * the label suggests (providing help or undoing). + * + * - Console switching is done with Alt+Fx (consoles 1..10) and + * Shift+Alt+Fx (consoles 11..20). + * + * - The misc. special function implemented in the kernel are mapped + * to the following key combinations: + * + * ClrHome -> Home/Find + * Shift + ClrHome -> End/Select + * Shift + Up -> Page Up + * Shift + Down -> Page Down + * Alt + Help -> show system status + * Shift + Help -> show memory info + * Ctrl + Help -> show registers + * Ctrl + Alt + Del -> Reboot + * Alt + Undo -> switch to last console + * Shift + Undo -> send interrupt + * Alt + Insert -> stop/start output (same as ^S/^Q) + * Alt + Up -> Scroll back console (if implemented) + * Alt + Down -> Scroll forward console (if implemented) + * Alt + CapsLock -> NumLock + * + * ++Andreas: + * + * - Help mapped to K_HELP + * - Undo mapped to K_UNDO (= K_F246) + * - Keypad Left/Right Parenthesis mapped to new K_PPAREN[LR] + */ + +static u_short ataplain_map[NR_KEYS] __initdata = { + 0xf200, 0xf01b, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036, + 0xf037, 0xf038, 0xf039, 0xf030, 0xf02d, 0xf03d, 0xf008, 0xf009, + 0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69, + 0xfb6f, 0xfb70, 0xf05b, 0xf05d, 0xf201, 0xf702, 0xfb61, 0xfb73, + 0xfb64, 0xfb66, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c, 0xf03b, + 0xf027, 0xf060, 0xf700, 0xf05c, 0xfb7a, 0xfb78, 0xfb63, 0xfb76, + 0xfb62, 0xfb6e, 0xfb6d, 0xf02c, 0xf02e, 0xf02f, 0xf700, 0xf200, + 0xf703, 0xf020, 0xf207, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104, + 0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf200, 0xf200, 0xf114, + 0xf603, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200, + 0xf600, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf1ff, 0xf11b, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf307, + 0xf308, 0xf309, 0xf304, 0xf305, 0xf306, 0xf301, 0xf302, 0xf303, + 0xf300, 0xf310, 0xf30e, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200 +}; + +typedef enum kb_state_t { + KEYBOARD, AMOUSE, RMOUSE, JOYSTICK, CLOCK, RESYNC +} KB_STATE_T; + +#define IS_SYNC_CODE(sc) ((sc) >= 0x04 && (sc) <= 0xfb) + +typedef struct keyboard_state { + unsigned char buf[6]; + int len; + KB_STATE_T state; +} KEYBOARD_STATE; + +KEYBOARD_STATE kb_state; + +#define DEFAULT_KEYB_REP_DELAY (HZ/4) +#define DEFAULT_KEYB_REP_RATE (HZ/25) + +/* These could be settable by some ioctl() in future... */ +static unsigned int key_repeat_delay = DEFAULT_KEYB_REP_DELAY; +static unsigned int key_repeat_rate = DEFAULT_KEYB_REP_RATE; + +static unsigned char rep_scancode; +static struct timer_list atakeyb_rep_timer = { + .function = atakeyb_rep, +}; + +static void atakeyb_rep(unsigned long ignore) +{ + /* Disable keyboard for the time we call handle_scancode(), else a race + * in the keyboard tty queue may happen */ + atari_disable_irq(IRQ_MFP_ACIA); + del_timer(&atakeyb_rep_timer); + + /* A keyboard int may have come in before we disabled the irq, so + * double-check whether rep_scancode is still != 0 */ + if (rep_scancode) { + init_timer(&atakeyb_rep_timer); + atakeyb_rep_timer.expires = jiffies + key_repeat_rate; + add_timer(&atakeyb_rep_timer); + + //handle_scancode(rep_scancode, 1); + if (atari_input_keyboard_interrupt_hook) + atari_input_keyboard_interrupt_hook(rep_scancode, 1); + } + + atari_enable_irq(IRQ_MFP_ACIA); +} + + +/* ++roman: If a keyboard overrun happened, we can't tell in general how much + * bytes have been lost and in which state of the packet structure we are now. + * This usually causes keyboards bytes to be interpreted as mouse movements + * and vice versa, which is very annoying. It seems better to throw away some + * bytes (that are usually mouse bytes) than to misinterpret them. Therefor I + * introduced the RESYNC state for IKBD data. In this state, the bytes up to + * one that really looks like a key event (0x04..0xf2) or the start of a mouse + * packet (0xf8..0xfb) are thrown away, but at most 2 bytes. This at least + * speeds up the resynchronization of the event structure, even if maybe a + * mouse movement is lost. However, nothing is perfect. For bytes 0x01..0x03, + * it's really hard to decide whether they're mouse or keyboard bytes. Since + * overruns usually occur when moving the Atari mouse rapidly, they're seen as + * mouse bytes here. If this is wrong, only a make code of the keyboard gets + * lost, which isn't too bad. Loosing a break code would be disastrous, + * because then the keyboard repeat strikes... + */ + +static irqreturn_t atari_keyboard_interrupt(int irq, void *dummy) +{ + u_char acia_stat; + int scancode; + int break_flag; + +repeat: + if (acia.mid_ctrl & ACIA_IRQ) + if (atari_MIDI_interrupt_hook) + atari_MIDI_interrupt_hook(); + acia_stat = acia.key_ctrl; + /* check out if the interrupt came from this ACIA */ + if (!((acia_stat | acia.mid_ctrl) & ACIA_IRQ)) + return IRQ_HANDLED; + + if (acia_stat & ACIA_OVRN) { + /* a very fast typist or a slow system, give a warning */ + /* ...happens often if interrupts were disabled for too long */ + printk(KERN_DEBUG "Keyboard overrun\n"); + scancode = acia.key_data; + /* Turn off autorepeating in case a break code has been lost */ + del_timer(&atakeyb_rep_timer); + rep_scancode = 0; + if (ikbd_self_test) + /* During self test, don't do resyncing, just process the code */ + goto interpret_scancode; + else if (IS_SYNC_CODE(scancode)) { + /* This code seem already to be the start of a new packet or a + * single scancode */ + kb_state.state = KEYBOARD; + goto interpret_scancode; + } else { + /* Go to RESYNC state and skip this byte */ + kb_state.state = RESYNC; + kb_state.len = 1; /* skip max. 1 another byte */ + goto repeat; + } + } + + if (acia_stat & ACIA_RDRF) { + /* received a character */ + scancode = acia.key_data; /* get it or reset the ACIA, I'll get it! */ + tasklet_schedule(&keyboard_tasklet); + interpret_scancode: + switch (kb_state.state) { + case KEYBOARD: + switch (scancode) { + case 0xF7: + kb_state.state = AMOUSE; + kb_state.len = 0; + break; + + case 0xF8: + case 0xF9: + case 0xFA: + case 0xFB: + kb_state.state = RMOUSE; + kb_state.len = 1; + kb_state.buf[0] = scancode; + break; + + case 0xFC: + kb_state.state = CLOCK; + kb_state.len = 0; + break; + + case 0xFE: + case 0xFF: + kb_state.state = JOYSTICK; + kb_state.len = 1; + kb_state.buf[0] = scancode; + break; + + case 0xF1: + /* during self-test, note that 0xf1 received */ + if (ikbd_self_test) { + ++ikbd_self_test; + self_test_last_rcv = jiffies; + break; + } + /* FALL THROUGH */ + + default: + break_flag = scancode & BREAK_MASK; + scancode &= ~BREAK_MASK; + if (ikbd_self_test) { + /* Scancodes sent during the self-test stand for broken + * keys (keys being down). The code *should* be a break + * code, but nevertheless some AT keyboard interfaces send + * make codes instead. Therefore, simply ignore + * break_flag... + */ + int keyval = plain_map[scancode], keytyp; + + set_bit(scancode, broken_keys); + self_test_last_rcv = jiffies; + keyval = plain_map[scancode]; + keytyp = KTYP(keyval) - 0xf0; + keyval = KVAL(keyval); + + printk(KERN_WARNING "Key with scancode %d ", scancode); + if (keytyp == KT_LATIN || keytyp == KT_LETTER) { + if (keyval < ' ') + printk("('^%c') ", keyval + '@'); + else + printk("('%c') ", keyval); + } + printk("is broken -- will be ignored.\n"); + break; + } else if (test_bit(scancode, broken_keys)) + break; + +#if 0 // FIXME; hangs at boot + if (break_flag) { + del_timer(&atakeyb_rep_timer); + rep_scancode = 0; + } else { + del_timer(&atakeyb_rep_timer); + rep_scancode = scancode; + atakeyb_rep_timer.expires = jiffies + key_repeat_delay; + add_timer(&atakeyb_rep_timer); + } +#endif + + // handle_scancode(scancode, !break_flag); + if (atari_input_keyboard_interrupt_hook) + atari_input_keyboard_interrupt_hook((unsigned char)scancode, !break_flag); + break; + } + break; + + case AMOUSE: + kb_state.buf[kb_state.len++] = scancode; + if (kb_state.len == 5) { + kb_state.state = KEYBOARD; + /* not yet used */ + /* wake up someone waiting for this */ + } + break; + + case RMOUSE: + kb_state.buf[kb_state.len++] = scancode; + if (kb_state.len == 3) { + kb_state.state = KEYBOARD; + if (atari_mouse_interrupt_hook) + atari_mouse_interrupt_hook(kb_state.buf); + } + break; + + case JOYSTICK: + kb_state.buf[1] = scancode; + kb_state.state = KEYBOARD; +#ifdef FIXED_ATARI_JOYSTICK + atari_joystick_interrupt(kb_state.buf); +#endif + break; + + case CLOCK: + kb_state.buf[kb_state.len++] = scancode; + if (kb_state.len == 6) { + kb_state.state = KEYBOARD; + /* wake up someone waiting for this. + But will this ever be used, as Linux keeps its own time. + Perhaps for synchronization purposes? */ + /* wake_up_interruptible(&clock_wait); */ + } + break; + + case RESYNC: + if (kb_state.len <= 0 || IS_SYNC_CODE(scancode)) { + kb_state.state = KEYBOARD; + goto interpret_scancode; + } + kb_state.len--; + break; + } + } + +#if 0 + if (acia_stat & ACIA_CTS) + /* cannot happen */; +#endif + + if (acia_stat & (ACIA_FE | ACIA_PE)) { + printk("Error in keyboard communication\n"); + } + + /* handle_scancode() can take a lot of time, so check again if + * some character arrived + */ + goto repeat; +} + +/* + * I write to the keyboard without using interrupts, I poll instead. + * This takes for the maximum length string allowed (7) at 7812.5 baud + * 8 data 1 start 1 stop bit: 9.0 ms + * If this takes too long for normal operation, interrupt driven writing + * is the solution. (I made a feeble attempt in that direction but I + * kept it simple for now.) + */ +void ikbd_write(const char *str, int len) +{ + u_char acia_stat; + + if ((len < 1) || (len > 7)) + panic("ikbd: maximum string length exceeded"); + while (len) { + acia_stat = acia.key_ctrl; + if (acia_stat & ACIA_TDRE) { + acia.key_data = *str++; + len--; + } + } +} + +/* Reset (without touching the clock) */ +void ikbd_reset(void) +{ + static const char cmd[2] = { 0x80, 0x01 }; + + ikbd_write(cmd, 2); + + /* + * if all's well code 0xF1 is returned, else the break codes of + * all keys making contact + */ +} + +/* Set mouse button action */ +void ikbd_mouse_button_action(int mode) +{ + char cmd[2] = { 0x07, mode }; + + ikbd_write(cmd, 2); +} + +/* Set relative mouse position reporting */ +void ikbd_mouse_rel_pos(void) +{ + static const char cmd[1] = { 0x08 }; + + ikbd_write(cmd, 1); +} + +/* Set absolute mouse position reporting */ +void ikbd_mouse_abs_pos(int xmax, int ymax) +{ + char cmd[5] = { 0x09, xmax>>8, xmax&0xFF, ymax>>8, ymax&0xFF }; + + ikbd_write(cmd, 5); +} + +/* Set mouse keycode mode */ +void ikbd_mouse_kbd_mode(int dx, int dy) +{ + char cmd[3] = { 0x0A, dx, dy }; + + ikbd_write(cmd, 3); +} + +/* Set mouse threshold */ +void ikbd_mouse_thresh(int x, int y) +{ + char cmd[3] = { 0x0B, x, y }; + + ikbd_write(cmd, 3); +} + +/* Set mouse scale */ +void ikbd_mouse_scale(int x, int y) +{ + char cmd[3] = { 0x0C, x, y }; + + ikbd_write(cmd, 3); +} + +/* Interrogate mouse position */ +void ikbd_mouse_pos_get(int *x, int *y) +{ + static const char cmd[1] = { 0x0D }; + + ikbd_write(cmd, 1); + + /* wait for returning bytes */ +} + +/* Load mouse position */ +void ikbd_mouse_pos_set(int x, int y) +{ + char cmd[6] = { 0x0E, 0x00, x>>8, x&0xFF, y>>8, y&0xFF }; + + ikbd_write(cmd, 6); +} + +/* Set Y=0 at bottom */ +void ikbd_mouse_y0_bot(void) +{ + static const char cmd[1] = { 0x0F }; + + ikbd_write(cmd, 1); +} + +/* Set Y=0 at top */ +void ikbd_mouse_y0_top(void) +{ + static const char cmd[1] = { 0x10 }; + + ikbd_write(cmd, 1); +} + +/* Resume */ +void ikbd_resume(void) +{ + static const char cmd[1] = { 0x11 }; + + ikbd_write(cmd, 1); +} + +/* Disable mouse */ +void ikbd_mouse_disable(void) +{ + static const char cmd[1] = { 0x12 }; + + ikbd_write(cmd, 1); +} + +/* Pause output */ +void ikbd_pause(void) +{ + static const char cmd[1] = { 0x13 }; + + ikbd_write(cmd, 1); +} + +/* Set joystick event reporting */ +void ikbd_joystick_event_on(void) +{ + static const char cmd[1] = { 0x14 }; + + ikbd_write(cmd, 1); +} + +/* Set joystick interrogation mode */ +void ikbd_joystick_event_off(void) +{ + static const char cmd[1] = { 0x15 }; + + ikbd_write(cmd, 1); +} + +/* Joystick interrogation */ +void ikbd_joystick_get_state(void) +{ + static const char cmd[1] = { 0x16 }; + + ikbd_write(cmd, 1); +} + +#if 0 +/* This disables all other ikbd activities !!!! */ +/* Set joystick monitoring */ +void ikbd_joystick_monitor(int rate) +{ + static const char cmd[2] = { 0x17, rate }; + + ikbd_write(cmd, 2); + + kb_state.state = JOYSTICK_MONITOR; +} +#endif + +/* some joystick routines not in yet (0x18-0x19) */ + +/* Disable joysticks */ +void ikbd_joystick_disable(void) +{ + static const char cmd[1] = { 0x1A }; + + ikbd_write(cmd, 1); +} + +/* Time-of-day clock set */ +void ikbd_clock_set(int year, int month, int day, int hour, int minute, int second) +{ + char cmd[7] = { 0x1B, year, month, day, hour, minute, second }; + + ikbd_write(cmd, 7); +} + +/* Interrogate time-of-day clock */ +void ikbd_clock_get(int *year, int *month, int *day, int *hour, int *minute, int second) +{ + static const char cmd[1] = { 0x1C }; + + ikbd_write(cmd, 1); +} + +/* Memory load */ +void ikbd_mem_write(int address, int size, char *data) +{ + panic("Attempt to write data into keyboard memory"); +} + +/* Memory read */ +void ikbd_mem_read(int address, char data[6]) +{ + char cmd[3] = { 0x21, address>>8, address&0xFF }; + + ikbd_write(cmd, 3); + + /* receive data and put it in data */ +} + +/* Controller execute */ +void ikbd_exec(int address) +{ + char cmd[3] = { 0x22, address>>8, address&0xFF }; + + ikbd_write(cmd, 3); +} + +/* Status inquiries (0x87-0x9A) not yet implemented */ + +/* Set the state of the caps lock led. */ +void atari_kbd_leds(unsigned int leds) +{ + char cmd[6] = {32, 0, 4, 1, 254 + ((leds & 4) != 0), 0}; + + ikbd_write(cmd, 6); +} + +/* + * The original code sometimes left the interrupt line of + * the ACIAs low forever. I hope, it is fixed now. + * + * Martin Rogge, 20 Aug 1995 + */ + +static int atari_keyb_done = 0; + +int __init atari_keyb_init(void) +{ + if (atari_keyb_done) + return 0; + + /* setup key map */ + memcpy(key_maps[0], ataplain_map, sizeof(plain_map)); + + kb_state.state = KEYBOARD; + kb_state.len = 0; + + request_irq(IRQ_MFP_ACIA, atari_keyboard_interrupt, IRQ_TYPE_SLOW, + "keyboard/mouse/MIDI", atari_keyboard_interrupt); + + atari_turnoff_irq(IRQ_MFP_ACIA); + do { + /* reset IKBD ACIA */ + acia.key_ctrl = ACIA_RESET | + (atari_switches & ATARI_SWITCH_IKBD) ? ACIA_RHTID : 0; + (void)acia.key_ctrl; + (void)acia.key_data; + + /* reset MIDI ACIA */ + acia.mid_ctrl = ACIA_RESET | + (atari_switches & ATARI_SWITCH_MIDI) ? ACIA_RHTID : 0; + (void)acia.mid_ctrl; + (void)acia.mid_data; + + /* divide 500kHz by 64 gives 7812.5 baud */ + /* 8 data no parity 1 start 1 stop bit */ + /* receive interrupt enabled */ + /* RTS low (except if switch selected), transmit interrupt disabled */ + acia.key_ctrl = (ACIA_DIV64|ACIA_D8N1S|ACIA_RIE) | + ((atari_switches & ATARI_SWITCH_IKBD) ? + ACIA_RHTID : ACIA_RLTID); + + acia.mid_ctrl = ACIA_DIV16 | ACIA_D8N1S | + (atari_switches & ATARI_SWITCH_MIDI) ? ACIA_RHTID : 0; + + /* make sure the interrupt line is up */ + } while ((mfp.par_dt_reg & 0x10) == 0); + + /* enable ACIA Interrupts */ + mfp.active_edge &= ~0x10; + atari_turnon_irq(IRQ_MFP_ACIA); + + ikbd_self_test = 1; + ikbd_reset(); + /* wait for a period of inactivity (here: 0.25s), then assume the IKBD's + * self-test is finished */ + self_test_last_rcv = jiffies; + while (time_before(jiffies, self_test_last_rcv + HZ/4)) + barrier(); + /* if not incremented: no 0xf1 received */ + if (ikbd_self_test == 1) + printk(KERN_ERR "WARNING: keyboard self test failed!\n"); + ikbd_self_test = 0; + + ikbd_mouse_disable(); + ikbd_joystick_disable(); + +#ifdef FIXED_ATARI_JOYSTICK + atari_joystick_init(); +#endif + + // flag init done + atari_keyb_done = 1; + return 0; +} + + +int atari_kbdrate(struct kbd_repeat *k) +{ + if (k->delay > 0) { + /* convert from msec to jiffies */ + key_repeat_delay = (k->delay * HZ + 500) / 1000; + if (key_repeat_delay < 1) + key_repeat_delay = 1; + } + if (k->period > 0) { + key_repeat_rate = (k->period * HZ + 500) / 1000; + if (key_repeat_rate < 1) + key_repeat_rate = 1; + } + + k->delay = key_repeat_delay * 1000 / HZ; + k->period = key_repeat_rate * 1000 / HZ; + + return 0; +} + +int atari_kbd_translate(unsigned char keycode, unsigned char *keycodep, char raw_mode) +{ +#ifdef CONFIG_MAGIC_SYSRQ + /* ALT+HELP pressed? */ + if ((keycode == 98) && ((shift_state & 0xff) == 8)) + *keycodep = 0xff; + else +#endif + *keycodep = keycode; + return 1; +} diff --git a/arch/m68k/atari/config.c b/arch/m68k/atari/config.c index ca5cd4344e3..e40e5dcaa34 100644 --- a/arch/m68k/atari/config.c +++ b/arch/m68k/atari/config.c @@ -50,70 +50,25 @@ int atari_dont_touch_floppy_select; int atari_rtc_year_offset; /* local function prototypes */ -static void atari_reset( void ); +static void atari_reset(void); static void atari_get_model(char *model); static int atari_get_hardware_list(char *buffer); /* atari specific irq functions */ extern void atari_init_IRQ (void); -extern void atari_mksound( unsigned int count, unsigned int ticks ); +extern void atari_mksound(unsigned int count, unsigned int ticks); #ifdef CONFIG_HEARTBEAT -static void atari_heartbeat( int on ); +static void atari_heartbeat(int on); #endif /* atari specific timer functions (in time.c) */ -extern void atari_sched_init(irq_handler_t ); +extern void atari_sched_init(irq_handler_t); extern unsigned long atari_gettimeoffset (void); extern int atari_mste_hwclk (int, struct rtc_time *); extern int atari_tt_hwclk (int, struct rtc_time *); extern int atari_mste_set_clock_mmss (unsigned long); extern int atari_tt_set_clock_mmss (unsigned long); -/* atari specific debug functions (in debug.c) */ -extern void atari_debug_init(void); - - -/* I've moved hwreg_present() and hwreg_present_bywrite() out into - * mm/hwtest.c, to avoid having multiple copies of the same routine - * in the kernel [I wanted them in hp300 and they were already used - * in the nubus code. NB: I don't have an Atari so this might (just - * conceivably) break something. - * I've preserved the #if 0 version of hwreg_present_bywrite() here - * for posterity. - * -- Peter Maydell <pmaydell@chiark.greenend.org.uk>, 05/1998 - */ - -#if 0 -static int __init -hwreg_present_bywrite(volatile void *regp, unsigned char val) -{ - int ret; - long save_sp, save_vbr; - static long tmp_vectors[3] = { [2] = (long)&&after_test }; - - __asm__ __volatile__ - ( "movec %/vbr,%2\n\t" /* save vbr value */ - "movec %4,%/vbr\n\t" /* set up temporary vectors */ - "movel %/sp,%1\n\t" /* save sp */ - "moveq #0,%0\n\t" /* assume not present */ - "moveb %5,%3@\n\t" /* write the hardware reg */ - "cmpb %3@,%5\n\t" /* compare it */ - "seq %0" /* comes here only if reg */ - /* is present */ - : "=d&" (ret), "=r&" (save_sp), "=r&" (save_vbr) - : "a" (regp), "r" (tmp_vectors), "d" (val) - ); - after_test: - __asm__ __volatile__ - ( "movel %0,%/sp\n\t" /* restore sp */ - "movec %1,%/vbr" /* restore vbr */ - : : "r" (save_sp), "r" (save_vbr) : "sp" - ); - - return( ret ); -} -#endif - /* ++roman: This is a more elaborate test for an SCC chip, since the plain * Medusa board generates DTACK at the SCC's standard addresses, but a SCC @@ -123,26 +78,34 @@ hwreg_present_bywrite(volatile void *regp, unsigned char val) * should be readable without trouble (from channel A!). */ -static int __init scc_test( volatile char *ctla ) +static int __init scc_test(volatile char *ctla) { - if (!hwreg_present( ctla )) - return( 0 ); + if (!hwreg_present(ctla)) + return 0; MFPDELAY(); - *ctla = 2; MFPDELAY(); - *ctla = 0x40; MFPDELAY(); + *ctla = 2; + MFPDELAY(); + *ctla = 0x40; + MFPDELAY(); - *ctla = 2; MFPDELAY(); - if (*ctla != 0x40) return( 0 ); + *ctla = 2; + MFPDELAY(); + if (*ctla != 0x40) + return 0; MFPDELAY(); - *ctla = 2; MFPDELAY(); - *ctla = 0x60; MFPDELAY(); + *ctla = 2; + MFPDELAY(); + *ctla = 0x60; + MFPDELAY(); - *ctla = 2; MFPDELAY(); - if (*ctla != 0x60) return( 0 ); + *ctla = 2; + MFPDELAY(); + if (*ctla != 0x60) + return 0; - return( 1 ); + return 1; } @@ -152,61 +115,66 @@ static int __init scc_test( volatile char *ctla ) int __init atari_parse_bootinfo(const struct bi_record *record) { - int unknown = 0; - const u_long *data = record->data; + int unknown = 0; + const u_long *data = record->data; - switch (record->tag) { + switch (record->tag) { case BI_ATARI_MCH_COOKIE: - atari_mch_cookie = *data; - break; + atari_mch_cookie = *data; + break; case BI_ATARI_MCH_TYPE: - atari_mch_type = *data; - break; + atari_mch_type = *data; + break; default: - unknown = 1; - } - return(unknown); + unknown = 1; + break; + } + return unknown; } /* Parse the Atari-specific switches= option. */ -void __init atari_switches_setup( const char *str, unsigned len ) +static int __init atari_switches_setup(char *str) { - char switches[len+1]; - char *p; - int ovsc_shift; - char *args = switches; - - /* copy string to local array, strsep works destructively... */ - strlcpy( switches, str, sizeof(switches) ); - atari_switches = 0; - - /* parse the options */ - while ((p = strsep(&args, ",")) != NULL) { - if (!*p) continue; - ovsc_shift = 0; - if (strncmp( p, "ov_", 3 ) == 0) { - p += 3; - ovsc_shift = ATARI_SWITCH_OVSC_SHIFT; - } - - if (strcmp( p, "ikbd" ) == 0) { - /* RTS line of IKBD ACIA */ - atari_switches |= ATARI_SWITCH_IKBD << ovsc_shift; - } - else if (strcmp( p, "midi" ) == 0) { - /* RTS line of MIDI ACIA */ - atari_switches |= ATARI_SWITCH_MIDI << ovsc_shift; + char switches[strlen(str) + 1]; + char *p; + int ovsc_shift; + char *args = switches; + + if (!MACH_IS_ATARI) + return 0; + + /* copy string to local array, strsep works destructively... */ + strcpy(switches, str); + atari_switches = 0; + + /* parse the options */ + while ((p = strsep(&args, ",")) != NULL) { + if (!*p) + continue; + ovsc_shift = 0; + if (strncmp(p, "ov_", 3) == 0) { + p += 3; + ovsc_shift = ATARI_SWITCH_OVSC_SHIFT; + } + + if (strcmp(p, "ikbd") == 0) { + /* RTS line of IKBD ACIA */ + atari_switches |= ATARI_SWITCH_IKBD << ovsc_shift; + } else if (strcmp(p, "midi") == 0) { + /* RTS line of MIDI ACIA */ + atari_switches |= ATARI_SWITCH_MIDI << ovsc_shift; + } else if (strcmp(p, "snd6") == 0) { + atari_switches |= ATARI_SWITCH_SND6 << ovsc_shift; + } else if (strcmp(p, "snd7") == 0) { + atari_switches |= ATARI_SWITCH_SND7 << ovsc_shift; + } } - else if (strcmp( p, "snd6" ) == 0) { - atari_switches |= ATARI_SWITCH_SND6 << ovsc_shift; - } - else if (strcmp( p, "snd7" ) == 0) { - atari_switches |= ATARI_SWITCH_SND7 << ovsc_shift; - } - } + return 0; } +early_param("switches", atari_switches_setup); + /* * Setup the Atari configuration info @@ -214,284 +182,281 @@ void __init atari_switches_setup( const char *str, unsigned len ) void __init config_atari(void) { - unsigned short tos_version; + unsigned short tos_version; - memset(&atari_hw_present, 0, sizeof(atari_hw_present)); + memset(&atari_hw_present, 0, sizeof(atari_hw_present)); - atari_debug_init(); + /* Change size of I/O space from 64KB to 4GB. */ + ioport_resource.end = 0xFFFFFFFF; - ioport_resource.end = 0xFFFFFFFF; /* Change size of I/O space from 64KB - to 4GB. */ - - mach_sched_init = atari_sched_init; - mach_init_IRQ = atari_init_IRQ; - mach_get_model = atari_get_model; - mach_get_hardware_list = atari_get_hardware_list; - mach_gettimeoffset = atari_gettimeoffset; - mach_reset = atari_reset; - mach_max_dma_address = 0xffffff; + mach_sched_init = atari_sched_init; + mach_init_IRQ = atari_init_IRQ; + mach_get_model = atari_get_model; + mach_get_hardware_list = atari_get_hardware_list; + mach_gettimeoffset = atari_gettimeoffset; + mach_reset = atari_reset; + mach_max_dma_address = 0xffffff; #if defined(CONFIG_INPUT_M68K_BEEP) || defined(CONFIG_INPUT_M68K_BEEP_MODULE) - mach_beep = atari_mksound; + mach_beep = atari_mksound; #endif #ifdef CONFIG_HEARTBEAT - mach_heartbeat = atari_heartbeat; + mach_heartbeat = atari_heartbeat; #endif - /* Set switches as requested by the user */ - if (atari_switches & ATARI_SWITCH_IKBD) - acia.key_ctrl = ACIA_DIV64 | ACIA_D8N1S | ACIA_RHTID; - if (atari_switches & ATARI_SWITCH_MIDI) - acia.mid_ctrl = ACIA_DIV16 | ACIA_D8N1S | ACIA_RHTID; - if (atari_switches & (ATARI_SWITCH_SND6|ATARI_SWITCH_SND7)) { - sound_ym.rd_data_reg_sel = 14; - sound_ym.wd_data = sound_ym.rd_data_reg_sel | - ((atari_switches&ATARI_SWITCH_SND6) ? 0x40 : 0) | - ((atari_switches&ATARI_SWITCH_SND7) ? 0x80 : 0); - } - - /* ++bjoern: - * Determine hardware present - */ + /* Set switches as requested by the user */ + if (atari_switches & ATARI_SWITCH_IKBD) + acia.key_ctrl = ACIA_DIV64 | ACIA_D8N1S | ACIA_RHTID; + if (atari_switches & ATARI_SWITCH_MIDI) + acia.mid_ctrl = ACIA_DIV16 | ACIA_D8N1S | ACIA_RHTID; + if (atari_switches & (ATARI_SWITCH_SND6|ATARI_SWITCH_SND7)) { + sound_ym.rd_data_reg_sel = 14; + sound_ym.wd_data = sound_ym.rd_data_reg_sel | + ((atari_switches&ATARI_SWITCH_SND6) ? 0x40 : 0) | + ((atari_switches&ATARI_SWITCH_SND7) ? 0x80 : 0); + } - printk( "Atari hardware found: " ); - if (MACH_IS_MEDUSA || MACH_IS_HADES) { - /* There's no Atari video hardware on the Medusa, but all the - * addresses below generate a DTACK so no bus error occurs! */ - } - else if (hwreg_present( f030_xreg )) { - ATARIHW_SET(VIDEL_SHIFTER); - printk( "VIDEL " ); - /* This is a temporary hack: If there is Falcon video - * hardware, we assume that the ST-DMA serves SCSI instead of - * ACSI. In the future, there should be a better method for - * this... - */ - ATARIHW_SET(ST_SCSI); - printk( "STDMA-SCSI " ); - } - else if (hwreg_present( tt_palette )) { - ATARIHW_SET(TT_SHIFTER); - printk( "TT_SHIFTER " ); - } - else if (hwreg_present( &shifter.bas_hi )) { - if (hwreg_present( &shifter.bas_lo ) && - (shifter.bas_lo = 0x0aau, shifter.bas_lo == 0x0aau)) { - ATARIHW_SET(EXTD_SHIFTER); - printk( "EXTD_SHIFTER " ); - } - else { - ATARIHW_SET(STND_SHIFTER); - printk( "STND_SHIFTER " ); - } - } - if (hwreg_present( &mfp.par_dt_reg )) { - ATARIHW_SET(ST_MFP); - printk( "ST_MFP " ); - } - if (hwreg_present( &tt_mfp.par_dt_reg )) { - ATARIHW_SET(TT_MFP); - printk( "TT_MFP " ); - } - if (hwreg_present( &tt_scsi_dma.dma_addr_hi )) { - ATARIHW_SET(SCSI_DMA); - printk( "TT_SCSI_DMA " ); - } - if (!MACH_IS_HADES && hwreg_present( &st_dma.dma_hi )) { - ATARIHW_SET(STND_DMA); - printk( "STND_DMA " ); - } - if (MACH_IS_MEDUSA || /* The ST-DMA address registers aren't readable - * on all Medusas, so the test below may fail */ - (hwreg_present( &st_dma.dma_vhi ) && - (st_dma.dma_vhi = 0x55) && (st_dma.dma_hi = 0xaa) && - st_dma.dma_vhi == 0x55 && st_dma.dma_hi == 0xaa && - (st_dma.dma_vhi = 0xaa) && (st_dma.dma_hi = 0x55) && - st_dma.dma_vhi == 0xaa && st_dma.dma_hi == 0x55)) { - ATARIHW_SET(EXTD_DMA); - printk( "EXTD_DMA " ); - } - if (hwreg_present( &tt_scsi.scsi_data )) { - ATARIHW_SET(TT_SCSI); - printk( "TT_SCSI " ); - } - if (hwreg_present( &sound_ym.rd_data_reg_sel )) { - ATARIHW_SET(YM_2149); - printk( "YM2149 " ); - } - if (!MACH_IS_MEDUSA && !MACH_IS_HADES && - hwreg_present( &tt_dmasnd.ctrl )) { - ATARIHW_SET(PCM_8BIT); - printk( "PCM " ); - } - if (!MACH_IS_HADES && hwreg_present( &falcon_codec.unused5 )) { - ATARIHW_SET(CODEC); - printk( "CODEC " ); - } - if (hwreg_present( &dsp56k_host_interface.icr )) { - ATARIHW_SET(DSP56K); - printk( "DSP56K " ); - } - if (hwreg_present( &tt_scc_dma.dma_ctrl ) && + /* ++bjoern: + * Determine hardware present + */ + + printk("Atari hardware found: "); + if (MACH_IS_MEDUSA || MACH_IS_HADES) { + /* There's no Atari video hardware on the Medusa, but all the + * addresses below generate a DTACK so no bus error occurs! */ + } else if (hwreg_present(f030_xreg)) { + ATARIHW_SET(VIDEL_SHIFTER); + printk("VIDEL "); + /* This is a temporary hack: If there is Falcon video + * hardware, we assume that the ST-DMA serves SCSI instead of + * ACSI. In the future, there should be a better method for + * this... + */ + ATARIHW_SET(ST_SCSI); + printk("STDMA-SCSI "); + } else if (hwreg_present(tt_palette)) { + ATARIHW_SET(TT_SHIFTER); + printk("TT_SHIFTER "); + } else if (hwreg_present(&shifter.bas_hi)) { + if (hwreg_present(&shifter.bas_lo) && + (shifter.bas_lo = 0x0aau, shifter.bas_lo == 0x0aau)) { + ATARIHW_SET(EXTD_SHIFTER); + printk("EXTD_SHIFTER "); + } else { + ATARIHW_SET(STND_SHIFTER); + printk("STND_SHIFTER "); + } + } + if (hwreg_present(&mfp.par_dt_reg)) { + ATARIHW_SET(ST_MFP); + printk("ST_MFP "); + } + if (hwreg_present(&tt_mfp.par_dt_reg)) { + ATARIHW_SET(TT_MFP); + printk("TT_MFP "); + } + if (hwreg_present(&tt_scsi_dma.dma_addr_hi)) { + ATARIHW_SET(SCSI_DMA); + printk("TT_SCSI_DMA "); + } + if (!MACH_IS_HADES && hwreg_present(&st_dma.dma_hi)) { + ATARIHW_SET(STND_DMA); + printk("STND_DMA "); + } + /* + * The ST-DMA address registers aren't readable + * on all Medusas, so the test below may fail + */ + if (MACH_IS_MEDUSA || + (hwreg_present(&st_dma.dma_vhi) && + (st_dma.dma_vhi = 0x55) && (st_dma.dma_hi = 0xaa) && + st_dma.dma_vhi == 0x55 && st_dma.dma_hi == 0xaa && + (st_dma.dma_vhi = 0xaa) && (st_dma.dma_hi = 0x55) && + st_dma.dma_vhi == 0xaa && st_dma.dma_hi == 0x55)) { + ATARIHW_SET(EXTD_DMA); + printk("EXTD_DMA "); + } + if (hwreg_present(&tt_scsi.scsi_data)) { + ATARIHW_SET(TT_SCSI); + printk("TT_SCSI "); + } + if (hwreg_present(&sound_ym.rd_data_reg_sel)) { + ATARIHW_SET(YM_2149); + printk("YM2149 "); + } + if (!MACH_IS_MEDUSA && !MACH_IS_HADES && + hwreg_present(&tt_dmasnd.ctrl)) { + ATARIHW_SET(PCM_8BIT); + printk("PCM "); + } + if (!MACH_IS_HADES && hwreg_present(&falcon_codec.unused5)) { + ATARIHW_SET(CODEC); + printk("CODEC "); + } + if (hwreg_present(&dsp56k_host_interface.icr)) { + ATARIHW_SET(DSP56K); + printk("DSP56K "); + } + if (hwreg_present(&tt_scc_dma.dma_ctrl) && #if 0 - /* This test sucks! Who knows some better? */ - (tt_scc_dma.dma_ctrl = 0x01, (tt_scc_dma.dma_ctrl & 1) == 1) && - (tt_scc_dma.dma_ctrl = 0x00, (tt_scc_dma.dma_ctrl & 1) == 0) + /* This test sucks! Who knows some better? */ + (tt_scc_dma.dma_ctrl = 0x01, (tt_scc_dma.dma_ctrl & 1) == 1) && + (tt_scc_dma.dma_ctrl = 0x00, (tt_scc_dma.dma_ctrl & 1) == 0) #else - !MACH_IS_MEDUSA && !MACH_IS_HADES + !MACH_IS_MEDUSA && !MACH_IS_HADES #endif - ) { - ATARIHW_SET(SCC_DMA); - printk( "SCC_DMA " ); - } - if (scc_test( &scc.cha_a_ctrl )) { - ATARIHW_SET(SCC); - printk( "SCC " ); - } - if (scc_test( &st_escc.cha_b_ctrl )) { - ATARIHW_SET( ST_ESCC ); - printk( "ST_ESCC " ); - } - if (MACH_IS_HADES) - { - ATARIHW_SET( VME ); - printk( "VME " ); - } - else if (hwreg_present( &tt_scu.sys_mask )) { - ATARIHW_SET(SCU); - /* Assume a VME bus if there's a SCU */ - ATARIHW_SET( VME ); - printk( "VME SCU " ); - } - if (hwreg_present( (void *)(0xffff9210) )) { - ATARIHW_SET(ANALOG_JOY); - printk( "ANALOG_JOY " ); - } - if (!MACH_IS_HADES && hwreg_present( blitter.halftone )) { - ATARIHW_SET(BLITTER); - printk( "BLITTER " ); - } - if (hwreg_present((void *)0xfff00039)) { - ATARIHW_SET(IDE); - printk( "IDE " ); - } + ) { + ATARIHW_SET(SCC_DMA); + printk("SCC_DMA "); + } + if (scc_test(&scc.cha_a_ctrl)) { + ATARIHW_SET(SCC); + printk("SCC "); + } + if (scc_test(&st_escc.cha_b_ctrl)) { + ATARIHW_SET(ST_ESCC); + printk("ST_ESCC "); + } + if (MACH_IS_HADES) { + ATARIHW_SET(VME); + printk("VME "); + } else if (hwreg_present(&tt_scu.sys_mask)) { + ATARIHW_SET(SCU); + /* Assume a VME bus if there's a SCU */ + ATARIHW_SET(VME); + printk("VME SCU "); + } + if (hwreg_present((void *)(0xffff9210))) { + ATARIHW_SET(ANALOG_JOY); + printk("ANALOG_JOY "); + } + if (!MACH_IS_HADES && hwreg_present(blitter.halftone)) { + ATARIHW_SET(BLITTER); + printk("BLITTER "); + } + if (hwreg_present((void *)0xfff00039)) { + ATARIHW_SET(IDE); + printk("IDE "); + } #if 1 /* This maybe wrong */ - if (!MACH_IS_MEDUSA && !MACH_IS_HADES && - hwreg_present( &tt_microwire.data ) && - hwreg_present( &tt_microwire.mask ) && - (tt_microwire.mask = 0x7ff, - udelay(1), - tt_microwire.data = MW_LM1992_PSG_HIGH | MW_LM1992_ADDR, - udelay(1), - tt_microwire.data != 0)) { - ATARIHW_SET(MICROWIRE); - while (tt_microwire.mask != 0x7ff) ; - printk( "MICROWIRE " ); - } + if (!MACH_IS_MEDUSA && !MACH_IS_HADES && + hwreg_present(&tt_microwire.data) && + hwreg_present(&tt_microwire.mask) && + (tt_microwire.mask = 0x7ff, + udelay(1), + tt_microwire.data = MW_LM1992_PSG_HIGH | MW_LM1992_ADDR, + udelay(1), + tt_microwire.data != 0)) { + ATARIHW_SET(MICROWIRE); + while (tt_microwire.mask != 0x7ff) + ; + printk("MICROWIRE "); + } #endif - if (hwreg_present( &tt_rtc.regsel )) { - ATARIHW_SET(TT_CLK); - printk( "TT_CLK " ); - mach_hwclk = atari_tt_hwclk; - mach_set_clock_mmss = atari_tt_set_clock_mmss; - } - if (!MACH_IS_HADES && hwreg_present( &mste_rtc.sec_ones)) { - ATARIHW_SET(MSTE_CLK); - printk( "MSTE_CLK "); - mach_hwclk = atari_mste_hwclk; - mach_set_clock_mmss = atari_mste_set_clock_mmss; - } - if (!MACH_IS_MEDUSA && !MACH_IS_HADES && - hwreg_present( &dma_wd.fdc_speed ) && - hwreg_write( &dma_wd.fdc_speed, 0 )) { - ATARIHW_SET(FDCSPEED); - printk( "FDC_SPEED "); - } - if (!MACH_IS_HADES && !ATARIHW_PRESENT(ST_SCSI)) { - ATARIHW_SET(ACSI); - printk( "ACSI " ); - } - printk("\n"); - - if (CPU_IS_040_OR_060) - /* Now it seems to be safe to turn of the tt0 transparent - * translation (the one that must not be turned off in - * head.S...) - */ - __asm__ volatile ("moveq #0,%/d0\n\t" - ".chip 68040\n\t" - "movec %%d0,%%itt0\n\t" - "movec %%d0,%%dtt0\n\t" - ".chip 68k" - : /* no outputs */ - : /* no inputs */ - : "d0"); - - /* allocator for memory that must reside in st-ram */ - atari_stram_init (); - - /* Set up a mapping for the VMEbus address region: - * - * VME is either at phys. 0xfexxxxxx (TT) or 0xa00000..0xdfffff - * (MegaSTE) In both cases, the whole 16 MB chunk is mapped at - * 0xfe000000 virt., because this can be done with a single - * transparent translation. On the 68040, lots of often unused - * page tables would be needed otherwise. On a MegaSTE or similar, - * the highest byte is stripped off by hardware due to the 24 bit - * design of the bus. - */ + if (hwreg_present(&tt_rtc.regsel)) { + ATARIHW_SET(TT_CLK); + printk("TT_CLK "); + mach_hwclk = atari_tt_hwclk; + mach_set_clock_mmss = atari_tt_set_clock_mmss; + } + if (!MACH_IS_HADES && hwreg_present(&mste_rtc.sec_ones)) { + ATARIHW_SET(MSTE_CLK); + printk("MSTE_CLK "); + mach_hwclk = atari_mste_hwclk; + mach_set_clock_mmss = atari_mste_set_clock_mmss; + } + if (!MACH_IS_MEDUSA && !MACH_IS_HADES && + hwreg_present(&dma_wd.fdc_speed) && + hwreg_write(&dma_wd.fdc_speed, 0)) { + ATARIHW_SET(FDCSPEED); + printk("FDC_SPEED "); + } + if (!MACH_IS_HADES && !ATARIHW_PRESENT(ST_SCSI)) { + ATARIHW_SET(ACSI); + printk("ACSI "); + } + printk("\n"); + + if (CPU_IS_040_OR_060) + /* Now it seems to be safe to turn of the tt0 transparent + * translation (the one that must not be turned off in + * head.S...) + */ + asm volatile ("\n" + " moveq #0,%%d0\n" + " .chip 68040\n" + " movec %%d0,%%itt0\n" + " movec %%d0,%%dtt0\n" + " .chip 68k" + : /* no outputs */ + : /* no inputs */ + : "d0"); + + /* allocator for memory that must reside in st-ram */ + atari_stram_init(); + + /* Set up a mapping for the VMEbus address region: + * + * VME is either at phys. 0xfexxxxxx (TT) or 0xa00000..0xdfffff + * (MegaSTE) In both cases, the whole 16 MB chunk is mapped at + * 0xfe000000 virt., because this can be done with a single + * transparent translation. On the 68040, lots of often unused + * page tables would be needed otherwise. On a MegaSTE or similar, + * the highest byte is stripped off by hardware due to the 24 bit + * design of the bus. + */ + + if (CPU_IS_020_OR_030) { + unsigned long tt1_val; + tt1_val = 0xfe008543; /* Translate 0xfexxxxxx, enable, cache + * inhibit, read and write, FDC mask = 3, + * FDC val = 4 -> Supervisor only */ + asm volatile ("\n" + " .chip 68030\n" + " pmove %0@,%/tt1\n" + " .chip 68k" + : : "a" (&tt1_val)); + } else { + asm volatile ("\n" + " .chip 68040\n" + " movec %0,%%itt1\n" + " movec %0,%%dtt1\n" + " .chip 68k" + : + : "d" (0xfe00a040)); /* Translate 0xfexxxxxx, enable, + * supervisor only, non-cacheable/ + * serialized, writable */ + + } - if (CPU_IS_020_OR_030) { - unsigned long tt1_val; - tt1_val = 0xfe008543; /* Translate 0xfexxxxxx, enable, cache - * inhibit, read and write, FDC mask = 3, - * FDC val = 4 -> Supervisor only */ - __asm__ __volatile__ ( ".chip 68030\n\t" - "pmove %0@,%/tt1\n\t" - ".chip 68k" - : : "a" (&tt1_val) ); - } - else { - __asm__ __volatile__ - ( "movel %0,%/d0\n\t" - ".chip 68040\n\t" - "movec %%d0,%%itt1\n\t" - "movec %%d0,%%dtt1\n\t" - ".chip 68k" - : - : "g" (0xfe00a040) /* Translate 0xfexxxxxx, enable, - * supervisor only, non-cacheable/ - * serialized, writable */ - : "d0" ); - - } - - /* Fetch tos version at Physical 2 */ - /* We my not be able to access this address if the kernel is - loaded to st ram, since the first page is unmapped. On the - Medusa this is always the case and there is nothing we can do - about this, so we just assume the smaller offset. For the TT - we use the fact that in head.S we have set up a mapping - 0xFFxxxxxx -> 0x00xxxxxx, so that the first 16MB is accessible - in the last 16MB of the address space. */ - tos_version = (MACH_IS_MEDUSA || MACH_IS_HADES) ? - 0xfff : *(unsigned short *)0xff000002; - atari_rtc_year_offset = (tos_version < 0x306) ? 70 : 68; + /* Fetch tos version at Physical 2 */ + /* + * We my not be able to access this address if the kernel is + * loaded to st ram, since the first page is unmapped. On the + * Medusa this is always the case and there is nothing we can do + * about this, so we just assume the smaller offset. For the TT + * we use the fact that in head.S we have set up a mapping + * 0xFFxxxxxx -> 0x00xxxxxx, so that the first 16MB is accessible + * in the last 16MB of the address space. + */ + tos_version = (MACH_IS_MEDUSA || MACH_IS_HADES) ? + 0xfff : *(unsigned short *)0xff000002; + atari_rtc_year_offset = (tos_version < 0x306) ? 70 : 68; } #ifdef CONFIG_HEARTBEAT -static void atari_heartbeat( int on ) +static void atari_heartbeat(int on) { - unsigned char tmp; - unsigned long flags; + unsigned char tmp; + unsigned long flags; - if (atari_dont_touch_floppy_select) - return; + if (atari_dont_touch_floppy_select) + return; - local_irq_save(flags); - sound_ym.rd_data_reg_sel = 14; /* Select PSG Port A */ - tmp = sound_ym.rd_data_reg_sel; - sound_ym.wd_data = on ? (tmp & ~0x02) : (tmp | 0x02); - local_irq_restore(flags); + local_irq_save(flags); + sound_ym.rd_data_reg_sel = 14; /* Select PSG Port A */ + tmp = sound_ym.rd_data_reg_sel; + sound_ym.wd_data = on ? (tmp & ~0x02) : (tmp | 0x02); + local_irq_restore(flags); } #endif @@ -526,180 +491,171 @@ static void atari_heartbeat( int on ) /* ++andreas: no need for complicated code, just depend on prefetch */ -static void atari_reset (void) +static void atari_reset(void) { - long tc_val = 0; - long reset_addr; - - /* On the Medusa, phys. 0x4 may contain garbage because it's no - ROM. See above for explanation why we cannot use PTOV(4). */ - reset_addr = MACH_IS_HADES ? 0x7fe00030 : - MACH_IS_MEDUSA || MACH_IS_AB40 ? 0xe00030 : - *(unsigned long *) 0xff000004; - - /* reset ACIA for switch off OverScan, if it's active */ - if (atari_switches & ATARI_SWITCH_OVSC_IKBD) - acia.key_ctrl = ACIA_RESET; - if (atari_switches & ATARI_SWITCH_OVSC_MIDI) - acia.mid_ctrl = ACIA_RESET; - - /* processor independent: turn off interrupts and reset the VBR; - * the caches must be left enabled, else prefetching the final jump - * instruction doesn't work. */ - local_irq_disable(); - __asm__ __volatile__ - ("moveq #0,%/d0\n\t" - "movec %/d0,%/vbr" - : : : "d0" ); - - if (CPU_IS_040_OR_060) { - unsigned long jmp_addr040 = virt_to_phys(&&jmp_addr_label040); - if (CPU_IS_060) { - /* 68060: clear PCR to turn off superscalar operation */ - __asm__ __volatile__ - ("moveq #0,%/d0\n\t" - ".chip 68060\n\t" - "movec %%d0,%%pcr\n\t" - ".chip 68k" - : : : "d0" ); - } - - __asm__ __volatile__ - ("movel %0,%/d0\n\t" - "andl #0xff000000,%/d0\n\t" - "orw #0xe020,%/d0\n\t" /* map 16 MB, enable, cacheable */ - ".chip 68040\n\t" - "movec %%d0,%%itt0\n\t" - "movec %%d0,%%dtt0\n\t" - ".chip 68k\n\t" - "jmp %0@\n\t" - : /* no outputs */ - : "a" (jmp_addr040) - : "d0" ); - jmp_addr_label040: - __asm__ __volatile__ - ("moveq #0,%/d0\n\t" - "nop\n\t" - ".chip 68040\n\t" - "cinva %%bc\n\t" - "nop\n\t" - "pflusha\n\t" - "nop\n\t" - "movec %%d0,%%tc\n\t" - "nop\n\t" - /* the following setup of transparent translations is needed on the - * Afterburner040 to successfully reboot. Other machines shouldn't - * care about a different tt regs setup, they also didn't care in - * the past that the regs weren't turned off. */ - "movel #0xffc000,%%d0\n\t" /* whole insn space cacheable */ - "movec %%d0,%%itt0\n\t" - "movec %%d0,%%itt1\n\t" - "orw #0x40,%/d0\n\t" /* whole data space non-cacheable/ser. */ - "movec %%d0,%%dtt0\n\t" - "movec %%d0,%%dtt1\n\t" - ".chip 68k\n\t" - "jmp %0@" - : /* no outputs */ - : "a" (reset_addr) - : "d0"); - } - else - __asm__ __volatile__ - ("pmove %0@,%/tc\n\t" - "jmp %1@" - : /* no outputs */ - : "a" (&tc_val), "a" (reset_addr)); + long tc_val = 0; + long reset_addr; + + /* + * On the Medusa, phys. 0x4 may contain garbage because it's no + * ROM. See above for explanation why we cannot use PTOV(4). + */ + reset_addr = MACH_IS_HADES ? 0x7fe00030 : + MACH_IS_MEDUSA || MACH_IS_AB40 ? 0xe00030 : + *(unsigned long *) 0xff000004; + + /* reset ACIA for switch off OverScan, if it's active */ + if (atari_switches & ATARI_SWITCH_OVSC_IKBD) + acia.key_ctrl = ACIA_RESET; + if (atari_switches & ATARI_SWITCH_OVSC_MIDI) + acia.mid_ctrl = ACIA_RESET; + + /* processor independent: turn off interrupts and reset the VBR; + * the caches must be left enabled, else prefetching the final jump + * instruction doesn't work. + */ + local_irq_disable(); + asm volatile ("movec %0,%%vbr" + : : "d" (0)); + + if (CPU_IS_040_OR_060) { + unsigned long jmp_addr040 = virt_to_phys(&&jmp_addr_label040); + if (CPU_IS_060) { + /* 68060: clear PCR to turn off superscalar operation */ + asm volatile ("\n" + " .chip 68060\n" + " movec %0,%%pcr\n" + " .chip 68k" + : : "d" (0)); + } + + asm volatile ("\n" + " move.l %0,%%d0\n" + " and.l #0xff000000,%%d0\n" + " or.w #0xe020,%%d0\n" /* map 16 MB, enable, cacheable */ + " .chip 68040\n" + " movec %%d0,%%itt0\n" + " movec %%d0,%%dtt0\n" + " .chip 68k\n" + " jmp %0@" + : : "a" (jmp_addr040) + : "d0"); + jmp_addr_label040: + asm volatile ("\n" + " moveq #0,%%d0\n" + " nop\n" + " .chip 68040\n" + " cinva %%bc\n" + " nop\n" + " pflusha\n" + " nop\n" + " movec %%d0,%%tc\n" + " nop\n" + /* the following setup of transparent translations is needed on the + * Afterburner040 to successfully reboot. Other machines shouldn't + * care about a different tt regs setup, they also didn't care in + * the past that the regs weren't turned off. */ + " move.l #0xffc000,%%d0\n" /* whole insn space cacheable */ + " movec %%d0,%%itt0\n" + " movec %%d0,%%itt1\n" + " or.w #0x40,%/d0\n" /* whole data space non-cacheable/ser. */ + " movec %%d0,%%dtt0\n" + " movec %%d0,%%dtt1\n" + " .chip 68k\n" + " jmp %0@" + : /* no outputs */ + : "a" (reset_addr) + : "d0"); + } else + asm volatile ("\n" + " pmove %0@,%%tc\n" + " jmp %1@" + : /* no outputs */ + : "a" (&tc_val), "a" (reset_addr)); } static void atari_get_model(char *model) { - strcpy(model, "Atari "); - switch (atari_mch_cookie >> 16) { + strcpy(model, "Atari "); + switch (atari_mch_cookie >> 16) { case ATARI_MCH_ST: - if (ATARIHW_PRESENT(MSTE_CLK)) - strcat (model, "Mega ST"); - else - strcat (model, "ST"); - break; + if (ATARIHW_PRESENT(MSTE_CLK)) + strcat(model, "Mega ST"); + else + strcat(model, "ST"); + break; case ATARI_MCH_STE: - if (MACH_IS_MSTE) - strcat (model, "Mega STE"); - else - strcat (model, "STE"); - break; + if (MACH_IS_MSTE) + strcat(model, "Mega STE"); + else + strcat(model, "STE"); + break; case ATARI_MCH_TT: - if (MACH_IS_MEDUSA) - /* Medusa has TT _MCH cookie */ - strcat (model, "Medusa"); - else if (MACH_IS_HADES) - strcat(model, "Hades"); - else - strcat (model, "TT"); - break; + if (MACH_IS_MEDUSA) + /* Medusa has TT _MCH cookie */ + strcat(model, "Medusa"); + else if (MACH_IS_HADES) + strcat(model, "Hades"); + else + strcat(model, "TT"); + break; case ATARI_MCH_FALCON: - strcat (model, "Falcon"); - if (MACH_IS_AB40) - strcat (model, " (with Afterburner040)"); - break; + strcat(model, "Falcon"); + if (MACH_IS_AB40) + strcat(model, " (with Afterburner040)"); + break; default: - sprintf (model + strlen (model), "(unknown mach cookie 0x%lx)", - atari_mch_cookie); - break; - } + sprintf(model + strlen(model), "(unknown mach cookie 0x%lx)", + atari_mch_cookie); + break; + } } static int atari_get_hardware_list(char *buffer) { - int len = 0, i; - - for (i = 0; i < m68k_num_memory; i++) - len += sprintf (buffer+len, "\t%3ld MB at 0x%08lx (%s)\n", - m68k_memory[i].size >> 20, m68k_memory[i].addr, - (m68k_memory[i].addr & 0xff000000 ? - "alternate RAM" : "ST-RAM")); - -#define ATARIHW_ANNOUNCE(name,str) \ - if (ATARIHW_PRESENT(name)) \ - len += sprintf (buffer + len, "\t%s\n", str) - - len += sprintf (buffer + len, "Detected hardware:\n"); - ATARIHW_ANNOUNCE(STND_SHIFTER, "ST Shifter"); - ATARIHW_ANNOUNCE(EXTD_SHIFTER, "STe Shifter"); - ATARIHW_ANNOUNCE(TT_SHIFTER, "TT Shifter"); - ATARIHW_ANNOUNCE(VIDEL_SHIFTER, "Falcon Shifter"); - ATARIHW_ANNOUNCE(YM_2149, "Programmable Sound Generator"); - ATARIHW_ANNOUNCE(PCM_8BIT, "PCM 8 Bit Sound"); - ATARIHW_ANNOUNCE(CODEC, "CODEC Sound"); - ATARIHW_ANNOUNCE(TT_SCSI, "SCSI Controller NCR5380 (TT style)"); - ATARIHW_ANNOUNCE(ST_SCSI, "SCSI Controller NCR5380 (Falcon style)"); - ATARIHW_ANNOUNCE(ACSI, "ACSI Interface"); - ATARIHW_ANNOUNCE(IDE, "IDE Interface"); - ATARIHW_ANNOUNCE(FDCSPEED, "8/16 Mhz Switch for FDC"); - ATARIHW_ANNOUNCE(ST_MFP, "Multi Function Peripheral MFP 68901"); - ATARIHW_ANNOUNCE(TT_MFP, "Second Multi Function Peripheral MFP 68901"); - ATARIHW_ANNOUNCE(SCC, "Serial Communications Controller SCC 8530"); - ATARIHW_ANNOUNCE(ST_ESCC, "Extended Serial Communications Controller SCC 85230"); - ATARIHW_ANNOUNCE(ANALOG_JOY, "Paddle Interface"); - ATARIHW_ANNOUNCE(MICROWIRE, "MICROWIRE(tm) Interface"); - ATARIHW_ANNOUNCE(STND_DMA, "DMA Controller (24 bit)"); - ATARIHW_ANNOUNCE(EXTD_DMA, "DMA Controller (32 bit)"); - ATARIHW_ANNOUNCE(SCSI_DMA, "DMA Controller for NCR5380"); - ATARIHW_ANNOUNCE(SCC_DMA, "DMA Controller for SCC"); - ATARIHW_ANNOUNCE(TT_CLK, "Clock Chip MC146818A"); - ATARIHW_ANNOUNCE(MSTE_CLK, "Clock Chip RP5C15"); - ATARIHW_ANNOUNCE(SCU, "System Control Unit"); - ATARIHW_ANNOUNCE(BLITTER, "Blitter"); - ATARIHW_ANNOUNCE(VME, "VME Bus"); - ATARIHW_ANNOUNCE(DSP56K, "DSP56001 processor"); - - return(len); + int len = 0, i; + + for (i = 0; i < m68k_num_memory; i++) + len += sprintf(buffer+len, "\t%3ld MB at 0x%08lx (%s)\n", + m68k_memory[i].size >> 20, m68k_memory[i].addr, + (m68k_memory[i].addr & 0xff000000 ? + "alternate RAM" : "ST-RAM")); + +#define ATARIHW_ANNOUNCE(name, str) \ + if (ATARIHW_PRESENT(name)) \ + len += sprintf(buffer + len, "\t%s\n", str) + + len += sprintf(buffer + len, "Detected hardware:\n"); + ATARIHW_ANNOUNCE(STND_SHIFTER, "ST Shifter"); + ATARIHW_ANNOUNCE(EXTD_SHIFTER, "STe Shifter"); + ATARIHW_ANNOUNCE(TT_SHIFTER, "TT Shifter"); + ATARIHW_ANNOUNCE(VIDEL_SHIFTER, "Falcon Shifter"); + ATARIHW_ANNOUNCE(YM_2149, "Programmable Sound Generator"); + ATARIHW_ANNOUNCE(PCM_8BIT, "PCM 8 Bit Sound"); + ATARIHW_ANNOUNCE(CODEC, "CODEC Sound"); + ATARIHW_ANNOUNCE(TT_SCSI, "SCSI Controller NCR5380 (TT style)"); + ATARIHW_ANNOUNCE(ST_SCSI, "SCSI Controller NCR5380 (Falcon style)"); + ATARIHW_ANNOUNCE(ACSI, "ACSI Interface"); + ATARIHW_ANNOUNCE(IDE, "IDE Interface"); + ATARIHW_ANNOUNCE(FDCSPEED, "8/16 Mhz Switch for FDC"); + ATARIHW_ANNOUNCE(ST_MFP, "Multi Function Peripheral MFP 68901"); + ATARIHW_ANNOUNCE(TT_MFP, "Second Multi Function Peripheral MFP 68901"); + ATARIHW_ANNOUNCE(SCC, "Serial Communications Controller SCC 8530"); + ATARIHW_ANNOUNCE(ST_ESCC, "Extended Serial Communications Controller SCC 85230"); + ATARIHW_ANNOUNCE(ANALOG_JOY, "Paddle Interface"); + ATARIHW_ANNOUNCE(MICROWIRE, "MICROWIRE(tm) Interface"); + ATARIHW_ANNOUNCE(STND_DMA, "DMA Controller (24 bit)"); + ATARIHW_ANNOUNCE(EXTD_DMA, "DMA Controller (32 bit)"); + ATARIHW_ANNOUNCE(SCSI_DMA, "DMA Controller for NCR5380"); + ATARIHW_ANNOUNCE(SCC_DMA, "DMA Controller for SCC"); + ATARIHW_ANNOUNCE(TT_CLK, "Clock Chip MC146818A"); + ATARIHW_ANNOUNCE(MSTE_CLK, "Clock Chip RP5C15"); + ATARIHW_ANNOUNCE(SCU, "System Control Unit"); + ATARIHW_ANNOUNCE(BLITTER, "Blitter"); + ATARIHW_ANNOUNCE(VME, "VME Bus"); + ATARIHW_ANNOUNCE(DSP56K, "DSP56001 processor"); + + return len; } - -/* - * Local variables: - * c-indent-level: 4 - * tab-width: 8 - * End: - */ diff --git a/arch/m68k/atari/debug.c b/arch/m68k/atari/debug.c index 4ae01004d8d..fbeed8c8ecb 100644 --- a/arch/m68k/atari/debug.c +++ b/arch/m68k/atari/debug.c @@ -19,8 +19,6 @@ #include <asm/atarihw.h> #include <asm/atariints.h> -extern char m68k_debug_device[]; - /* Flag that Modem1 port is already initialized and used */ int atari_MFP_init_done; /* Flag that Modem1 port is already initialized and used */ @@ -30,317 +28,317 @@ int atari_SCC_init_done; int atari_SCC_reset_done; static struct console atari_console_driver = { - .name = "debug", - .flags = CON_PRINTBUFFER, - .index = -1, + .name = "debug", + .flags = CON_PRINTBUFFER, + .index = -1, }; -static inline void ata_mfp_out (char c) +static inline void ata_mfp_out(char c) { - while (!(mfp.trn_stat & 0x80)) /* wait for tx buf empty */ - barrier (); - mfp.usart_dta = c; + while (!(mfp.trn_stat & 0x80)) /* wait for tx buf empty */ + barrier(); + mfp.usart_dta = c; } -void atari_mfp_console_write (struct console *co, const char *str, - unsigned int count) +void atari_mfp_console_write(struct console *co, const char *str, + unsigned int count) { - while (count--) { - if (*str == '\n') - ata_mfp_out( '\r' ); - ata_mfp_out( *str++ ); - } + while (count--) { + if (*str == '\n') + ata_mfp_out('\r'); + ata_mfp_out(*str++); + } } -static inline void ata_scc_out (char c) +static inline void ata_scc_out(char c) { - do { + do { + MFPDELAY(); + } while (!(scc.cha_b_ctrl & 0x04)); /* wait for tx buf empty */ MFPDELAY(); - } while (!(scc.cha_b_ctrl & 0x04)); /* wait for tx buf empty */ - MFPDELAY(); - scc.cha_b_data = c; + scc.cha_b_data = c; } -void atari_scc_console_write (struct console *co, const char *str, - unsigned int count) +void atari_scc_console_write(struct console *co, const char *str, + unsigned int count) { - while (count--) { - if (*str == '\n') - ata_scc_out( '\r' ); - ata_scc_out( *str++ ); - } + while (count--) { + if (*str == '\n') + ata_scc_out('\r'); + ata_scc_out(*str++); + } } -static inline void ata_midi_out (char c) +static inline void ata_midi_out(char c) { - while (!(acia.mid_ctrl & ACIA_TDRE)) /* wait for tx buf empty */ - barrier (); - acia.mid_data = c; + while (!(acia.mid_ctrl & ACIA_TDRE)) /* wait for tx buf empty */ + barrier(); + acia.mid_data = c; } -void atari_midi_console_write (struct console *co, const char *str, - unsigned int count) +void atari_midi_console_write(struct console *co, const char *str, + unsigned int count) { - while (count--) { - if (*str == '\n') - ata_midi_out( '\r' ); - ata_midi_out( *str++ ); - } + while (count--) { + if (*str == '\n') + ata_midi_out('\r'); + ata_midi_out(*str++); + } } -static int ata_par_out (char c) +static int ata_par_out(char c) { - unsigned char tmp; - /* This a some-seconds timeout in case no printer is connected */ - unsigned long i = loops_per_jiffy > 1 ? loops_per_jiffy : 10000000/HZ; - - while( (mfp.par_dt_reg & 1) && --i ) /* wait for BUSY == L */ - ; - if (!i) return( 0 ); - - sound_ym.rd_data_reg_sel = 15; /* select port B */ - sound_ym.wd_data = c; /* put char onto port */ - sound_ym.rd_data_reg_sel = 14; /* select port A */ - tmp = sound_ym.rd_data_reg_sel; - sound_ym.wd_data = tmp & ~0x20; /* set strobe L */ - MFPDELAY(); /* wait a bit */ - sound_ym.wd_data = tmp | 0x20; /* set strobe H */ - return( 1 ); + unsigned char tmp; + /* This a some-seconds timeout in case no printer is connected */ + unsigned long i = loops_per_jiffy > 1 ? loops_per_jiffy : 10000000/HZ; + + while ((mfp.par_dt_reg & 1) && --i) /* wait for BUSY == L */ + ; + if (!i) + return 0; + + sound_ym.rd_data_reg_sel = 15; /* select port B */ + sound_ym.wd_data = c; /* put char onto port */ + sound_ym.rd_data_reg_sel = 14; /* select port A */ + tmp = sound_ym.rd_data_reg_sel; + sound_ym.wd_data = tmp & ~0x20; /* set strobe L */ + MFPDELAY(); /* wait a bit */ + sound_ym.wd_data = tmp | 0x20; /* set strobe H */ + return 1; } -static void atari_par_console_write (struct console *co, const char *str, - unsigned int count) +static void atari_par_console_write(struct console *co, const char *str, + unsigned int count) { - static int printer_present = 1; + static int printer_present = 1; - if (!printer_present) - return; - - while (count--) { - if (*str == '\n') - if (!ata_par_out( '\r' )) { - printer_present = 0; + if (!printer_present) return; - } - if (!ata_par_out( *str++ )) { - printer_present = 0; - return; + + while (count--) { + if (*str == '\n') { + if (!ata_par_out('\r')) { + printer_present = 0; + return; + } + } + if (!ata_par_out(*str++)) { + printer_present = 0; + return; + } } - } } #ifdef CONFIG_SERIAL_CONSOLE int atari_mfp_console_wait_key(struct console *co) { - while( !(mfp.rcv_stat & 0x80) ) /* wait for rx buf filled */ - barrier(); - return( mfp.usart_dta ); + while (!(mfp.rcv_stat & 0x80)) /* wait for rx buf filled */ + barrier(); + return mfp.usart_dta; } int atari_scc_console_wait_key(struct console *co) { - do { + do { + MFPDELAY(); + } while (!(scc.cha_b_ctrl & 0x01)); /* wait for rx buf filled */ MFPDELAY(); - } while( !(scc.cha_b_ctrl & 0x01) ); /* wait for rx buf filled */ - MFPDELAY(); - return( scc.cha_b_data ); + return scc.cha_b_data; } int atari_midi_console_wait_key(struct console *co) { - while( !(acia.mid_ctrl & ACIA_RDRF) ) /* wait for rx buf filled */ - barrier(); - return( acia.mid_data ); + while (!(acia.mid_ctrl & ACIA_RDRF)) /* wait for rx buf filled */ + barrier(); + return acia.mid_data; } #endif -/* The following two functions do a quick'n'dirty initialization of the MFP or +/* + * The following two functions do a quick'n'dirty initialization of the MFP or * SCC serial ports. They're used by the debugging interface, kgdb, and the - * serial console code. */ + * serial console code. + */ #ifndef CONFIG_SERIAL_CONSOLE -static void __init atari_init_mfp_port( int cflag ) +static void __init atari_init_mfp_port(int cflag) #else -void atari_init_mfp_port( int cflag ) +void atari_init_mfp_port(int cflag) #endif { - /* timer values for 1200...115200 bps; > 38400 select 110, 134, or 150 - * bps, resp., and work only correct if there's a RSVE or RSSPEED */ - static int baud_table[9] = { 16, 11, 8, 4, 2, 1, 175, 143, 128 }; - int baud = cflag & CBAUD; - int parity = (cflag & PARENB) ? ((cflag & PARODD) ? 0x04 : 0x06) : 0; - int csize = ((cflag & CSIZE) == CS7) ? 0x20 : 0x00; - - if (cflag & CBAUDEX) - baud += B38400; - if (baud < B1200 || baud > B38400+2) - baud = B9600; /* use default 9600bps for non-implemented rates */ - baud -= B1200; /* baud_table[] starts at 1200bps */ - - mfp.trn_stat &= ~0x01; /* disable TX */ - mfp.usart_ctr = parity | csize | 0x88; /* 1:16 clk mode, 1 stop bit */ - mfp.tim_ct_cd &= 0x70; /* stop timer D */ - mfp.tim_dt_d = baud_table[baud]; - mfp.tim_ct_cd |= 0x01; /* start timer D, 1:4 */ - mfp.trn_stat |= 0x01; /* enable TX */ - - atari_MFP_init_done = 1; + /* + * timer values for 1200...115200 bps; > 38400 select 110, 134, or 150 + * bps, resp., and work only correct if there's a RSVE or RSSPEED + */ + static int baud_table[9] = { 16, 11, 8, 4, 2, 1, 175, 143, 128 }; + int baud = cflag & CBAUD; + int parity = (cflag & PARENB) ? ((cflag & PARODD) ? 0x04 : 0x06) : 0; + int csize = ((cflag & CSIZE) == CS7) ? 0x20 : 0x00; + + if (cflag & CBAUDEX) + baud += B38400; + if (baud < B1200 || baud > B38400+2) + baud = B9600; /* use default 9600bps for non-implemented rates */ + baud -= B1200; /* baud_table[] starts at 1200bps */ + + mfp.trn_stat &= ~0x01; /* disable TX */ + mfp.usart_ctr = parity | csize | 0x88; /* 1:16 clk mode, 1 stop bit */ + mfp.tim_ct_cd &= 0x70; /* stop timer D */ + mfp.tim_dt_d = baud_table[baud]; + mfp.tim_ct_cd |= 0x01; /* start timer D, 1:4 */ + mfp.trn_stat |= 0x01; /* enable TX */ + + atari_MFP_init_done = 1; } -#define SCC_WRITE(reg,val) \ - do { \ - scc.cha_b_ctrl = (reg); \ - MFPDELAY(); \ - scc.cha_b_ctrl = (val); \ - MFPDELAY(); \ - } while(0) +#define SCC_WRITE(reg, val) \ + do { \ + scc.cha_b_ctrl = (reg); \ + MFPDELAY(); \ + scc.cha_b_ctrl = (val); \ + MFPDELAY(); \ + } while (0) /* loops_per_jiffy isn't initialized yet, so we can't use udelay(). This does a * delay of ~ 60us. */ -#define LONG_DELAY() \ - do { \ - int i; \ - for( i = 100; i > 0; --i ) \ - MFPDELAY(); \ - } while(0) +#define LONG_DELAY() \ + do { \ + int i; \ + for (i = 100; i > 0; --i) \ + MFPDELAY(); \ + } while (0) #ifndef CONFIG_SERIAL_CONSOLE -static void __init atari_init_scc_port( int cflag ) +static void __init atari_init_scc_port(int cflag) #else -void atari_init_scc_port( int cflag ) +void atari_init_scc_port(int cflag) #endif { - extern int atari_SCC_reset_done; - static int clksrc_table[9] = - /* reg 11: 0x50 = BRG, 0x00 = RTxC, 0x28 = TRxC */ - { 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x00, 0x00 }; - static int brgsrc_table[9] = - /* reg 14: 0 = RTxC, 2 = PCLK */ - { 2, 2, 2, 2, 2, 2, 0, 2, 2 }; - static int clkmode_table[9] = - /* reg 4: 0x40 = x16, 0x80 = x32, 0xc0 = x64 */ - { 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0xc0, 0x80 }; - static int div_table[9] = - /* reg12 (BRG low) */ - { 208, 138, 103, 50, 24, 11, 1, 0, 0 }; - - int baud = cflag & CBAUD; - int clksrc, clkmode, div, reg3, reg5; - - if (cflag & CBAUDEX) - baud += B38400; - if (baud < B1200 || baud > B38400+2) - baud = B9600; /* use default 9600bps for non-implemented rates */ - baud -= B1200; /* tables starts at 1200bps */ - - clksrc = clksrc_table[baud]; - clkmode = clkmode_table[baud]; - div = div_table[baud]; - if (ATARIHW_PRESENT(TT_MFP) && baud >= 6) { - /* special treatment for TT, where rates >= 38400 are done via TRxC */ - clksrc = 0x28; /* TRxC */ - clkmode = baud == 6 ? 0xc0 : - baud == 7 ? 0x80 : /* really 76800bps */ - 0x40; /* really 153600bps */ - div = 0; - } - - reg3 = (cflag & CSIZE) == CS8 ? 0xc0 : 0x40; - reg5 = (cflag & CSIZE) == CS8 ? 0x60 : 0x20 | 0x82 /* assert DTR/RTS */; - - (void)scc.cha_b_ctrl; /* reset reg pointer */ - SCC_WRITE( 9, 0xc0 ); /* reset */ - LONG_DELAY(); /* extra delay after WR9 access */ - SCC_WRITE( 4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03) : 0 | - 0x04 /* 1 stopbit */ | - clkmode ); - SCC_WRITE( 3, reg3 ); - SCC_WRITE( 5, reg5 ); - SCC_WRITE( 9, 0 ); /* no interrupts */ - LONG_DELAY(); /* extra delay after WR9 access */ - SCC_WRITE( 10, 0 ); /* NRZ mode */ - SCC_WRITE( 11, clksrc ); /* main clock source */ - SCC_WRITE( 12, div ); /* BRG value */ - SCC_WRITE( 13, 0 ); /* BRG high byte */ - SCC_WRITE( 14, brgsrc_table[baud] ); - SCC_WRITE( 14, brgsrc_table[baud] | (div ? 1 : 0) ); - SCC_WRITE( 3, reg3 | 1 ); - SCC_WRITE( 5, reg5 | 8 ); - - atari_SCC_reset_done = 1; - atari_SCC_init_done = 1; + extern int atari_SCC_reset_done; + static int clksrc_table[9] = + /* reg 11: 0x50 = BRG, 0x00 = RTxC, 0x28 = TRxC */ + { 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x00, 0x00 }; + static int brgsrc_table[9] = + /* reg 14: 0 = RTxC, 2 = PCLK */ + { 2, 2, 2, 2, 2, 2, 0, 2, 2 }; + static int clkmode_table[9] = + /* reg 4: 0x40 = x16, 0x80 = x32, 0xc0 = x64 */ + { 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0xc0, 0x80 }; + static int div_table[9] = + /* reg12 (BRG low) */ + { 208, 138, 103, 50, 24, 11, 1, 0, 0 }; + + int baud = cflag & CBAUD; + int clksrc, clkmode, div, reg3, reg5; + + if (cflag & CBAUDEX) + baud += B38400; + if (baud < B1200 || baud > B38400+2) + baud = B9600; /* use default 9600bps for non-implemented rates */ + baud -= B1200; /* tables starts at 1200bps */ + + clksrc = clksrc_table[baud]; + clkmode = clkmode_table[baud]; + div = div_table[baud]; + if (ATARIHW_PRESENT(TT_MFP) && baud >= 6) { + /* special treatment for TT, where rates >= 38400 are done via TRxC */ + clksrc = 0x28; /* TRxC */ + clkmode = baud == 6 ? 0xc0 : + baud == 7 ? 0x80 : /* really 76800bps */ + 0x40; /* really 153600bps */ + div = 0; + } + + reg3 = (cflag & CSIZE) == CS8 ? 0xc0 : 0x40; + reg5 = (cflag & CSIZE) == CS8 ? 0x60 : 0x20 | 0x82 /* assert DTR/RTS */; + + (void)scc.cha_b_ctrl; /* reset reg pointer */ + SCC_WRITE(9, 0xc0); /* reset */ + LONG_DELAY(); /* extra delay after WR9 access */ + SCC_WRITE(4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03) + : 0 | 0x04 /* 1 stopbit */ | clkmode); + SCC_WRITE(3, reg3); + SCC_WRITE(5, reg5); + SCC_WRITE(9, 0); /* no interrupts */ + LONG_DELAY(); /* extra delay after WR9 access */ + SCC_WRITE(10, 0); /* NRZ mode */ + SCC_WRITE(11, clksrc); /* main clock source */ + SCC_WRITE(12, div); /* BRG value */ + SCC_WRITE(13, 0); /* BRG high byte */ + SCC_WRITE(14, brgsrc_table[baud]); + SCC_WRITE(14, brgsrc_table[baud] | (div ? 1 : 0)); + SCC_WRITE(3, reg3 | 1); + SCC_WRITE(5, reg5 | 8); + + atari_SCC_reset_done = 1; + atari_SCC_init_done = 1; } #ifndef CONFIG_SERIAL_CONSOLE -static void __init atari_init_midi_port( int cflag ) +static void __init atari_init_midi_port(int cflag) #else -void atari_init_midi_port( int cflag ) +void atari_init_midi_port(int cflag) #endif { - int baud = cflag & CBAUD; - int csize = ((cflag & CSIZE) == CS8) ? 0x10 : 0x00; - /* warning 7N1 isn't possible! (instead 7O2 is used...) */ - int parity = (cflag & PARENB) ? ((cflag & PARODD) ? 0x0c : 0x08) : 0x04; - int div; - - /* 4800 selects 7812.5, 115200 selects 500000, all other (incl. 9600 as - * default) the standard MIDI speed 31250. */ - if (cflag & CBAUDEX) - baud += B38400; - if (baud == B4800) - div = ACIA_DIV64; /* really 7812.5 bps */ - else if (baud == B38400+2 /* 115200 */) - div = ACIA_DIV1; /* really 500 kbps (does that work??) */ - else - div = ACIA_DIV16; /* 31250 bps, standard for MIDI */ - - /* RTS low, ints disabled */ - acia.mid_ctrl = div | csize | parity | + int baud = cflag & CBAUD; + int csize = ((cflag & CSIZE) == CS8) ? 0x10 : 0x00; + /* warning 7N1 isn't possible! (instead 7O2 is used...) */ + int parity = (cflag & PARENB) ? ((cflag & PARODD) ? 0x0c : 0x08) : 0x04; + int div; + + /* 4800 selects 7812.5, 115200 selects 500000, all other (incl. 9600 as + * default) the standard MIDI speed 31250. */ + if (cflag & CBAUDEX) + baud += B38400; + if (baud == B4800) + div = ACIA_DIV64; /* really 7812.5 bps */ + else if (baud == B38400+2 /* 115200 */) + div = ACIA_DIV1; /* really 500 kbps (does that work??) */ + else + div = ACIA_DIV16; /* 31250 bps, standard for MIDI */ + + /* RTS low, ints disabled */ + acia.mid_ctrl = div | csize | parity | ((atari_switches & ATARI_SWITCH_MIDI) ? ACIA_RHTID : ACIA_RLTID); } -void __init atari_debug_init(void) +static int __init atari_debug_setup(char *arg) { - if (!strcmp( m68k_debug_device, "ser" )) { - /* defaults to ser2 for a Falcon and ser1 otherwise */ - strcpy( m68k_debug_device, MACH_IS_FALCON ? "ser2" : "ser1" ); - - } - - if (!strcmp( m68k_debug_device, "ser1" )) { - /* ST-MFP Modem1 serial port */ - atari_init_mfp_port( B9600|CS8 ); - atari_console_driver.write = atari_mfp_console_write; - } - else if (!strcmp( m68k_debug_device, "ser2" )) { - /* SCC Modem2 serial port */ - atari_init_scc_port( B9600|CS8 ); - atari_console_driver.write = atari_scc_console_write; - } - else if (!strcmp( m68k_debug_device, "midi" )) { - /* MIDI port */ - atari_init_midi_port( B9600|CS8 ); - atari_console_driver.write = atari_midi_console_write; - } - else if (!strcmp( m68k_debug_device, "par" )) { - /* parallel printer */ - atari_turnoff_irq( IRQ_MFP_BUSY ); /* avoid ints */ - sound_ym.rd_data_reg_sel = 7; /* select mixer control */ - sound_ym.wd_data = 0xff; /* sound off, ports are output */ - sound_ym.rd_data_reg_sel = 15; /* select port B */ - sound_ym.wd_data = 0; /* no char */ - sound_ym.rd_data_reg_sel = 14; /* select port A */ - sound_ym.wd_data = sound_ym.rd_data_reg_sel | 0x20; /* strobe H */ - atari_console_driver.write = atari_par_console_write; - } - if (atari_console_driver.write) - register_console(&atari_console_driver); + if (!MACH_IS_ATARI) + return 0; + + if (!strcmp(arg, "ser")) + /* defaults to ser2 for a Falcon and ser1 otherwise */ + arg = MACH_IS_FALCON ? "ser2" : "ser1"; + + if (!strcmp(arg, "ser1")) { + /* ST-MFP Modem1 serial port */ + atari_init_mfp_port(B9600|CS8); + atari_console_driver.write = atari_mfp_console_write; + } else if (!strcmp(arg, "ser2")) { + /* SCC Modem2 serial port */ + atari_init_scc_port(B9600|CS8); + atari_console_driver.write = atari_scc_console_write; + } else if (!strcmp(arg, "midi")) { + /* MIDI port */ + atari_init_midi_port(B9600|CS8); + atari_console_driver.write = atari_midi_console_write; + } else if (!strcmp(arg, "par")) { + /* parallel printer */ + atari_turnoff_irq(IRQ_MFP_BUSY); /* avoid ints */ + sound_ym.rd_data_reg_sel = 7; /* select mixer control */ + sound_ym.wd_data = 0xff; /* sound off, ports are output */ + sound_ym.rd_data_reg_sel = 15; /* select port B */ + sound_ym.wd_data = 0; /* no char */ + sound_ym.rd_data_reg_sel = 14; /* select port A */ + sound_ym.wd_data = sound_ym.rd_data_reg_sel | 0x20; /* strobe H */ + atari_console_driver.write = atari_par_console_write; + } + if (atari_console_driver.write) + register_console(&atari_console_driver); + + return 0; } -/* - * Local variables: - * c-indent-level: 4 - * tab-width: 8 - * End: - */ +early_param("debug", atari_debug_setup); diff --git a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S index 222ce424456..e162ee685d2 100644 --- a/arch/m68k/kernel/entry.S +++ b/arch/m68k/kernel/entry.S @@ -692,7 +692,7 @@ sys_call_table: .long sys_tgkill /* 265 */ .long sys_utimes .long sys_fadvise64_64 - .long sys_mbind + .long sys_mbind .long sys_get_mempolicy .long sys_set_mempolicy /* 270 */ .long sys_mq_open diff --git a/arch/m68k/kernel/head.S b/arch/m68k/kernel/head.S index 6739e87fe82..05741f23356 100644 --- a/arch/m68k/kernel/head.S +++ b/arch/m68k/kernel/head.S @@ -3195,7 +3195,7 @@ func_start serial_putc,%d0/%d1/%a0/%a1 jbra L(serial_putc_done) 3: #endif - + L(serial_putc_done): func_return serial_putc diff --git a/arch/m68k/kernel/setup.c b/arch/m68k/kernel/setup.c index 42b8fd09ea8..61031935669 100644 --- a/arch/m68k/kernel/setup.c +++ b/arch/m68k/kernel/setup.c @@ -71,9 +71,6 @@ static struct mem_info m68k_ramdisk; static char m68k_command_line[CL_SIZE]; -char m68k_debug_device[6] = ""; -EXPORT_SYMBOL(m68k_debug_device); - void (*mach_sched_init) (irq_handler_t handler) __initdata = NULL; /* machine dependent irq functions */ void (*mach_init_IRQ) (void) __initdata = NULL; @@ -133,78 +130,78 @@ extern void config_hp300(void); extern void config_q40(void); extern void config_sun3x(void); -extern void mac_debugging_short (int, short); -extern void mac_debugging_long (int, long); - #define MASK_256K 0xfffc0000 extern void paging_init(void); static void __init m68k_parse_bootinfo(const struct bi_record *record) { - while (record->tag != BI_LAST) { - int unknown = 0; - const unsigned long *data = record->data; - switch (record->tag) { - case BI_MACHTYPE: - case BI_CPUTYPE: - case BI_FPUTYPE: - case BI_MMUTYPE: - /* Already set up by head.S */ - break; - - case BI_MEMCHUNK: - if (m68k_num_memory < NUM_MEMINFO) { - m68k_memory[m68k_num_memory].addr = data[0]; - m68k_memory[m68k_num_memory].size = data[1]; - m68k_num_memory++; - } else - printk("m68k_parse_bootinfo: too many memory chunks\n"); - break; - - case BI_RAMDISK: - m68k_ramdisk.addr = data[0]; - m68k_ramdisk.size = data[1]; - break; - - case BI_COMMAND_LINE: - strlcpy(m68k_command_line, (const char *)data, sizeof(m68k_command_line)); - break; - - default: - if (MACH_IS_AMIGA) - unknown = amiga_parse_bootinfo(record); - else if (MACH_IS_ATARI) - unknown = atari_parse_bootinfo(record); - else if (MACH_IS_MAC) - unknown = mac_parse_bootinfo(record); - else if (MACH_IS_Q40) - unknown = q40_parse_bootinfo(record); - else if (MACH_IS_BVME6000) - unknown = bvme6000_parse_bootinfo(record); - else if (MACH_IS_MVME16x) - unknown = mvme16x_parse_bootinfo(record); - else if (MACH_IS_MVME147) - unknown = mvme147_parse_bootinfo(record); - else if (MACH_IS_HP300) - unknown = hp300_parse_bootinfo(record); - else - unknown = 1; + while (record->tag != BI_LAST) { + int unknown = 0; + const unsigned long *data = record->data; + + switch (record->tag) { + case BI_MACHTYPE: + case BI_CPUTYPE: + case BI_FPUTYPE: + case BI_MMUTYPE: + /* Already set up by head.S */ + break; + + case BI_MEMCHUNK: + if (m68k_num_memory < NUM_MEMINFO) { + m68k_memory[m68k_num_memory].addr = data[0]; + m68k_memory[m68k_num_memory].size = data[1]; + m68k_num_memory++; + } else + printk("m68k_parse_bootinfo: too many memory chunks\n"); + break; + + case BI_RAMDISK: + m68k_ramdisk.addr = data[0]; + m68k_ramdisk.size = data[1]; + break; + + case BI_COMMAND_LINE: + strlcpy(m68k_command_line, (const char *)data, + sizeof(m68k_command_line)); + break; + + default: + if (MACH_IS_AMIGA) + unknown = amiga_parse_bootinfo(record); + else if (MACH_IS_ATARI) + unknown = atari_parse_bootinfo(record); + else if (MACH_IS_MAC) + unknown = mac_parse_bootinfo(record); + else if (MACH_IS_Q40) + unknown = q40_parse_bootinfo(record); + else if (MACH_IS_BVME6000) + unknown = bvme6000_parse_bootinfo(record); + else if (MACH_IS_MVME16x) + unknown = mvme16x_parse_bootinfo(record); + else if (MACH_IS_MVME147) + unknown = mvme147_parse_bootinfo(record); + else if (MACH_IS_HP300) + unknown = hp300_parse_bootinfo(record); + else + unknown = 1; + } + if (unknown) + printk("m68k_parse_bootinfo: unknown tag 0x%04x ignored\n", + record->tag); + record = (struct bi_record *)((unsigned long)record + + record->size); } - if (unknown) - printk("m68k_parse_bootinfo: unknown tag 0x%04x ignored\n", - record->tag); - record = (struct bi_record *)((unsigned long)record+record->size); - } - m68k_realnum_memory = m68k_num_memory; + m68k_realnum_memory = m68k_num_memory; #ifdef CONFIG_SINGLE_MEMORY_CHUNK - if (m68k_num_memory > 1) { - printk("Ignoring last %i chunks of physical memory\n", - (m68k_num_memory - 1)); - m68k_num_memory = 1; - } - m68k_memoffset = m68k_memory[0].addr-PAGE_OFFSET; + if (m68k_num_memory > 1) { + printk("Ignoring last %i chunks of physical memory\n", + (m68k_num_memory - 1)); + m68k_num_memory = 1; + } + m68k_memoffset = m68k_memory[0].addr-PAGE_OFFSET; #endif } @@ -215,7 +212,6 @@ void __init setup_arch(char **cmdline_p) unsigned long endmem, startmem; #endif int i; - char *p, *q; /* The bootinfo is located right after the kernel bss */ m68k_parse_bootinfo((const struct bi_record *)&_end); @@ -234,7 +230,7 @@ void __init setup_arch(char **cmdline_p) /* clear the fpu if we have one */ if (m68k_fputype & (FPU_68881|FPU_68882|FPU_68040|FPU_68060)) { volatile int zero = 0; - asm __volatile__ ("frestore %0" : : "m" (zero)); + asm volatile ("frestore %0" : : "m" (zero)); } #endif @@ -258,37 +254,7 @@ void __init setup_arch(char **cmdline_p) *cmdline_p = m68k_command_line; memcpy(boot_command_line, *cmdline_p, CL_SIZE); - /* Parse the command line for arch-specific options. - * For the m68k, this is currently only "debug=xxx" to enable printing - * certain kernel messages to some machine-specific device. - */ - for( p = *cmdline_p; p && *p; ) { - i = 0; - if (!strncmp( p, "debug=", 6 )) { - strlcpy( m68k_debug_device, p+6, sizeof(m68k_debug_device) ); - if ((q = strchr( m68k_debug_device, ' ' ))) *q = 0; - i = 1; - } -#ifdef CONFIG_ATARI - /* This option must be parsed very early */ - if (!strncmp( p, "switches=", 9 )) { - extern void atari_switches_setup( const char *, int ); - atari_switches_setup( p+9, (q = strchr( p+9, ' ' )) ? - (q - (p+9)) : strlen(p+9) ); - i = 1; - } -#endif - - if (i) { - /* option processed, delete it */ - if ((q = strchr( p, ' ' ))) - strcpy( p, q+1 ); - else - *p = 0; - } else { - if ((p = strchr( p, ' ' ))) ++p; - } - } + parse_early_param(); #ifdef CONFIG_DUMMY_CONSOLE conswitchp = &dummy_con; @@ -296,62 +262,62 @@ void __init setup_arch(char **cmdline_p) switch (m68k_machtype) { #ifdef CONFIG_AMIGA - case MACH_AMIGA: + case MACH_AMIGA: config_amiga(); break; #endif #ifdef CONFIG_ATARI - case MACH_ATARI: + case MACH_ATARI: config_atari(); break; #endif #ifdef CONFIG_MAC - case MACH_MAC: + case MACH_MAC: config_mac(); break; #endif #ifdef CONFIG_SUN3 - case MACH_SUN3: + case MACH_SUN3: config_sun3(); break; #endif #ifdef CONFIG_APOLLO - case MACH_APOLLO: + case MACH_APOLLO: config_apollo(); break; #endif #ifdef CONFIG_MVME147 - case MACH_MVME147: + case MACH_MVME147: config_mvme147(); break; #endif #ifdef CONFIG_MVME16x - case MACH_MVME16x: + case MACH_MVME16x: config_mvme16x(); break; #endif #ifdef CONFIG_BVME6000 - case MACH_BVME6000: + case MACH_BVME6000: config_bvme6000(); break; #endif #ifdef CONFIG_HP300 - case MACH_HP300: + case MACH_HP300: config_hp300(); break; #endif #ifdef CONFIG_Q40 - case MACH_Q40: - config_q40(); + case MACH_Q40: + config_q40(); break; #endif #ifdef CONFIG_SUN3X - case MACH_SUN3X: + case MACH_SUN3X: config_sun3x(); break; #endif - default: - panic ("No configuration setup"); + default: + panic("No configuration setup"); } #ifndef CONFIG_SUN3 @@ -380,7 +346,7 @@ void __init setup_arch(char **cmdline_p) reserve_bootmem(m68k_ramdisk.addr, m68k_ramdisk.size); initrd_start = (unsigned long)phys_to_virt(m68k_ramdisk.addr); initrd_end = initrd_start + m68k_ramdisk.size; - printk ("initrd: %08lx - %08lx\n", initrd_start, initrd_end); + printk("initrd: %08lx - %08lx\n", initrd_start, initrd_end); } #endif @@ -402,18 +368,18 @@ void __init setup_arch(char **cmdline_p) #if defined(CONFIG_ISA) && defined(MULTI_ISA) #if defined(CONFIG_Q40) if (MACH_IS_Q40) { - isa_type = Q40_ISA; - isa_sex = 0; + isa_type = Q40_ISA; + isa_sex = 0; } #elif defined(CONFIG_GG2) - if (MACH_IS_AMIGA && AMIGAHW_PRESENT(GG2_ISA)){ - isa_type = GG2_ISA; - isa_sex = 0; + if (MACH_IS_AMIGA && AMIGAHW_PRESENT(GG2_ISA)) { + isa_type = GG2_ISA; + isa_sex = 0; } #elif defined(CONFIG_AMIGA_PCMCIA) - if (MACH_IS_AMIGA && AMIGAHW_PRESENT(PCMCIA)){ - isa_type = AG_ISA; - isa_sex = 1; + if (MACH_IS_AMIGA && AMIGAHW_PRESENT(PCMCIA)) { + isa_type = AG_ISA; + isa_sex = 1; } #endif #endif @@ -421,66 +387,66 @@ void __init setup_arch(char **cmdline_p) static int show_cpuinfo(struct seq_file *m, void *v) { - const char *cpu, *mmu, *fpu; - unsigned long clockfreq, clockfactor; + const char *cpu, *mmu, *fpu; + unsigned long clockfreq, clockfactor; #define LOOP_CYCLES_68020 (8) #define LOOP_CYCLES_68030 (8) #define LOOP_CYCLES_68040 (3) #define LOOP_CYCLES_68060 (1) - if (CPU_IS_020) { - cpu = "68020"; - clockfactor = LOOP_CYCLES_68020; - } else if (CPU_IS_030) { - cpu = "68030"; - clockfactor = LOOP_CYCLES_68030; - } else if (CPU_IS_040) { - cpu = "68040"; - clockfactor = LOOP_CYCLES_68040; - } else if (CPU_IS_060) { - cpu = "68060"; - clockfactor = LOOP_CYCLES_68060; - } else { - cpu = "680x0"; - clockfactor = 0; - } + if (CPU_IS_020) { + cpu = "68020"; + clockfactor = LOOP_CYCLES_68020; + } else if (CPU_IS_030) { + cpu = "68030"; + clockfactor = LOOP_CYCLES_68030; + } else if (CPU_IS_040) { + cpu = "68040"; + clockfactor = LOOP_CYCLES_68040; + } else if (CPU_IS_060) { + cpu = "68060"; + clockfactor = LOOP_CYCLES_68060; + } else { + cpu = "680x0"; + clockfactor = 0; + } #ifdef CONFIG_M68KFPU_EMU_ONLY - fpu="none(soft float)"; + fpu = "none(soft float)"; #else - if (m68k_fputype & FPU_68881) - fpu = "68881"; - else if (m68k_fputype & FPU_68882) - fpu = "68882"; - else if (m68k_fputype & FPU_68040) - fpu = "68040"; - else if (m68k_fputype & FPU_68060) - fpu = "68060"; - else if (m68k_fputype & FPU_SUNFPA) - fpu = "Sun FPA"; - else - fpu = "none"; + if (m68k_fputype & FPU_68881) + fpu = "68881"; + else if (m68k_fputype & FPU_68882) + fpu = "68882"; + else if (m68k_fputype & FPU_68040) + fpu = "68040"; + else if (m68k_fputype & FPU_68060) + fpu = "68060"; + else if (m68k_fputype & FPU_SUNFPA) + fpu = "Sun FPA"; + else + fpu = "none"; #endif - if (m68k_mmutype & MMU_68851) - mmu = "68851"; - else if (m68k_mmutype & MMU_68030) - mmu = "68030"; - else if (m68k_mmutype & MMU_68040) - mmu = "68040"; - else if (m68k_mmutype & MMU_68060) - mmu = "68060"; - else if (m68k_mmutype & MMU_SUN3) - mmu = "Sun-3"; - else if (m68k_mmutype & MMU_APOLLO) - mmu = "Apollo"; - else - mmu = "unknown"; - - clockfreq = loops_per_jiffy*HZ*clockfactor; - - seq_printf(m, "CPU:\t\t%s\n" + if (m68k_mmutype & MMU_68851) + mmu = "68851"; + else if (m68k_mmutype & MMU_68030) + mmu = "68030"; + else if (m68k_mmutype & MMU_68040) + mmu = "68040"; + else if (m68k_mmutype & MMU_68060) + mmu = "68060"; + else if (m68k_mmutype & MMU_SUN3) + mmu = "Sun-3"; + else if (m68k_mmutype & MMU_APOLLO) + mmu = "Apollo"; + else + mmu = "unknown"; + + clockfreq = loops_per_jiffy * HZ * clockfactor; + + seq_printf(m, "CPU:\t\t%s\n" "MMU:\t\t%s\n" "FPU:\t\t%s\n" "Clocking:\t%lu.%1luMHz\n" @@ -490,7 +456,7 @@ static int show_cpuinfo(struct seq_file *m, void *v) clockfreq/1000000,(clockfreq/100000)%10, loops_per_jiffy/(500000/HZ),(loops_per_jiffy/(5000/HZ))%100, loops_per_jiffy); - return 0; + return 0; } static void *c_start(struct seq_file *m, loff_t *pos) @@ -506,44 +472,54 @@ static void c_stop(struct seq_file *m, void *v) { } struct seq_operations cpuinfo_op = { - .start = c_start, - .next = c_next, - .stop = c_stop, - .show = show_cpuinfo, + .start = c_start, + .next = c_next, + .stop = c_stop, + .show = show_cpuinfo, }; int get_hardware_list(char *buffer) { - int len = 0; - char model[80]; - unsigned long mem; - int i; + int len = 0; + char model[80]; + unsigned long mem; + int i; - if (mach_get_model) - mach_get_model(model); - else - strcpy(model, "Unknown m68k"); + if (mach_get_model) + mach_get_model(model); + else + strcpy(model, "Unknown m68k"); - len += sprintf(buffer+len, "Model:\t\t%s\n", model); - for (mem = 0, i = 0; i < m68k_num_memory; i++) - mem += m68k_memory[i].size; - len += sprintf(buffer+len, "System Memory:\t%ldK\n", mem>>10); + len += sprintf(buffer + len, "Model:\t\t%s\n", model); + for (mem = 0, i = 0; i < m68k_num_memory; i++) + mem += m68k_memory[i].size; + len += sprintf(buffer + len, "System Memory:\t%ldK\n", mem >> 10); - if (mach_get_hardware_list) - len += mach_get_hardware_list(buffer+len); + if (mach_get_hardware_list) + len += mach_get_hardware_list(buffer + len); - return(len); + return len; } void check_bugs(void) { #ifndef CONFIG_M68KFPU_EMU if (m68k_fputype == 0) { - printk( KERN_EMERG "*** YOU DO NOT HAVE A FLOATING POINT UNIT, " - "WHICH IS REQUIRED BY LINUX/M68K ***\n" ); - printk( KERN_EMERG "Upgrade your hardware or join the FPU " - "emulation project\n" ); - panic( "no FPU" ); + printk(KERN_EMERG "*** YOU DO NOT HAVE A FLOATING POINT UNIT, " + "WHICH IS REQUIRED BY LINUX/M68K ***\n"); + printk(KERN_EMERG "Upgrade your hardware or join the FPU " + "emulation project\n"); + panic("no FPU"); } #endif /* !CONFIG_M68KFPU_EMU */ } + +#ifdef CONFIG_ADB +static int __init adb_probe_sync_enable (char *str) { + extern int __adb_probe_sync; + __adb_probe_sync = 1; + return 1; +} + +__setup("adb_sync", adb_probe_sync_enable); +#endif /* CONFIG_ADB */ diff --git a/arch/m68k/lib/checksum.c b/arch/m68k/lib/checksum.c index aed3be29e06..cf6bb51945a 100644 --- a/arch/m68k/lib/checksum.c +++ b/arch/m68k/lib/checksum.c @@ -320,6 +320,9 @@ csum_partial_copy_from_user(const void __user *src, void *dst, return(sum); } +EXPORT_SYMBOL(csum_partial_copy_from_user); + + /* * copy from kernel space while checksumming, otherwise like csum_partial */ diff --git a/arch/m68k/mac/baboon.c b/arch/m68k/mac/baboon.c index a1c7ec70674..673a1085984 100644 --- a/arch/m68k/mac/baboon.c +++ b/arch/m68k/mac/baboon.c @@ -22,7 +22,7 @@ /* #define DEBUG_BABOON */ /* #define DEBUG_IRQS */ -int baboon_present,baboon_active; +int baboon_present; volatile struct baboon *baboon; irqreturn_t baboon_irq(int, void *); @@ -45,7 +45,6 @@ void __init baboon_init(void) baboon = (struct baboon *) BABOON_BASE; baboon_present = 1; - baboon_active = 0; printk("Baboon detected at %p\n", baboon); } @@ -66,26 +65,28 @@ void __init baboon_register_interrupts(void) irqreturn_t baboon_irq(int irq, void *dev_id) { - int irq_bit,i; + int irq_bit, irq_num; unsigned char events; #ifdef DEBUG_IRQS - printk("baboon_irq: mb_control %02X mb_ifr %02X mb_status %02X active %02X\n", + printk("baboon_irq: mb_control %02X mb_ifr %02X mb_status %02X\n", (uint) baboon->mb_control, (uint) baboon->mb_ifr, - (uint) baboon->mb_status, baboon_active); + (uint) baboon->mb_status); #endif if (!(events = baboon->mb_ifr & 0x07)) return IRQ_NONE; - for (i = 0, irq_bit = 1 ; i < 3 ; i++, irq_bit <<= 1) { - if (events & irq_bit/* & baboon_active*/) { - baboon_active &= ~irq_bit; - m68k_handle_int(IRQ_BABOON_0 + i); - baboon_active |= irq_bit; + irq_num = IRQ_BABOON_0; + irq_bit = 1; + do { + if (events & irq_bit) { baboon->mb_ifr &= ~irq_bit; + m68k_handle_int(irq_num); } - } + irq_bit <<= 1; + irq_num++; + } while(events >= irq_bit); #if 0 if (baboon->mb_ifr & 0x02) macide_ack_intr(NULL); /* for now we need to smash all interrupts */ @@ -95,21 +96,18 @@ irqreturn_t baboon_irq(int irq, void *dev_id) } void baboon_irq_enable(int irq) { - int irq_idx = IRQ_IDX(irq); - #ifdef DEBUG_IRQUSE printk("baboon_irq_enable(%d)\n", irq); #endif - baboon_active |= (1 << irq_idx); + /* FIXME: figure out how to mask and unmask baboon interrupt sources */ + enable_irq(IRQ_NUBUS_C); } void baboon_irq_disable(int irq) { - int irq_idx = IRQ_IDX(irq); - #ifdef DEBUG_IRQUSE printk("baboon_irq_disable(%d)\n", irq); #endif - baboon_active &= ~(1 << irq_idx); + disable_irq(IRQ_NUBUS_C); } void baboon_irq_clear(int irq) { diff --git a/arch/m68k/mac/config.c b/arch/m68k/mac/config.c index 562b38d0018..5fd413246f8 100644 --- a/arch/m68k/mac/config.c +++ b/arch/m68k/mac/config.c @@ -59,15 +59,15 @@ extern struct mem_info m68k_ramdisk; extern char m68k_command_line[CL_SIZE]; -void *mac_env; /* Loaded by the boot asm */ +void *mac_env; /* Loaded by the boot asm */ /* The phys. video addr. - might be bogus on some machines */ unsigned long mac_orig_videoaddr; /* Mac specific timer functions */ -extern unsigned long mac_gettimeoffset (void); -extern int mac_hwclk (int, struct rtc_time *); -extern int mac_set_clock_mmss (unsigned long); +extern unsigned long mac_gettimeoffset(void); +extern int mac_hwclk(int, struct rtc_time *); +extern int mac_set_clock_mmss(unsigned long); extern int show_mac_interrupts(struct seq_file *, void *); extern void iop_preinit(void); extern void iop_init(void); @@ -82,10 +82,6 @@ extern void mac_mksound(unsigned int, unsigned int); extern void nubus_sweep_video(void); -/* Mac specific debug functions (in debug.c) */ -extern void mac_debug_init(void); -extern void mac_debugging_long(int, long); - static void mac_get_model(char *str); static void mac_sched_init(irq_handler_t vector) @@ -99,51 +95,52 @@ static void mac_sched_init(irq_handler_t vector) int __init mac_parse_bootinfo(const struct bi_record *record) { - int unknown = 0; - const u_long *data = record->data; + int unknown = 0; + const u_long *data = record->data; - switch (record->tag) { + switch (record->tag) { case BI_MAC_MODEL: - mac_bi_data.id = *data; - break; + mac_bi_data.id = *data; + break; case BI_MAC_VADDR: - mac_bi_data.videoaddr = *data; - break; + mac_bi_data.videoaddr = *data; + break; case BI_MAC_VDEPTH: - mac_bi_data.videodepth = *data; - break; + mac_bi_data.videodepth = *data; + break; case BI_MAC_VROW: - mac_bi_data.videorow = *data; - break; + mac_bi_data.videorow = *data; + break; case BI_MAC_VDIM: - mac_bi_data.dimensions = *data; - break; + mac_bi_data.dimensions = *data; + break; case BI_MAC_VLOGICAL: - mac_bi_data.videological = VIDEOMEMBASE + (*data & ~VIDEOMEMMASK); - mac_orig_videoaddr = *data; - break; + mac_bi_data.videological = VIDEOMEMBASE + (*data & ~VIDEOMEMMASK); + mac_orig_videoaddr = *data; + break; case BI_MAC_SCCBASE: - mac_bi_data.sccbase = *data; - break; + mac_bi_data.sccbase = *data; + break; case BI_MAC_BTIME: - mac_bi_data.boottime = *data; - break; + mac_bi_data.boottime = *data; + break; case BI_MAC_GMTBIAS: - mac_bi_data.gmtbias = *data; - break; + mac_bi_data.gmtbias = *data; + break; case BI_MAC_MEMSIZE: - mac_bi_data.memsize = *data; - break; + mac_bi_data.memsize = *data; + break; case BI_MAC_CPUID: - mac_bi_data.cpuid = *data; - break; - case BI_MAC_ROMBASE: - mac_bi_data.rombase = *data; - break; + mac_bi_data.cpuid = *data; + break; + case BI_MAC_ROMBASE: + mac_bi_data.rombase = *data; + break; default: - unknown = 1; - } - return(unknown); + unknown = 1; + break; + } + return unknown; } /* @@ -155,6 +152,7 @@ int __init mac_parse_bootinfo(const struct bi_record *record) static void mac_cache_card_flush(int writeback) { unsigned long flags; + local_irq_save(flags); via_flush_cache(); local_irq_restore(flags); @@ -162,28 +160,24 @@ static void mac_cache_card_flush(int writeback) void __init config_mac(void) { - if (!MACH_IS_MAC) { - printk(KERN_ERR "ERROR: no Mac, but config_mac() called!! \n"); - } + if (!MACH_IS_MAC) + printk(KERN_ERR "ERROR: no Mac, but config_mac() called!! \n"); - mach_sched_init = mac_sched_init; - mach_init_IRQ = mac_init_IRQ; - mach_get_model = mac_get_model; - mach_gettimeoffset = mac_gettimeoffset; + mach_sched_init = mac_sched_init; + mach_init_IRQ = mac_init_IRQ; + mach_get_model = mac_get_model; + mach_gettimeoffset = mac_gettimeoffset; #warning move to adb/via init #if 0 - mach_hwclk = mac_hwclk; + mach_hwclk = mac_hwclk; #endif - mach_set_clock_mmss = mac_set_clock_mmss; - mach_reset = mac_reset; - mach_halt = mac_poweroff; - mach_power_off = mac_poweroff; + mach_set_clock_mmss = mac_set_clock_mmss; + mach_reset = mac_reset; + mach_halt = mac_poweroff; + mach_power_off = mac_poweroff; mach_max_dma_address = 0xffffffff; -#if 0 - mach_debug_init = mac_debug_init; -#endif #if defined(CONFIG_INPUT_M68K_BEEP) || defined(CONFIG_INPUT_M68K_BEEP_MODULE) - mach_beep = mac_mksound; + mach_beep = mac_mksound; #endif #ifdef CONFIG_HEARTBEAT #if 0 @@ -199,21 +193,22 @@ void __init config_mac(void) mac_identify(); mac_report_hardware(); - /* AFAIK only the IIci takes a cache card. The IIfx has onboard - cache ... someone needs to figure out how to tell if it's on or - not. */ + /* + * AFAIK only the IIci takes a cache card. The IIfx has onboard + * cache ... someone needs to figure out how to tell if it's on or + * not. + */ if (macintosh_config->ident == MAC_MODEL_IICI - || macintosh_config->ident == MAC_MODEL_IIFX) { + || macintosh_config->ident == MAC_MODEL_IIFX) mach_l2_flush = mac_cache_card_flush; - } /* * Check for machine specific fixups. */ #ifdef OLD_NUBUS_CODE - nubus_sweep_video(); + nubus_sweep_video(); #endif } @@ -233,8 +228,7 @@ void __init config_mac(void) struct mac_model *macintosh_config; EXPORT_SYMBOL(macintosh_config); -static struct mac_model mac_data_table[]= -{ +static struct mac_model mac_data_table[] = { /* * We'll pretend to be a Macintosh II, that's pretty safe. */ @@ -784,12 +778,12 @@ void mac_identify(void) if (!model) { /* no bootinfo model id -> NetBSD booter was used! */ /* XXX FIXME: breaks for model > 31 */ - model=(mac_bi_data.cpuid>>2)&63; - printk (KERN_WARNING "No bootinfo model ID, using cpuid instead (hey, use Penguin!)\n"); + model = (mac_bi_data.cpuid >> 2) & 63; + printk(KERN_WARNING "No bootinfo model ID, using cpuid instead (hey, use Penguin!)\n"); } macintosh_config = mac_data_table; - for (m = macintosh_config ; m->ident != -1 ; m++) { + for (m = macintosh_config; m->ident != -1; m++) { if (m->ident == model) { macintosh_config = m; break; @@ -801,27 +795,26 @@ void mac_identify(void) /* the serial ports set to "Faster" mode in MacOS. */ iop_preinit(); - mac_debug_init(); - printk (KERN_INFO "Detected Macintosh model: %d \n", model); + printk(KERN_INFO "Detected Macintosh model: %d \n", model); /* * Report booter data: */ - printk (KERN_DEBUG " Penguin bootinfo data:\n"); - printk (KERN_DEBUG " Video: addr 0x%lx row 0x%lx depth %lx dimensions %ld x %ld\n", + printk(KERN_DEBUG " Penguin bootinfo data:\n"); + printk(KERN_DEBUG " Video: addr 0x%lx row 0x%lx depth %lx dimensions %ld x %ld\n", mac_bi_data.videoaddr, mac_bi_data.videorow, mac_bi_data.videodepth, mac_bi_data.dimensions & 0xFFFF, mac_bi_data.dimensions >> 16); - printk (KERN_DEBUG " Videological 0x%lx phys. 0x%lx, SCC at 0x%lx \n", + printk(KERN_DEBUG " Videological 0x%lx phys. 0x%lx, SCC at 0x%lx \n", mac_bi_data.videological, mac_orig_videoaddr, mac_bi_data.sccbase); - printk (KERN_DEBUG " Boottime: 0x%lx GMTBias: 0x%lx \n", + printk(KERN_DEBUG " Boottime: 0x%lx GMTBias: 0x%lx \n", mac_bi_data.boottime, mac_bi_data.gmtbias); - printk (KERN_DEBUG " Machine ID: %ld CPUid: 0x%lx memory size: 0x%lx \n", + printk(KERN_DEBUG " Machine ID: %ld CPUid: 0x%lx memory size: 0x%lx \n", mac_bi_data.id, mac_bi_data.cpuid, mac_bi_data.memsize); #if 0 - printk ("Ramdisk: addr 0x%lx size 0x%lx\n", + printk("Ramdisk: addr 0x%lx size 0x%lx\n", m68k_ramdisk.addr, m68k_ramdisk.size); #endif @@ -830,22 +823,22 @@ void mac_identify(void) */ switch (macintosh_config->scsi_type) { case MAC_SCSI_OLD: - MACHW_SET(MAC_SCSI_80); - break; + MACHW_SET(MAC_SCSI_80); + break; case MAC_SCSI_QUADRA: case MAC_SCSI_QUADRA2: case MAC_SCSI_QUADRA3: - MACHW_SET(MAC_SCSI_96); - if ((macintosh_config->ident == MAC_MODEL_Q900) || - (macintosh_config->ident == MAC_MODEL_Q950)) - MACHW_SET(MAC_SCSI_96_2); - break; + MACHW_SET(MAC_SCSI_96); + if ((macintosh_config->ident == MAC_MODEL_Q900) || + (macintosh_config->ident == MAC_MODEL_Q950)) + MACHW_SET(MAC_SCSI_96_2); + break; default: - printk(KERN_WARNING "config.c: wtf: unknown scsi, using 53c80\n"); - MACHW_SET(MAC_SCSI_80); - break; - + printk(KERN_WARNING "config.c: wtf: unknown scsi, using 53c80\n"); + MACHW_SET(MAC_SCSI_80); + break; } + iop_init(); via_init(); oss_init(); @@ -860,6 +853,6 @@ void mac_report_hardware(void) static void mac_get_model(char *str) { - strcpy(str,"Macintosh "); + strcpy(str, "Macintosh "); strcat(str, macintosh_config->name); } diff --git a/arch/m68k/mac/debug.c b/arch/m68k/mac/debug.c index 4eeb09dc0e8..7a5bed5bdc5 100644 --- a/arch/m68k/mac/debug.c +++ b/arch/m68k/mac/debug.c @@ -27,10 +27,6 @@ #include <asm/machw.h> #include <asm/macints.h> -extern char m68k_debug_device[]; - -extern struct compat_bootinfo compat_boot_info; - extern unsigned long mac_videobase; extern unsigned long mac_videodepth; extern unsigned long mac_rowbytes; @@ -52,7 +48,7 @@ extern void mac_serial_print(const char *); */ #ifdef DEBUG_SCREEN -static int peng=0, line=0; +static int peng, line; #endif void mac_debugging_short(int pos, short num) @@ -74,15 +70,14 @@ void mac_debugging_short(int pos, short num) } /* calculate current offset */ - pengoffset=(unsigned char *)(mac_videobase+(150+line*2)*mac_rowbytes) - +80*peng; + pengoffset = (unsigned char *)mac_videobase + + (150+line*2) * mac_rowbytes) + 80 * peng; - pptr=pengoffset; + pptr = pengoffset; - for(i=0;i<8*sizeof(short);i++) /* # of bits */ - { + for (i = 0; i < 8 * sizeof(short); i++) { /* # of bits */ /* value mask for bit i, reverse order */ - *pptr++ = (num & ( 1 << (8*sizeof(short)-i-1) ) ? 0xFF : 0x00); + *pptr++ = (num & (1 << (8*sizeof(short)-i-1)) ? 0xFF : 0x00); } peng++; @@ -115,11 +110,10 @@ void mac_debugging_long(int pos, long addr) pengoffset=(unsigned char *)(mac_videobase+(150+line*2)*mac_rowbytes) +80*peng; - pptr=pengoffset; + pptr = pengoffset; - for(i=0;i<8*sizeof(long);i++) /* # of bits */ - { - *pptr++ = (addr & ( 1 << (8*sizeof(long)-i-1) ) ? 0xFF : 0x00); + for (i = 0; i < 8 * sizeof(long); i++) { /* # of bits */ + *pptr++ = (addr & (1 << (8*sizeof(long)-i-1)) ? 0xFF : 0x00); } peng++; @@ -136,16 +130,15 @@ void mac_debugging_long(int pos, long addr) * TODO: serial debug code */ -struct mac_SCC - { - u_char cha_b_ctrl; - u_char char_dummy1; - u_char cha_a_ctrl; - u_char char_dummy2; - u_char cha_b_data; - u_char char_dummy3; - u_char cha_a_data; - }; +struct mac_SCC { + u_char cha_b_ctrl; + u_char char_dummy1; + u_char cha_a_ctrl; + u_char char_dummy2; + u_char cha_b_data; + u_char char_dummy3; + u_char cha_a_data; +}; # define scc (*((volatile struct mac_SCC*)mac_bi_data.sccbase)) @@ -158,9 +151,9 @@ int mac_SCC_reset_done; static int scc_port = -1; static struct console mac_console_driver = { - .name = "debug", - .flags = CON_PRINTBUFFER, - .index = -1, + .name = "debug", + .flags = CON_PRINTBUFFER, + .index = -1, }; /* @@ -178,8 +171,8 @@ static struct console mac_console_driver = { * this driver if Mac. */ -void mac_debug_console_write (struct console *co, const char *str, - unsigned int count) +void mac_debug_console_write(struct console *co, const char *str, + unsigned int count) { mac_serial_print(str); } @@ -190,48 +183,50 @@ void mac_debug_console_write (struct console *co, const char *str, #define uSEC 1 -static inline void mac_sccb_out (char c) +static inline void mac_sccb_out(char c) { - int i; - do { - for( i = uSEC; i > 0; --i ) + int i; + + do { + for (i = uSEC; i > 0; --i) + barrier(); + } while (!(scc.cha_b_ctrl & 0x04)); /* wait for tx buf empty */ + for (i = uSEC; i > 0; --i) barrier(); - } while (!(scc.cha_b_ctrl & 0x04)); /* wait for tx buf empty */ - for( i = uSEC; i > 0; --i ) - barrier(); - scc.cha_b_data = c; + scc.cha_b_data = c; } -static inline void mac_scca_out (char c) +static inline void mac_scca_out(char c) { - int i; - do { - for( i = uSEC; i > 0; --i ) + int i; + + do { + for (i = uSEC; i > 0; --i) + barrier(); + } while (!(scc.cha_a_ctrl & 0x04)); /* wait for tx buf empty */ + for (i = uSEC; i > 0; --i) barrier(); - } while (!(scc.cha_a_ctrl & 0x04)); /* wait for tx buf empty */ - for( i = uSEC; i > 0; --i ) - barrier(); - scc.cha_a_data = c; + scc.cha_a_data = c; } -void mac_sccb_console_write (struct console *co, const char *str, - unsigned int count) +void mac_sccb_console_write(struct console *co, const char *str, + unsigned int count) { - while (count--) { - if (*str == '\n') - mac_sccb_out( '\r' ); - mac_sccb_out( *str++ ); - } + while (count--) { + if (*str == '\n') + mac_sccb_out('\r'); + mac_sccb_out(*str++); + } } -void mac_scca_console_write (struct console *co, const char *str, - unsigned int count) +void mac_scca_console_write(struct console *co, const char *str, + unsigned int count) { - while (count--) { - if (*str == '\n') - mac_scca_out( '\r' ); - mac_scca_out( *str++ ); - } + while (count--) { + if (*str == '\n') + mac_scca_out('\r'); + mac_scca_out(*str++); + } } @@ -239,41 +234,41 @@ void mac_scca_console_write (struct console *co, const char *str, * SCC serial ports. They're used by the debugging interface, kgdb, and the * serial console code. */ #define SCCB_WRITE(reg,val) \ - do { \ - int i; \ - scc.cha_b_ctrl = (reg); \ - for( i = uSEC; i > 0; --i ) \ - barrier(); \ - scc.cha_b_ctrl = (val); \ - for( i = uSEC; i > 0; --i ) \ - barrier(); \ - } while(0) + do { \ + int i; \ + scc.cha_b_ctrl = (reg); \ + for (i = uSEC; i > 0; --i) \ + barrier(); \ + scc.cha_b_ctrl = (val); \ + for (i = uSEC; i > 0; --i) \ + barrier(); \ + } while(0) #define SCCA_WRITE(reg,val) \ - do { \ - int i; \ - scc.cha_a_ctrl = (reg); \ - for( i = uSEC; i > 0; --i ) \ - barrier(); \ - scc.cha_a_ctrl = (val); \ - for( i = uSEC; i > 0; --i ) \ - barrier(); \ - } while(0) + do { \ + int i; \ + scc.cha_a_ctrl = (reg); \ + for (i = uSEC; i > 0; --i) \ + barrier(); \ + scc.cha_a_ctrl = (val); \ + for (i = uSEC; i > 0; --i) \ + barrier(); \ + } while(0) /* loops_per_jiffy isn't initialized yet, so we can't use udelay(). This does a * delay of ~ 60us. */ /* Mac: loops_per_jiffy min. 19000 ^= .5 us; MFPDELAY was 0.6 us*/ -#define LONG_DELAY() \ - do { \ - int i; \ - for( i = 60*uSEC; i > 0; --i ) \ - barrier(); \ - } while(0) +#define LONG_DELAY() \ + do { \ + int i; \ + for (i = 60*uSEC; i > 0; --i) \ + barrier(); \ + } while(0) #ifndef CONFIG_SERIAL_CONSOLE -static void __init mac_init_scc_port( int cflag, int port ) +static void __init mac_init_scc_port(int cflag, int port) #else -void mac_init_scc_port( int cflag, int port ) +void mac_init_scc_port(int cflag, int port) #endif { extern int mac_SCC_reset_done; @@ -292,106 +287,102 @@ void mac_init_scc_port( int cflag, int port ) /* reg12 (BRG low) */ { 94, 62, 46, 22, 10, 4, 1, 0, 0 }; - int baud = cflag & CBAUD; - int clksrc, clkmode, div, reg3, reg5; - - if (cflag & CBAUDEX) - baud += B38400; - if (baud < B1200 || baud > B38400+2) - baud = B9600; /* use default 9600bps for non-implemented rates */ - baud -= B1200; /* tables starts at 1200bps */ - - clksrc = clksrc_table[baud]; - clkmode = clkmode_table[baud]; - div = div_table[baud]; - - reg3 = (((cflag & CSIZE) == CS8) ? 0xc0 : 0x40); - reg5 = (((cflag & CSIZE) == CS8) ? 0x60 : 0x20) | 0x82 /* assert DTR/RTS */; - - if (port == 1) { - (void)scc.cha_b_ctrl; /* reset reg pointer */ - SCCB_WRITE( 9, 0xc0 ); /* reset */ - LONG_DELAY(); /* extra delay after WR9 access */ - SCCB_WRITE( 4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03) : 0 | + int baud = cflag & CBAUD; + int clksrc, clkmode, div, reg3, reg5; + + if (cflag & CBAUDEX) + baud += B38400; + if (baud < B1200 || baud > B38400+2) + baud = B9600; /* use default 9600bps for non-implemented rates */ + baud -= B1200; /* tables starts at 1200bps */ + + clksrc = clksrc_table[baud]; + clkmode = clkmode_table[baud]; + div = div_table[baud]; + + reg3 = (((cflag & CSIZE) == CS8) ? 0xc0 : 0x40); + reg5 = (((cflag & CSIZE) == CS8) ? 0x60 : 0x20) | 0x82 /* assert DTR/RTS */; + + if (port == 1) { + (void)scc.cha_b_ctrl; /* reset reg pointer */ + SCCB_WRITE(9, 0xc0); /* reset */ + LONG_DELAY(); /* extra delay after WR9 access */ + SCCB_WRITE(4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03) : 0 | + 0x04 /* 1 stopbit */ | + clkmode); + SCCB_WRITE(3, reg3); + SCCB_WRITE(5, reg5); + SCCB_WRITE(9, 0); /* no interrupts */ + LONG_DELAY(); /* extra delay after WR9 access */ + SCCB_WRITE(10, 0); /* NRZ mode */ + SCCB_WRITE(11, clksrc); /* main clock source */ + SCCB_WRITE(12, div); /* BRG value */ + SCCB_WRITE(13, 0); /* BRG high byte */ + SCCB_WRITE(14, 1); + SCCB_WRITE(3, reg3 | 1); + SCCB_WRITE(5, reg5 | 8); + } else if (port == 0) { + (void)scc.cha_a_ctrl; /* reset reg pointer */ + SCCA_WRITE(9, 0xc0); /* reset */ + LONG_DELAY(); /* extra delay after WR9 access */ + SCCA_WRITE(4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03) : 0 | 0x04 /* 1 stopbit */ | - clkmode ); - SCCB_WRITE( 3, reg3 ); - SCCB_WRITE( 5, reg5 ); - SCCB_WRITE( 9, 0 ); /* no interrupts */ - LONG_DELAY(); /* extra delay after WR9 access */ - SCCB_WRITE( 10, 0 ); /* NRZ mode */ - SCCB_WRITE( 11, clksrc ); /* main clock source */ - SCCB_WRITE( 12, div ); /* BRG value */ - SCCB_WRITE( 13, 0 ); /* BRG high byte */ - SCCB_WRITE( 14, 1 ); - SCCB_WRITE( 3, reg3 | 1 ); - SCCB_WRITE( 5, reg5 | 8 ); - } else if (port == 0) { - (void)scc.cha_a_ctrl; /* reset reg pointer */ - SCCA_WRITE( 9, 0xc0 ); /* reset */ - LONG_DELAY(); /* extra delay after WR9 access */ - SCCA_WRITE( 4, (cflag & PARENB) ? ((cflag & PARODD) ? 0x01 : 0x03) : 0 | - 0x04 /* 1 stopbit */ | - clkmode ); - SCCA_WRITE( 3, reg3 ); - SCCA_WRITE( 5, reg5 ); - SCCA_WRITE( 9, 0 ); /* no interrupts */ - LONG_DELAY(); /* extra delay after WR9 access */ - SCCA_WRITE( 10, 0 ); /* NRZ mode */ - SCCA_WRITE( 11, clksrc ); /* main clock source */ - SCCA_WRITE( 12, div ); /* BRG value */ - SCCA_WRITE( 13, 0 ); /* BRG high byte */ - SCCA_WRITE( 14, 1 ); - SCCA_WRITE( 3, reg3 | 1 ); - SCCA_WRITE( 5, reg5 | 8 ); - } - - mac_SCC_reset_done = 1; - mac_SCC_init_done = 1; + clkmode); + SCCA_WRITE(3, reg3); + SCCA_WRITE(5, reg5); + SCCA_WRITE(9, 0); /* no interrupts */ + LONG_DELAY(); /* extra delay after WR9 access */ + SCCA_WRITE(10, 0); /* NRZ mode */ + SCCA_WRITE(11, clksrc); /* main clock source */ + SCCA_WRITE(12, div); /* BRG value */ + SCCA_WRITE(13, 0); /* BRG high byte */ + SCCA_WRITE(14, 1); + SCCA_WRITE(3, reg3 | 1); + SCCA_WRITE(5, reg5 | 8); + } + + mac_SCC_reset_done = 1; + mac_SCC_init_done = 1; } #endif /* DEBUG_SERIAL */ -void mac_init_scca_port( int cflag ) +void mac_init_scca_port(int cflag) { mac_init_scc_port(cflag, 0); } -void mac_init_sccb_port( int cflag ) +void mac_init_sccb_port(int cflag) { mac_init_scc_port(cflag, 1); } -void __init mac_debug_init(void) +static int __init mac_debug_setup(char *arg) { + if (!MACH_IS_MAC) + return 0; + #ifdef DEBUG_SERIAL - if ( !strcmp( m68k_debug_device, "ser" ) - || !strcmp( m68k_debug_device, "ser1" )) { - /* Mac modem port */ - mac_init_scc_port( B9600|CS8, 0 ); - mac_console_driver.write = mac_scca_console_write; - scc_port = 0; - } - else if (!strcmp( m68k_debug_device, "ser2" )) { - /* Mac printer port */ - mac_init_scc_port( B9600|CS8, 1 ); - mac_console_driver.write = mac_sccb_console_write; - scc_port = 1; - } + if (!strcmp(arg, "ser") || !strcmp(arg, "ser1")) { + /* Mac modem port */ + mac_init_scc_port(B9600|CS8, 0); + mac_console_driver.write = mac_scca_console_write; + scc_port = 0; + } else if (!strcmp(arg, "ser2")) { + /* Mac printer port */ + mac_init_scc_port(B9600|CS8, 1); + mac_console_driver.write = mac_sccb_console_write; + scc_port = 1; + } #endif #ifdef DEBUG_HEADS - if ( !strcmp( m68k_debug_device, "scn" ) - || !strcmp( m68k_debug_device, "con" )) { - /* display, using head.S console routines */ - mac_console_driver.write = mac_debug_console_write; - } + if (!strcmp(arg, "scn") || !strcmp(arg, "con")) { + /* display, using head.S console routines */ + mac_console_driver.write = mac_debug_console_write; + } #endif - if (mac_console_driver.write) - register_console(&mac_console_driver); + if (mac_console_driver.write) + register_console(&mac_console_driver); + return 0; } -/* - * Local variables: - * c-indent-level: 4 - * tab-width: 8 - * End: - */ +early_param("debug", mac_debug_setup); diff --git a/arch/m68k/mac/oss.c b/arch/m68k/mac/oss.c index 63690819565..d7be16917ef 100644 --- a/arch/m68k/mac/oss.c +++ b/arch/m68k/mac/oss.c @@ -109,13 +109,11 @@ irqreturn_t oss_irq(int irq, void *dev_id) /* FIXME: how do you clear a pending IRQ? */ if (events & OSS_IP_SOUND) { - /* FIXME: call sound handler */ oss->irq_pending &= ~OSS_IP_SOUND; + /* FIXME: call sound handler */ } else if (events & OSS_IP_SCSI) { - oss->irq_level[OSS_SCSI] = OSS_IRQLEV_DISABLED; - m68k_handle_int(IRQ_MAC_SCSI); oss->irq_pending &= ~OSS_IP_SCSI; - oss->irq_level[OSS_SCSI] = OSS_IRQLEV_SCSI; + m68k_handle_int(IRQ_MAC_SCSI); } else { /* FIXME: error check here? */ } @@ -143,14 +141,16 @@ irqreturn_t oss_nubus_irq(int irq, void *dev_id) #endif /* There are only six slots on the OSS, not seven */ - for (i = 0, irq_bit = 1 ; i < 6 ; i++, irq_bit <<= 1) { + i = 6; + irq_bit = 0x40; + do { + --i; + irq_bit >>= 1; if (events & irq_bit) { - oss->irq_level[i] = OSS_IRQLEV_DISABLED; - m68k_handle_int(NUBUS_SOURCE_BASE + i); oss->irq_pending &= ~irq_bit; - oss->irq_level[i] = OSS_IRQLEV_NUBUS; + m68k_handle_int(NUBUS_SOURCE_BASE + i); } - } + } while(events & (irq_bit - 1)); return IRQ_HANDLED; } diff --git a/arch/m68k/mac/psc.c b/arch/m68k/mac/psc.c index 15378a5878c..d66f723b17c 100644 --- a/arch/m68k/mac/psc.c +++ b/arch/m68k/mac/psc.c @@ -131,11 +131,8 @@ irqreturn_t psc_irq(int irq, void *dev_id) { int pIFR = pIFRbase + ((int) dev_id); int pIER = pIERbase + ((int) dev_id); - int base_irq; - int irq_bit,i; - unsigned char events; - - base_irq = irq << 3; + int irq_num; + unsigned char irq_bit, events; #ifdef DEBUG_IRQS printk("psc_irq: irq %d pIFR = 0x%02X pIER = 0x%02X\n", @@ -146,14 +143,16 @@ irqreturn_t psc_irq(int irq, void *dev_id) if (!events) return IRQ_NONE; - for (i = 0, irq_bit = 1 ; i < 4 ; i++, irq_bit <<= 1) { - if (events & irq_bit) { - psc_write_byte(pIER, irq_bit); - m68k_handle_int(base_irq + i); + irq_num = irq << 3; + irq_bit = 1; + do { + if (events & irq_bit) { psc_write_byte(pIFR, irq_bit); - psc_write_byte(pIER, irq_bit | 0x80); + m68k_handle_int(irq_num); } - } + irq_num++; + irq_bit <<= 1; + } while (events >= irq_bit); return IRQ_HANDLED; } diff --git a/arch/m68k/mac/via.c b/arch/m68k/mac/via.c index e27735be292..d5cac72eb3d 100644 --- a/arch/m68k/mac/via.c +++ b/arch/m68k/mac/via.c @@ -13,6 +13,10 @@ * for info. A full-text web search on 6522 AND VIA will probably also * net some usefulness. <cananian@alumni.princeton.edu> 20apr1999 * + * Additional data is here (the SY6522 was used in the Mac II etc): + * http://www.6502.org/documents/datasheets/synertek/synertek_sy6522.pdf + * http://www.6502.org/documents/datasheets/synertek/synertek_sy6522_programming_reference.pdf + * * PRAM/RTC access algorithms are from the NetBSD RTC toolkit version 1.08b * by Erik Vogan and adapted to Linux by Joshua M. Thompson (funaho@jurai.org) * @@ -37,7 +41,7 @@ volatile __u8 *via1, *via2; /* See note in mac_via.h about how this is possibly not useful */ volatile long *via_memory_bogon=(long *)&via_memory_bogon; #endif -int rbv_present,via_alt_mapping; +int rbv_present, via_alt_mapping; __u8 rbv_clear; /* @@ -60,7 +64,19 @@ static int gIER,gIFR,gBufA,gBufB; #define MAC_CLOCK_LOW (MAC_CLOCK_TICK&0xFF) #define MAC_CLOCK_HIGH (MAC_CLOCK_TICK>>8) -static int nubus_active; +/* To disable a NuBus slot on Quadras we make the slot IRQ lines outputs, set + * high. On RBV we just use the slot interrupt enable register. On Macs with + * genuine VIA chips we must use nubus_disabled to keep track of disabled slot + * interrupts. When any slot IRQ is disabled we mask the (edge triggered) CA1 + * or "SLOTS" interrupt. When no slot is disabled, we unmask the CA1 interrupt. + * So, on genuine VIAs, having more than one NuBus IRQ can mean trouble, + * because closing one of those drivers can mask all of the NuBus interrupts. + * Also, since we can't mask the unregistered slot IRQs on genuine VIAs, it's + * possible to get interrupts from cards that MacOS or the ROM has configured + * but we have not. FWIW, "Designing Cards and Drivers for Macintosh II and + * Macintosh SE", page 9-8, says, a slot IRQ with no driver would crash MacOS. + */ +static u8 nubus_disabled; void via_debug_dump(void); irqreturn_t via1_irq(int, void *); @@ -138,11 +154,11 @@ void __init via_init(void) printk(KERN_INFO "VIA2 at %p is ", via2); if (rbv_present) { - printk(KERN_INFO "an RBV\n"); + printk("an RBV\n"); } else if (oss_present) { - printk(KERN_INFO "an OSS\n"); + printk("an OSS\n"); } else { - printk(KERN_INFO "a 6522 or clone\n"); + printk("a 6522 or clone\n"); } #ifdef DEBUG_VIA @@ -163,6 +179,7 @@ void __init via_init(void) via1[vT2CL] = 0; via1[vT2CH] = 0; via1[vACR] &= 0x3F; + via1[vACR] &= ~0x03; /* disable port A & B latches */ /* * SE/30: disable video IRQ @@ -193,8 +210,14 @@ void __init via_init(void) /* that the IIfx emulates this alternate mapping using the OSS. */ switch(macintosh_config->ident) { + case MAC_MODEL_P475: + case MAC_MODEL_P475F: + case MAC_MODEL_P575: + case MAC_MODEL_Q605: + case MAC_MODEL_Q605_ACC: case MAC_MODEL_C610: case MAC_MODEL_Q610: + case MAC_MODEL_Q630: case MAC_MODEL_C650: case MAC_MODEL_Q650: case MAC_MODEL_Q700: @@ -228,6 +251,22 @@ void __init via_init(void) via2[vT2CL] = 0; via2[vT2CH] = 0; via2[vACR] &= 0x3F; + via2[vACR] &= ~0x03; /* disable port A & B latches */ + } + + /* + * Set vPCR for SCSI interrupts (but not on RBV) + */ + if (!rbv_present) { + if (macintosh_config->scsi_type == MAC_SCSI_OLD) { + /* CB2 (IRQ) indep. input, positive edge */ + /* CA2 (DRQ) indep. input, positive edge */ + via2[vPCR] = 0x66; + } else { + /* CB2 (IRQ) indep. input, negative edge */ + /* CA2 (DRQ) indep. input, negative edge */ + via2[vPCR] = 0x22; + } } } @@ -356,78 +395,75 @@ int via_get_cache_disable(void) void __init via_nubus_init(void) { - /* don't set nubus_active = 0 here, it kills the Baboon */ - /* interrupt that we've already registered. */ - /* unlock nubus transactions */ - if (!rbv_present) { + if ((macintosh_config->adb_type != MAC_ADB_PB1) && + (macintosh_config->adb_type != MAC_ADB_PB2)) { /* set the line to be an output on non-RBV machines */ - if ((macintosh_config->adb_type != MAC_ADB_PB1) && - (macintosh_config->adb_type != MAC_ADB_PB2)) { + if (!rbv_present) via2[vDirB] |= 0x02; - } - } - /* this seems to be an ADB bit on PMU machines */ - /* according to MkLinux. -- jmt */ - - if ((macintosh_config->adb_type != MAC_ADB_PB1) && - (macintosh_config->adb_type != MAC_ADB_PB2)) { + /* this seems to be an ADB bit on PMU machines */ + /* according to MkLinux. -- jmt */ via2[gBufB] |= 0x02; } - /* disable nubus slot interrupts. */ - if (rbv_present) { + /* Disable all the slot interrupts (where possible). */ + + switch (macintosh_config->via_type) { + case MAC_VIA_II: + /* Just make the port A lines inputs. */ + switch(macintosh_config->ident) { + case MAC_MODEL_II: + case MAC_MODEL_IIX: + case MAC_MODEL_IICX: + case MAC_MODEL_SE30: + /* The top two bits are RAM size outputs. */ + via2[vDirA] &= 0xC0; + break; + default: + via2[vDirA] &= 0x80; + } + break; + case MAC_VIA_IIci: + /* RBV. Disable all the slot interrupts. SIER works like IER. */ via2[rSIER] = 0x7F; - via2[rSIER] = nubus_active | 0x80; - } else { - /* These are ADB bits on PMU */ + break; + case MAC_VIA_QUADRA: + /* Disable the inactive slot interrupts by making those lines outputs. */ if ((macintosh_config->adb_type != MAC_ADB_PB1) && - (macintosh_config->adb_type != MAC_ADB_PB2)) { - switch(macintosh_config->ident) - { - case MAC_MODEL_II: - case MAC_MODEL_IIX: - case MAC_MODEL_IICX: - case MAC_MODEL_SE30: - via2[vBufA] |= 0x3F; - via2[vDirA] = ~nubus_active | 0xc0; - break; - default: - via2[vBufA] = 0xFF; - via2[vDirA] = ~nubus_active; - } + (macintosh_config->adb_type != MAC_ADB_PB2)) { + via2[vBufA] |= 0x7F; + via2[vDirA] |= 0x7F; } + break; } } /* * The generic VIA interrupt routines (shamelessly stolen from Alan Cox's * via6522.c :-), disable/pending masks added. - * - * The new interrupt architecture in macints.c takes care of a lot of the - * gruntwork for us, including tallying the interrupts and calling the - * handlers on the linked list. All we need to do here is basically generate - * the machspec interrupt number after clearing the interrupt. */ irqreturn_t via1_irq(int irq, void *dev_id) { - int irq_bit, i; - unsigned char events, mask; + int irq_num; + unsigned char irq_bit, events; - mask = via1[vIER] & 0x7F; - if (!(events = via1[vIFR] & mask)) + events = via1[vIFR] & via1[vIER] & 0x7F; + if (!events) return IRQ_NONE; - for (i = 0, irq_bit = 1 ; i < 7 ; i++, irq_bit <<= 1) + irq_num = VIA1_SOURCE_BASE; + irq_bit = 1; + do { if (events & irq_bit) { - via1[vIER] = irq_bit; - m68k_handle_int(VIA1_SOURCE_BASE + i); via1[vIFR] = irq_bit; - via1[vIER] = irq_bit | 0x80; + m68k_handle_int(irq_num); } + ++irq_num; + irq_bit <<= 1; + } while (events >= irq_bit); #if 0 /* freakin' pmu is doing weird stuff */ if (!oss_present) { @@ -448,20 +484,23 @@ irqreturn_t via1_irq(int irq, void *dev_id) irqreturn_t via2_irq(int irq, void *dev_id) { - int irq_bit, i; - unsigned char events, mask; + int irq_num; + unsigned char irq_bit, events; - mask = via2[gIER] & 0x7F; - if (!(events = via2[gIFR] & mask)) + events = via2[gIFR] & via2[gIER] & 0x7F; + if (!events) return IRQ_NONE; - for (i = 0, irq_bit = 1 ; i < 7 ; i++, irq_bit <<= 1) + irq_num = VIA2_SOURCE_BASE; + irq_bit = 1; + do { if (events & irq_bit) { - via2[gIER] = irq_bit; via2[gIFR] = irq_bit | rbv_clear; - m68k_handle_int(VIA2_SOURCE_BASE + i); - via2[gIER] = irq_bit | 0x80; + m68k_handle_int(irq_num); } + ++irq_num; + irq_bit <<= 1; + } while (events >= irq_bit); return IRQ_HANDLED; } @@ -472,71 +511,75 @@ irqreturn_t via2_irq(int irq, void *dev_id) irqreturn_t via_nubus_irq(int irq, void *dev_id) { - int irq_bit, i; - unsigned char events; - - if (!(events = ~via2[gBufA] & nubus_active)) + int slot_irq; + unsigned char slot_bit, events; + + events = ~via2[gBufA] & 0x7F; + if (rbv_present) + events &= via2[rSIER]; + else + events &= ~via2[vDirA]; + if (!events) return IRQ_NONE; - for (i = 0, irq_bit = 1 ; i < 7 ; i++, irq_bit <<= 1) { - if (events & irq_bit) { - via_irq_disable(NUBUS_SOURCE_BASE + i); - m68k_handle_int(NUBUS_SOURCE_BASE + i); - via_irq_enable(NUBUS_SOURCE_BASE + i); - } - } + do { + slot_irq = IRQ_NUBUS_F; + slot_bit = 0x40; + do { + if (events & slot_bit) { + events &= ~slot_bit; + m68k_handle_int(slot_irq); + } + --slot_irq; + slot_bit >>= 1; + } while (events); + + /* clear the CA1 interrupt and make certain there's no more. */ + via2[gIFR] = 0x02 | rbv_clear; + events = ~via2[gBufA] & 0x7F; + if (rbv_present) + events &= via2[rSIER]; + else + events &= ~via2[vDirA]; + } while (events); return IRQ_HANDLED; } void via_irq_enable(int irq) { int irq_src = IRQ_SRC(irq); int irq_idx = IRQ_IDX(irq); - int irq_bit = 1 << irq_idx; #ifdef DEBUG_IRQUSE printk(KERN_DEBUG "via_irq_enable(%d)\n", irq); #endif if (irq_src == 1) { - via1[vIER] = irq_bit | 0x80; + via1[vIER] = IER_SET_BIT(irq_idx); } else if (irq_src == 2) { - /* - * Set vPCR for SCSI interrupts (but not on RBV) - */ - if ((irq_idx == 0) && !rbv_present) { - if (macintosh_config->scsi_type == MAC_SCSI_OLD) { - /* CB2 (IRQ) indep. input, positive edge */ - /* CA2 (DRQ) indep. input, positive edge */ - via2[vPCR] = 0x66; - } else { - /* CB2 (IRQ) indep. input, negative edge */ - /* CA2 (DRQ) indep. input, negative edge */ - via2[vPCR] = 0x22; - } - } - via2[gIER] = irq_bit | 0x80; + if (irq != IRQ_MAC_NUBUS || nubus_disabled == 0) + via2[gIER] = IER_SET_BIT(irq_idx); } else if (irq_src == 7) { - nubus_active |= irq_bit; - if (rbv_present) { - /* enable the slot interrupt. SIER works like IER. */ + switch (macintosh_config->via_type) { + case MAC_VIA_II: + nubus_disabled &= ~(1 << irq_idx); + /* Enable the CA1 interrupt when no slot is disabled. */ + if (!nubus_disabled) + via2[gIER] = IER_SET_BIT(1); + break; + case MAC_VIA_IIci: + /* On RBV, enable the slot interrupt. + * SIER works like IER. + */ via2[rSIER] = IER_SET_BIT(irq_idx); - } else { - /* Make sure the bit is an input, to enable the irq */ - /* But not on PowerBooks, that's ADB... */ + break; + case MAC_VIA_QUADRA: + /* Make the port A line an input to enable the slot irq. + * But not on PowerBooks, that's ADB. + */ if ((macintosh_config->adb_type != MAC_ADB_PB1) && - (macintosh_config->adb_type != MAC_ADB_PB2)) { - switch(macintosh_config->ident) - { - case MAC_MODEL_II: - case MAC_MODEL_IIX: - case MAC_MODEL_IICX: - case MAC_MODEL_SE30: - via2[vDirA] &= (~irq_bit | 0xc0); - break; - default: - via2[vDirA] &= ~irq_bit; - } - } + (macintosh_config->adb_type != MAC_ADB_PB2)) + via2[vDirA] &= ~(1 << irq_idx); + break; } } } @@ -544,29 +587,31 @@ void via_irq_enable(int irq) { void via_irq_disable(int irq) { int irq_src = IRQ_SRC(irq); int irq_idx = IRQ_IDX(irq); - int irq_bit = 1 << irq_idx; #ifdef DEBUG_IRQUSE printk(KERN_DEBUG "via_irq_disable(%d)\n", irq); #endif if (irq_src == 1) { - via1[vIER] = irq_bit; + via1[vIER] = IER_CLR_BIT(irq_idx); } else if (irq_src == 2) { - via2[gIER] = irq_bit; + via2[gIER] = IER_CLR_BIT(irq_idx); } else if (irq_src == 7) { - if (rbv_present) { - /* disable the slot interrupt. SIER works like IER. */ + switch (macintosh_config->via_type) { + case MAC_VIA_II: + nubus_disabled |= 1 << irq_idx; + if (nubus_disabled) + via2[gIER] = IER_CLR_BIT(1); + break; + case MAC_VIA_IIci: via2[rSIER] = IER_CLR_BIT(irq_idx); - } else { - /* disable the nubus irq by changing dir to output */ - /* except on PMU */ + break; + case MAC_VIA_QUADRA: if ((macintosh_config->adb_type != MAC_ADB_PB1) && - (macintosh_config->adb_type != MAC_ADB_PB2)) { - via2[vDirA] |= irq_bit; - } + (macintosh_config->adb_type != MAC_ADB_PB2)) + via2[vDirA] |= 1 << irq_idx; + break; } - nubus_active &= ~irq_bit; } } @@ -580,7 +625,9 @@ void via_irq_clear(int irq) { } else if (irq_src == 2) { via2[gIFR] = irq_bit | rbv_clear; } else if (irq_src == 7) { - /* FIXME: hmm.. */ + /* FIXME: There is no way to clear an individual nubus slot + * IRQ flag, other than getting the device to do it. + */ } } @@ -600,6 +647,7 @@ int via_irq_pending(int irq) } else if (irq_src == 2) { return via2[gIFR] & irq_bit; } else if (irq_src == 7) { + /* Always 0 for MAC_VIA_QUADRA if the slot irq is disabled. */ return ~via2[gBufA] & irq_bit; } return 0; diff --git a/arch/m68k/q40/config.c b/arch/m68k/q40/config.c index 92f873cc706..476e18eca75 100644 --- a/arch/m68k/q40/config.c +++ b/arch/m68k/q40/config.c @@ -35,35 +35,35 @@ #include <asm/machdep.h> #include <asm/q40_master.h> -extern irqreturn_t q40_process_int (int level, struct pt_regs *regs); -extern void q40_init_IRQ (void); +extern irqreturn_t q40_process_int(int level, struct pt_regs *regs); +extern void q40_init_IRQ(void); static void q40_get_model(char *model); static int q40_get_hardware_list(char *buffer); extern void q40_sched_init(irq_handler_t handler); -extern unsigned long q40_gettimeoffset (void); -extern int q40_hwclk (int, struct rtc_time *); -extern unsigned int q40_get_ss (void); -extern int q40_set_clock_mmss (unsigned long); +extern unsigned long q40_gettimeoffset(void); +extern int q40_hwclk(int, struct rtc_time *); +extern unsigned int q40_get_ss(void); +extern int q40_set_clock_mmss(unsigned long); static int q40_get_rtc_pll(struct rtc_pll_info *pll); static int q40_set_rtc_pll(struct rtc_pll_info *pll); -extern void q40_reset (void); +extern void q40_reset(void); void q40_halt(void); extern void q40_waitbut(void); -void q40_set_vectors (void); +void q40_set_vectors(void); -extern void q40_mksound(unsigned int /*freq*/, unsigned int /*ticks*/ ); +extern void q40_mksound(unsigned int /*freq*/, unsigned int /*ticks*/); -extern char m68k_debug_device[]; static void q40_mem_console_write(struct console *co, const char *b, - unsigned int count); + unsigned int count); extern int ql_ticks; static struct console q40_console_driver = { - .name = "debug", - .flags = CON_PRINTBUFFER, - .index = -1, + .name = "debug", + .write = q40_mem_console_write, + .flags = CON_PRINTBUFFER, + .index = -1, }; @@ -74,150 +74,162 @@ static int _cpleft; static void q40_mem_console_write(struct console *co, const char *s, unsigned int count) { - char *p=(char *)s; - - if (count<_cpleft) - while (count-- >0){ - *q40_mem_cptr=*p++; - q40_mem_cptr+=4; - _cpleft--; - } + const char *p = s; + + if (count < _cpleft) { + while (count-- > 0) { + *q40_mem_cptr = *p++; + q40_mem_cptr += 4; + _cpleft--; + } + } +} + +static int __init q40_debug_setup(char *arg) +{ + /* useful for early debugging stages - writes kernel messages into SRAM */ + if (MACH_IS_Q40 && !strncmp(arg, "mem", 3)) { + /*printk("using NVRAM debug, q40_mem_cptr=%p\n",q40_mem_cptr);*/ + _cpleft = 2000 - ((long)q40_mem_cptr-0xff020000) / 4; + register_console(&q40_console_driver); + } + return 0; } + +early_param("debug", q40_debug_setup); + #if 0 void printq40(char *str) { - int l=strlen(str); - char *p=q40_mem_cptr; - - while (l-- >0 && _cpleft-- >0) - { - *p=*str++; - p+=4; - } - q40_mem_cptr=p; + int l = strlen(str); + char *p = q40_mem_cptr; + + while (l-- > 0 && _cpleft-- > 0) { + *p = *str++; + p += 4; + } + q40_mem_cptr = p; } #endif -static int halted=0; +static int halted; #ifdef CONFIG_HEARTBEAT static void q40_heartbeat(int on) { - if (halted) return; + if (halted) + return; - if (on) - Q40_LED_ON(); - else - Q40_LED_OFF(); + if (on) + Q40_LED_ON(); + else + Q40_LED_OFF(); } #endif void q40_reset(void) { - halted=1; - printk ("\n\n*******************************************\n" + halted = 1; + printk("\n\n*******************************************\n" "Called q40_reset : press the RESET button!! \n" "*******************************************\n"); Q40_LED_ON(); - while(1) ; + while (1) + ; } void q40_halt(void) { - halted=1; - printk ("\n\n*******************\n" - " Called q40_halt\n" - "*******************\n"); + halted = 1; + printk("\n\n*******************\n" + " Called q40_halt\n" + "*******************\n"); Q40_LED_ON(); - while(1) ; + while (1) + ; } static void q40_get_model(char *model) { - sprintf(model, "Q40"); + sprintf(model, "Q40"); } /* No hardware options on Q40? */ static int q40_get_hardware_list(char *buffer) { - *buffer = '\0'; - return 0; + *buffer = '\0'; + return 0; } -static unsigned int serports[]={0x3f8,0x2f8,0x3e8,0x2e8,0}; +static unsigned int serports[] = +{ + 0x3f8,0x2f8,0x3e8,0x2e8,0 +}; void q40_disable_irqs(void) { - unsigned i,j; + unsigned i, j; - j=0; - while((i=serports[j++])) outb(0,i+UART_IER); - master_outb(0,EXT_ENABLE_REG); - master_outb(0,KEY_IRQ_ENABLE_REG); + j = 0; + while ((i = serports[j++])) + outb(0, i + UART_IER); + master_outb(0, EXT_ENABLE_REG); + master_outb(0, KEY_IRQ_ENABLE_REG); } void __init config_q40(void) { - mach_sched_init = q40_sched_init; + mach_sched_init = q40_sched_init; - mach_init_IRQ = q40_init_IRQ; - mach_gettimeoffset = q40_gettimeoffset; - mach_hwclk = q40_hwclk; - mach_get_ss = q40_get_ss; - mach_get_rtc_pll = q40_get_rtc_pll; - mach_set_rtc_pll = q40_set_rtc_pll; - mach_set_clock_mmss = q40_set_clock_mmss; + mach_init_IRQ = q40_init_IRQ; + mach_gettimeoffset = q40_gettimeoffset; + mach_hwclk = q40_hwclk; + mach_get_ss = q40_get_ss; + mach_get_rtc_pll = q40_get_rtc_pll; + mach_set_rtc_pll = q40_set_rtc_pll; + mach_set_clock_mmss = q40_set_clock_mmss; - mach_reset = q40_reset; - mach_get_model = q40_get_model; - mach_get_hardware_list = q40_get_hardware_list; + mach_reset = q40_reset; + mach_get_model = q40_get_model; + mach_get_hardware_list = q40_get_hardware_list; #if defined(CONFIG_INPUT_M68K_BEEP) || defined(CONFIG_INPUT_M68K_BEEP_MODULE) - mach_beep = q40_mksound; + mach_beep = q40_mksound; #endif #ifdef CONFIG_HEARTBEAT - mach_heartbeat = q40_heartbeat; + mach_heartbeat = q40_heartbeat; #endif - mach_halt = q40_halt; - - /* disable a few things that SMSQ might have left enabled */ - q40_disable_irqs(); - - /* no DMA at all, but ide-scsi requires it.. make sure - * all physical RAM fits into the boundary - otherwise - * allocator may play costly and useless tricks */ - mach_max_dma_address = 1024*1024*1024; - - /* useful for early debugging stages - writes kernel messages into SRAM */ - if (!strncmp( m68k_debug_device,"mem",3 )) - { - /*printk("using NVRAM debug, q40_mem_cptr=%p\n",q40_mem_cptr);*/ - _cpleft=2000-((long)q40_mem_cptr-0xff020000)/4; - q40_console_driver.write = q40_mem_console_write; - register_console(&q40_console_driver); - } + mach_halt = q40_halt; + + /* disable a few things that SMSQ might have left enabled */ + q40_disable_irqs(); + + /* no DMA at all, but ide-scsi requires it.. make sure + * all physical RAM fits into the boundary - otherwise + * allocator may play costly and useless tricks */ + mach_max_dma_address = 1024*1024*1024; } int q40_parse_bootinfo(const struct bi_record *rec) { - return 1; + return 1; } -static inline unsigned char bcd2bin (unsigned char b) +static inline unsigned char bcd2bin(unsigned char b) { - return ((b>>4)*10 + (b&15)); + return (b >> 4) * 10 + (b & 15); } -static inline unsigned char bin2bcd (unsigned char b) +static inline unsigned char bin2bcd(unsigned char b) { - return (((b/10)*16) + (b%10)); + return (b / 10) * 16 + (b % 10); } -unsigned long q40_gettimeoffset (void) +unsigned long q40_gettimeoffset(void) { - return 5000*(ql_ticks!=0); + return 5000 * (ql_ticks != 0); } @@ -238,9 +250,9 @@ unsigned long q40_gettimeoffset (void) int q40_hwclk(int op, struct rtc_time *t) { - if (op) - { /* Write.... */ - Q40_RTC_CTRL |= Q40_RTC_WRITE; + if (op) { + /* Write.... */ + Q40_RTC_CTRL |= Q40_RTC_WRITE; Q40_RTC_SECS = bin2bcd(t->tm_sec); Q40_RTC_MINS = bin2bcd(t->tm_min); @@ -251,25 +263,23 @@ int q40_hwclk(int op, struct rtc_time *t) if (t->tm_wday >= 0) Q40_RTC_DOW = bin2bcd(t->tm_wday+1); - Q40_RTC_CTRL &= ~(Q40_RTC_WRITE); - } - else - { /* Read.... */ - Q40_RTC_CTRL |= Q40_RTC_READ; - - t->tm_year = bcd2bin (Q40_RTC_YEAR); - t->tm_mon = bcd2bin (Q40_RTC_MNTH)-1; - t->tm_mday = bcd2bin (Q40_RTC_DATE); - t->tm_hour = bcd2bin (Q40_RTC_HOUR); - t->tm_min = bcd2bin (Q40_RTC_MINS); - t->tm_sec = bcd2bin (Q40_RTC_SECS); - - Q40_RTC_CTRL &= ~(Q40_RTC_READ); - - if (t->tm_year < 70) - t->tm_year += 100; - t->tm_wday = bcd2bin(Q40_RTC_DOW)-1; - + Q40_RTC_CTRL &= ~(Q40_RTC_WRITE); + } else { + /* Read.... */ + Q40_RTC_CTRL |= Q40_RTC_READ; + + t->tm_year = bcd2bin (Q40_RTC_YEAR); + t->tm_mon = bcd2bin (Q40_RTC_MNTH)-1; + t->tm_mday = bcd2bin (Q40_RTC_DATE); + t->tm_hour = bcd2bin (Q40_RTC_HOUR); + t->tm_min = bcd2bin (Q40_RTC_MINS); + t->tm_sec = bcd2bin (Q40_RTC_SECS); + + Q40_RTC_CTRL &= ~(Q40_RTC_READ); + + if (t->tm_year < 70) + t->tm_year += 100; + t->tm_wday = bcd2bin(Q40_RTC_DOW)-1; } return 0; @@ -285,29 +295,25 @@ unsigned int q40_get_ss(void) * clock is out by > 30 minutes. Logic lifted from atari code. */ -int q40_set_clock_mmss (unsigned long nowtime) +int q40_set_clock_mmss(unsigned long nowtime) { int retval = 0; short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60; int rtc_minutes; + rtc_minutes = bcd2bin(Q40_RTC_MINS); - rtc_minutes = bcd2bin (Q40_RTC_MINS); - - if ((rtc_minutes < real_minutes - ? real_minutes - rtc_minutes - : rtc_minutes - real_minutes) < 30) - { - Q40_RTC_CTRL |= Q40_RTC_WRITE; + if ((rtc_minutes < real_minutes ? + real_minutes - rtc_minutes : + rtc_minutes - real_minutes) < 30) { + Q40_RTC_CTRL |= Q40_RTC_WRITE; Q40_RTC_MINS = bin2bcd(real_minutes); Q40_RTC_SECS = bin2bcd(real_seconds); Q40_RTC_CTRL &= ~(Q40_RTC_WRITE); - } - else + } else retval = -1; - return retval; } @@ -318,21 +324,23 @@ int q40_set_clock_mmss (unsigned long nowtime) static int q40_get_rtc_pll(struct rtc_pll_info *pll) { - int tmp=Q40_RTC_CTRL; + int tmp = Q40_RTC_CTRL; + pll->pll_value = tmp & Q40_RTC_PLL_MASK; if (tmp & Q40_RTC_PLL_SIGN) pll->pll_value = -pll->pll_value; - pll->pll_max=31; - pll->pll_min=-31; - pll->pll_posmult=512; - pll->pll_negmult=256; - pll->pll_clock=125829120; + pll->pll_max = 31; + pll->pll_min = -31; + pll->pll_posmult = 512; + pll->pll_negmult = 256; + pll->pll_clock = 125829120; + return 0; } static int q40_set_rtc_pll(struct rtc_pll_info *pll) { - if (!pll->pll_ctrl){ + if (!pll->pll_ctrl) { /* the docs are a bit unclear so I am doublesetting */ /* RTC_WRITE here ... */ int tmp = (pll->pll_value & 31) | (pll->pll_value<0 ? 32 : 0) | diff --git a/arch/m68k/sun3/sun3ints.c b/arch/m68k/sun3/sun3ints.c index baf74e8de8b..4232a2c2fae 100644 --- a/arch/m68k/sun3/sun3ints.c +++ b/arch/m68k/sun3/sun3ints.c @@ -103,7 +103,7 @@ void sun3_init_IRQ(void) m68k_setup_auto_interrupt(sun3_inthandle); m68k_setup_irq_controller(&sun3_irq_controller, IRQ_AUTO_1, 7); - m68k_setup_user_interrupt(VEC_USER, 192, NULL); + m68k_setup_user_interrupt(VEC_USER, 128, NULL); request_irq(IRQ_AUTO_5, sun3_int5, 0, "int5", NULL); request_irq(IRQ_AUTO_7, sun3_int7, 0, "int7", NULL); diff --git a/arch/m68k/sun3x/prom.c b/arch/m68k/sun3x/prom.c index 574cf06df9e..48f8eb7b156 100644 --- a/arch/m68k/sun3x/prom.c +++ b/arch/m68k/sun3x/prom.c @@ -34,100 +34,101 @@ e_vector *sun3x_prom_vbr; /* Handle returning to the prom */ void sun3x_halt(void) { - unsigned long flags; + unsigned long flags; - /* Disable interrupts while we mess with things */ - local_irq_save(flags); + /* Disable interrupts while we mess with things */ + local_irq_save(flags); - /* Restore prom vbr */ - __asm__ volatile ("movec %0,%%vbr" : : "r" ((void*)sun3x_prom_vbr)); + /* Restore prom vbr */ + asm volatile ("movec %0,%%vbr" : : "r" ((void*)sun3x_prom_vbr)); - /* Restore prom NMI clock */ -// sun3x_disable_intreg(5); - sun3_enable_irq(7); + /* Restore prom NMI clock */ +// sun3x_disable_intreg(5); + sun3_enable_irq(7); - /* Let 'er rip */ - __asm__ volatile ("trap #14" : : ); + /* Let 'er rip */ + asm volatile ("trap #14"); - /* Restore everything */ - sun3_disable_irq(7); - sun3_enable_irq(5); + /* Restore everything */ + sun3_disable_irq(7); + sun3_enable_irq(5); - __asm__ volatile ("movec %0,%%vbr" : : "r" ((void*)vectors)); - local_irq_restore(flags); + asm volatile ("movec %0,%%vbr" : : "r" ((void*)vectors)); + local_irq_restore(flags); } void sun3x_reboot(void) { - /* This never returns, don't bother saving things */ - local_irq_disable(); + /* This never returns, don't bother saving things */ + local_irq_disable(); - /* Restore prom vbr */ - __asm__ volatile ("movec %0,%%vbr" : : "r" ((void*)sun3x_prom_vbr)); + /* Restore prom vbr */ + asm volatile ("movec %0,%%vbr" : : "r" ((void*)sun3x_prom_vbr)); - /* Restore prom NMI clock */ - sun3_disable_irq(5); - sun3_enable_irq(7); + /* Restore prom NMI clock */ + sun3_disable_irq(5); + sun3_enable_irq(7); - /* Let 'er rip */ - (*romvec->pv_reboot)("vmlinux"); + /* Let 'er rip */ + (*romvec->pv_reboot)("vmlinux"); } -extern char m68k_debug_device[]; - static void sun3x_prom_write(struct console *co, const char *s, unsigned int count) { - while (count--) { - if (*s == '\n') - sun3x_putchar('\r'); - sun3x_putchar(*s++); - } + while (count--) { + if (*s == '\n') + sun3x_putchar('\r'); + sun3x_putchar(*s++); + } } /* debug console - write-only */ static struct console sun3x_debug = { - .name = "debug", - .write = sun3x_prom_write, - .flags = CON_PRINTBUFFER, - .index = -1, + .name = "debug", + .write = sun3x_prom_write, + .flags = CON_PRINTBUFFER, + .index = -1, }; void sun3x_prom_init(void) { - /* Read the vector table */ - - sun3x_putchar = *(void (**)(int)) (SUN3X_P_PUTCHAR); - sun3x_getchar = *(int (**)(void)) (SUN3X_P_GETCHAR); - sun3x_mayget = *(int (**)(void)) (SUN3X_P_MAYGET); - sun3x_mayput = *(int (**)(int)) (SUN3X_P_MAYPUT); - sun3x_prom_reboot = *(void (**)(void)) (SUN3X_P_REBOOT); - sun3x_prom_abort = *(e_vector *) (SUN3X_P_ABORT); - romvec = (struct linux_romvec *)SUN3X_PROM_BASE; - - idprom_init(); - - if(!((idprom->id_machtype & SM_ARCH_MASK) == SM_SUN3X)) { - printk("Warning: machine reports strange type %02x\n", - idprom->id_machtype); - printk("Pretending it's a 3/80, but very afraid...\n"); - idprom->id_machtype = SM_SUN3X | SM_3_80; - } - - /* point trap #14 at abort. - * XXX this is futile since we restore the vbr first - oops - */ - vectors[VEC_TRAP14] = sun3x_prom_abort; - - /* If debug=prom was specified, start the debug console */ - - if (!strcmp(m68k_debug_device, "prom")) - register_console(&sun3x_debug); - + /* Read the vector table */ + + sun3x_putchar = *(void (**)(int)) (SUN3X_P_PUTCHAR); + sun3x_getchar = *(int (**)(void)) (SUN3X_P_GETCHAR); + sun3x_mayget = *(int (**)(void)) (SUN3X_P_MAYGET); + sun3x_mayput = *(int (**)(int)) (SUN3X_P_MAYPUT); + sun3x_prom_reboot = *(void (**)(void)) (SUN3X_P_REBOOT); + sun3x_prom_abort = *(e_vector *) (SUN3X_P_ABORT); + romvec = (struct linux_romvec *)SUN3X_PROM_BASE; + + idprom_init(); + + if (!((idprom->id_machtype & SM_ARCH_MASK) == SM_SUN3X)) { + printk("Warning: machine reports strange type %02x\n", + idprom->id_machtype); + printk("Pretending it's a 3/80, but very afraid...\n"); + idprom->id_machtype = SM_SUN3X | SM_3_80; + } + + /* point trap #14 at abort. + * XXX this is futile since we restore the vbr first - oops + */ + vectors[VEC_TRAP14] = sun3x_prom_abort; +} +static int __init sun3x_debug_setup(char *arg) +{ + /* If debug=prom was specified, start the debug console */ + if (MACH_IS_SUN3X && !strcmp(arg, "prom")) + register_console(&sun3x_debug); + return 0; } +early_param("debug", sun3x_debug_setup); + /* some prom functions to export */ int prom_getintdefault(int node, char *property, int deflt) { @@ -141,7 +142,6 @@ int prom_getbool (int node, char *prop) void prom_printf(char *fmt, ...) { - } void prom_halt (void) @@ -159,7 +159,7 @@ prom_get_idprom(char *idbuf, int num_bytes) int i; /* make a copy of the idprom structure */ - for(i = 0; i < num_bytes; i++) + for (i = 0; i < num_bytes; i++) idbuf[i] = ((char *)SUN3X_IDPROM)[i]; return idbuf[0]; diff --git a/arch/powerpc/platforms/powermac/cpufreq_32.c b/arch/powerpc/platforms/powermac/cpufreq_32.c index 8943a9456bb..1fe35dab0e9 100644 --- a/arch/powerpc/platforms/powermac/cpufreq_32.c +++ b/arch/powerpc/platforms/powermac/cpufreq_32.c @@ -25,7 +25,6 @@ #include <linux/cpufreq.h> #include <linux/init.h> #include <linux/sysdev.h> -#include <linux/i2c.h> #include <linux/hardirq.h> #include <asm/prom.h> #include <asm/machdep.h> diff --git a/arch/s390/crypto/aes_s390.c b/arch/s390/crypto/aes_s390.c index 91636353f6f..3660ca6a330 100644 --- a/arch/s390/crypto/aes_s390.c +++ b/arch/s390/crypto/aes_s390.c @@ -119,7 +119,8 @@ static struct crypto_alg aes_alg = { .cra_name = "aes", .cra_driver_name = "aes-s390", .cra_priority = CRYPT_S390_PRIORITY, - .cra_flags = CRYPTO_ALG_TYPE_CIPHER, + .cra_flags = CRYPTO_ALG_TYPE_CIPHER | + CRYPTO_ALG_NEED_FALLBACK, .cra_blocksize = AES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct s390_aes_ctx), .cra_module = THIS_MODULE, @@ -206,7 +207,8 @@ static struct crypto_alg ecb_aes_alg = { .cra_name = "ecb(aes)", .cra_driver_name = "ecb-aes-s390", .cra_priority = CRYPT_S390_COMPOSITE_PRIORITY, - .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER | + CRYPTO_ALG_NEED_FALLBACK, .cra_blocksize = AES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct s390_aes_ctx), .cra_type = &crypto_blkcipher_type, @@ -300,7 +302,8 @@ static struct crypto_alg cbc_aes_alg = { .cra_name = "cbc(aes)", .cra_driver_name = "cbc-aes-s390", .cra_priority = CRYPT_S390_COMPOSITE_PRIORITY, - .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER | + CRYPTO_ALG_NEED_FALLBACK, .cra_blocksize = AES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct s390_aes_ctx), .cra_type = &crypto_blkcipher_type, @@ -333,10 +336,14 @@ static int __init aes_init(void) return -EOPNOTSUPP; /* z9 109 and z9 BC/EC only support 128 bit key length */ - if (keylen_flag == AES_KEYLEN_128) + if (keylen_flag == AES_KEYLEN_128) { + aes_alg.cra_u.cipher.cia_max_keysize = AES_MIN_KEY_SIZE; + ecb_aes_alg.cra_u.blkcipher.max_keysize = AES_MIN_KEY_SIZE; + cbc_aes_alg.cra_u.blkcipher.max_keysize = AES_MIN_KEY_SIZE; printk(KERN_INFO "aes_s390: hardware acceleration only available for" "128 bit keys\n"); + } ret = crypto_register_alg(&aes_alg); if (ret) diff --git a/arch/s390/kernel/kprobes.c b/arch/s390/kernel/kprobes.c index 993f3538149..23c61f6d965 100644 --- a/arch/s390/kernel/kprobes.c +++ b/arch/s390/kernel/kprobes.c @@ -516,7 +516,7 @@ out: return 1; } -static int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr) +int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr) { struct kprobe *cur = kprobe_running(); struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); @@ -603,7 +603,6 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self, ret = NOTIFY_STOP; break; case DIE_TRAP: - case DIE_PAGE_FAULT: /* kprobe_running() needs smp_processor_id() */ preempt_disable(); if (kprobe_running() && diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 3dfd0985861..6bfb0889eb1 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -65,7 +65,7 @@ long psw_user_bits = (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_HOME | * User copy operations. */ struct uaccess_ops uaccess; -EXPORT_SYMBOL_GPL(uaccess); +EXPORT_SYMBOL(uaccess); /* * Machine setup.. @@ -74,6 +74,8 @@ unsigned int console_mode = 0; unsigned int console_devno = -1; unsigned int console_irq = -1; unsigned long machine_flags = 0; +unsigned long elf_hwcap = 0; +char elf_platform[ELF_PLATFORM_SIZE]; struct mem_chunk __initdata memory_chunk[MEMORY_CHUNKS]; volatile int __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */ @@ -749,6 +751,98 @@ setup_memory(void) #endif } +static __init unsigned int stfl(void) +{ + asm volatile( + " .insn s,0xb2b10000,0(0)\n" /* stfl */ + "0:\n" + EX_TABLE(0b,0b)); + return S390_lowcore.stfl_fac_list; +} + +static __init int stfle(unsigned long long *list, int doublewords) +{ + typedef struct { unsigned long long _[doublewords]; } addrtype; + register unsigned long __nr asm("0") = doublewords - 1; + + asm volatile(".insn s,0xb2b00000,%0" /* stfle */ + : "=m" (*(addrtype *) list), "+d" (__nr) : : "cc"); + return __nr + 1; +} + +/* + * Setup hardware capabilities. + */ +static void __init setup_hwcaps(void) +{ + static const int stfl_bits[6] = { 0, 2, 7, 17, 19, 21 }; + struct cpuinfo_S390 *cpuinfo = &S390_lowcore.cpu_data; + unsigned long long facility_list_extended; + unsigned int facility_list; + int i; + + facility_list = stfl(); + /* + * The store facility list bits numbers as found in the principles + * of operation are numbered with bit 1UL<<31 as number 0 to + * bit 1UL<<0 as number 31. + * Bit 0: instructions named N3, "backported" to esa-mode + * Bit 2: z/Architecture mode is active + * Bit 7: the store-facility-list-extended facility is installed + * Bit 17: the message-security assist is installed + * Bit 19: the long-displacement facility is installed + * Bit 21: the extended-immediate facility is installed + * These get translated to: + * HWCAP_S390_ESAN3 bit 0, HWCAP_S390_ZARCH bit 1, + * HWCAP_S390_STFLE bit 2, HWCAP_S390_MSA bit 3, + * HWCAP_S390_LDISP bit 4, and HWCAP_S390_EIMM bit 5. + */ + for (i = 0; i < 6; i++) + if (facility_list & (1UL << (31 - stfl_bits[i]))) + elf_hwcap |= 1UL << i; + + /* + * Check for additional facilities with store-facility-list-extended. + * stfle stores doublewords (8 byte) with bit 1ULL<<63 as bit 0 + * and 1ULL<<0 as bit 63. Bits 0-31 contain the same information + * as stored by stfl, bits 32-xxx contain additional facilities. + * How many facility words are stored depends on the number of + * doublewords passed to the instruction. The additional facilites + * are: + * Bit 43: decimal floating point facility is installed + * translated to: + * HWCAP_S390_DFP bit 6. + */ + if ((elf_hwcap & (1UL << 2)) && + stfle(&facility_list_extended, 1) > 0) { + if (facility_list_extended & (1ULL << (64 - 43))) + elf_hwcap |= 1UL << 6; + } + + switch (cpuinfo->cpu_id.machine) { + case 0x9672: +#if !defined(CONFIG_64BIT) + default: /* Use "g5" as default for 31 bit kernels. */ +#endif + strcpy(elf_platform, "g5"); + break; + case 0x2064: + case 0x2066: +#if defined(CONFIG_64BIT) + default: /* Use "z900" as default for 64 bit kernels. */ +#endif + strcpy(elf_platform, "z900"); + break; + case 0x2084: + case 0x2086: + strcpy(elf_platform, "z990"); + break; + case 0x2094: + strcpy(elf_platform, "z9-109"); + break; + } +} + /* * Setup function called from init/main.c just after the banner * was printed. @@ -805,6 +899,11 @@ setup_arch(char **cmdline_p) smp_setup_cpu_possible_map(); /* + * Setup capabilities (ELF_HWCAP & ELF_PLATFORM). + */ + setup_hwcaps(); + + /* * Create kernel page tables and switch to virtual addressing. */ paging_init(); @@ -839,8 +938,12 @@ void print_cpu_info(struct cpuinfo_S390 *cpuinfo) static int show_cpuinfo(struct seq_file *m, void *v) { + static const char *hwcap_str[7] = { + "esan3", "zarch", "stfle", "msa", "ldisp", "eimm", "dfp" + }; struct cpuinfo_S390 *cpuinfo; unsigned long n = (unsigned long) v - 1; + int i; s390_adjust_jiffies(); preempt_disable(); @@ -850,7 +953,13 @@ static int show_cpuinfo(struct seq_file *m, void *v) "bogomips per cpu: %lu.%02lu\n", num_online_cpus(), loops_per_jiffy/(500000/HZ), (loops_per_jiffy/(5000/HZ))%100); + seq_puts(m, "features\t: "); + for (i = 0; i < 7; i++) + if (hwcap_str[i] && (elf_hwcap & (1UL << i))) + seq_printf(m, "%s ", hwcap_str[i]); + seq_puts(m, "\n"); } + if (cpu_online(n)) { #ifdef CONFIG_SMP if (smp_processor_id() == n) diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index 2b76a879a7b..91f705adc3f 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c @@ -52,38 +52,24 @@ extern int sysctl_userprocess_debug; extern void die(const char *,struct pt_regs *,long); #ifdef CONFIG_KPROBES -static ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain); -int register_page_fault_notifier(struct notifier_block *nb) -{ - return atomic_notifier_chain_register(¬ify_page_fault_chain, nb); -} - -int unregister_page_fault_notifier(struct notifier_block *nb) -{ - return atomic_notifier_chain_unregister(¬ify_page_fault_chain, nb); -} - -static int __kprobes __notify_page_fault(struct pt_regs *regs, long err) -{ - struct die_args args = { .str = "page fault", - .trapnr = 14, - .signr = SIGSEGV }; - args.regs = regs; - args.err = err; - return atomic_notifier_call_chain(¬ify_page_fault_chain, - DIE_PAGE_FAULT, &args); -} - static inline int notify_page_fault(struct pt_regs *regs, long err) { - if (unlikely(kprobe_running())) - return __notify_page_fault(regs, err); - return NOTIFY_DONE; + int ret = 0; + + /* kprobe_running() needs smp_processor_id() */ + if (!user_mode(regs)) { + preempt_disable(); + if (kprobe_running() && kprobe_fault_handler(regs, 14)) + ret = 1; + preempt_enable(); + } + + return ret; } #else static inline int notify_page_fault(struct pt_regs *regs, long err) { - return NOTIFY_DONE; + return 0; } #endif @@ -319,7 +305,7 @@ do_exception(struct pt_regs *regs, unsigned long error_code, int write) int space; int si_code; - if (notify_page_fault(regs, error_code) == NOTIFY_STOP) + if (notify_page_fault(regs, error_code)) return; tsk = current; diff --git a/arch/x86_64/kernel/cpufreq/Kconfig b/arch/x86_64/kernel/cpufreq/Kconfig index 40acb67fb88..c0749d2479f 100644 --- a/arch/x86_64/kernel/cpufreq/Kconfig +++ b/arch/x86_64/kernel/cpufreq/Kconfig @@ -16,6 +16,9 @@ config X86_POWERNOW_K8 help This adds the CPUFreq driver for mobile AMD Opteron/Athlon64 processors. + To compile this driver as a module, choose M here: the + module will be called powernow-k8. + For details, take a look at <file:Documentation/cpu-freq/>. If in doubt, say N. @@ -38,6 +41,9 @@ config X86_SPEEDSTEP_CENTRINO mobile CPUs. This means Intel Pentium M (Centrino) CPUs or 64bit enabled Intel Xeons. + To compile this driver as a module, choose M here: the + module will be called speedstep-centrino. + For details, take a look at <file:Documentation/cpu-freq/>. If in doubt, say N. @@ -55,6 +61,9 @@ config X86_ACPI_CPUFREQ Processor Performance States. This driver also supports Intel Enhanced Speedstep. + To compile this driver as a module, choose M here: the + module will be called acpi-cpufreq. + For details, take a look at <file:Documentation/cpu-freq/>. If in doubt, say N. @@ -62,7 +71,7 @@ config X86_ACPI_CPUFREQ comment "shared options" config X86_ACPI_CPUFREQ_PROC_INTF - bool "/proc/acpi/processor/../performance interface (deprecated)" + bool "/proc/acpi/processor/../performance interface (deprecated)" depends on PROC_FS depends on X86_ACPI_CPUFREQ || X86_SPEEDSTEP_CENTRINO_ACPI || X86_POWERNOW_K8_ACPI help @@ -86,16 +95,18 @@ config X86_P4_CLOCKMOD slowdowns and noticeable latencies. Normally Speedstep should be used instead. + To compile this driver as a module, choose M here: the + module will be called p4-clockmod. + For details, take a look at <file:Documentation/cpu-freq/>. Unless you are absolutely sure say N. config X86_SPEEDSTEP_LIB - tristate - default X86_P4_CLOCKMOD + tristate + default X86_P4_CLOCKMOD endif endmenu - diff --git a/crypto/Kconfig b/crypto/Kconfig index 086fcec4472..620e14cabdc 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -16,6 +16,10 @@ config CRYPTO_ALGAPI help This option provides the API for cryptographic algorithms. +config CRYPTO_ABLKCIPHER + tristate + select CRYPTO_BLKCIPHER + config CRYPTO_BLKCIPHER tristate select CRYPTO_ALGAPI @@ -171,6 +175,15 @@ config CRYPTO_LRW The first 128, 192 or 256 bits in the key are used for AES and the rest is used to tie each cipher block to its logical position. +config CRYPTO_CRYPTD + tristate "Software async crypto daemon" + select CRYPTO_ABLKCIPHER + select CRYPTO_MANAGER + help + This is a generic software asynchronous crypto daemon that + converts an arbitrary synchronous software crypto algorithm + into an asynchronous algorithm that executes in a kernel thread. + config CRYPTO_DES tristate "DES and Triple DES EDE cipher algorithms" select CRYPTO_ALGAPI diff --git a/crypto/Makefile b/crypto/Makefile index 12f93f57817..cce46a1c9dc 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -8,6 +8,7 @@ crypto_algapi-$(CONFIG_PROC_FS) += proc.o crypto_algapi-objs := algapi.o $(crypto_algapi-y) obj-$(CONFIG_CRYPTO_ALGAPI) += crypto_algapi.o +obj-$(CONFIG_CRYPTO_ABLKCIPHER) += ablkcipher.o obj-$(CONFIG_CRYPTO_BLKCIPHER) += blkcipher.o crypto_hash-objs := hash.o @@ -29,6 +30,7 @@ obj-$(CONFIG_CRYPTO_ECB) += ecb.o obj-$(CONFIG_CRYPTO_CBC) += cbc.o obj-$(CONFIG_CRYPTO_PCBC) += pcbc.o obj-$(CONFIG_CRYPTO_LRW) += lrw.o +obj-$(CONFIG_CRYPTO_CRYPTD) += cryptd.o obj-$(CONFIG_CRYPTO_DES) += des.o obj-$(CONFIG_CRYPTO_FCRYPT) += fcrypt.o obj-$(CONFIG_CRYPTO_BLOWFISH) += blowfish.o diff --git a/crypto/ablkcipher.c b/crypto/ablkcipher.c new file mode 100644 index 00000000000..9348ddd84a5 --- /dev/null +++ b/crypto/ablkcipher.c @@ -0,0 +1,83 @@ +/* + * Asynchronous block chaining cipher operations. + * + * This is the asynchronous version of blkcipher.c indicating completion + * via a callback. + * + * Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + */ + +#include <crypto/algapi.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/seq_file.h> + +static int setkey(struct crypto_ablkcipher *tfm, const u8 *key, + unsigned int keylen) +{ + struct ablkcipher_alg *cipher = crypto_ablkcipher_alg(tfm); + + if (keylen < cipher->min_keysize || keylen > cipher->max_keysize) { + crypto_ablkcipher_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); + return -EINVAL; + } + + return cipher->setkey(tfm, key, keylen); +} + +static unsigned int crypto_ablkcipher_ctxsize(struct crypto_alg *alg, u32 type, + u32 mask) +{ + return alg->cra_ctxsize; +} + +static int crypto_init_ablkcipher_ops(struct crypto_tfm *tfm, u32 type, + u32 mask) +{ + struct ablkcipher_alg *alg = &tfm->__crt_alg->cra_ablkcipher; + struct ablkcipher_tfm *crt = &tfm->crt_ablkcipher; + + if (alg->ivsize > PAGE_SIZE / 8) + return -EINVAL; + + crt->setkey = setkey; + crt->encrypt = alg->encrypt; + crt->decrypt = alg->decrypt; + crt->ivsize = alg->ivsize; + + return 0; +} + +static void crypto_ablkcipher_show(struct seq_file *m, struct crypto_alg *alg) + __attribute__ ((unused)); +static void crypto_ablkcipher_show(struct seq_file *m, struct crypto_alg *alg) +{ + struct ablkcipher_alg *ablkcipher = &alg->cra_ablkcipher; + + seq_printf(m, "type : ablkcipher\n"); + seq_printf(m, "blocksize : %u\n", alg->cra_blocksize); + seq_printf(m, "min keysize : %u\n", ablkcipher->min_keysize); + seq_printf(m, "max keysize : %u\n", ablkcipher->max_keysize); + seq_printf(m, "ivsize : %u\n", ablkcipher->ivsize); + seq_printf(m, "qlen : %u\n", ablkcipher->queue->qlen); + seq_printf(m, "max qlen : %u\n", ablkcipher->queue->max_qlen); +} + +const struct crypto_type crypto_ablkcipher_type = { + .ctxsize = crypto_ablkcipher_ctxsize, + .init = crypto_init_ablkcipher_ops, +#ifdef CONFIG_PROC_FS + .show = crypto_ablkcipher_show, +#endif +}; +EXPORT_SYMBOL_GPL(crypto_ablkcipher_type); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Asynchronous block chaining cipher type"); diff --git a/crypto/algapi.c b/crypto/algapi.c index f7d2185b2c8..f137a432061 100644 --- a/crypto/algapi.c +++ b/crypto/algapi.c @@ -84,36 +84,47 @@ static void crypto_destroy_instance(struct crypto_alg *alg) crypto_tmpl_put(tmpl); } -static void crypto_remove_spawns(struct list_head *spawns, - struct list_head *list) +static void crypto_remove_spawn(struct crypto_spawn *spawn, + struct list_head *list, + struct list_head *secondary_spawns) { - struct crypto_spawn *spawn, *n; + struct crypto_instance *inst = spawn->inst; + struct crypto_template *tmpl = inst->tmpl; - list_for_each_entry_safe(spawn, n, spawns, list) { - struct crypto_instance *inst = spawn->inst; - struct crypto_template *tmpl = inst->tmpl; + list_del_init(&spawn->list); + spawn->alg = NULL; - list_del_init(&spawn->list); - spawn->alg = NULL; + if (crypto_is_dead(&inst->alg)) + return; - if (crypto_is_dead(&inst->alg)) - continue; + inst->alg.cra_flags |= CRYPTO_ALG_DEAD; + if (!tmpl || !crypto_tmpl_get(tmpl)) + return; - inst->alg.cra_flags |= CRYPTO_ALG_DEAD; - if (!tmpl || !crypto_tmpl_get(tmpl)) + crypto_notify(CRYPTO_MSG_ALG_UNREGISTER, &inst->alg); + list_move(&inst->alg.cra_list, list); + hlist_del(&inst->list); + inst->alg.cra_destroy = crypto_destroy_instance; + + list_splice(&inst->alg.cra_users, secondary_spawns); +} + +static void crypto_remove_spawns(struct list_head *spawns, + struct list_head *list, u32 new_type) +{ + struct crypto_spawn *spawn, *n; + LIST_HEAD(secondary_spawns); + + list_for_each_entry_safe(spawn, n, spawns, list) { + if ((spawn->alg->cra_flags ^ new_type) & spawn->mask) continue; - crypto_notify(CRYPTO_MSG_ALG_UNREGISTER, &inst->alg); - list_move(&inst->alg.cra_list, list); - hlist_del(&inst->list); - inst->alg.cra_destroy = crypto_destroy_instance; + crypto_remove_spawn(spawn, list, &secondary_spawns); + } - if (!list_empty(&inst->alg.cra_users)) { - if (&n->list == spawns) - n = list_entry(inst->alg.cra_users.next, - typeof(*n), list); - __list_splice(&inst->alg.cra_users, spawns->prev); - } + while (!list_empty(&secondary_spawns)) { + list_for_each_entry_safe(spawn, n, &secondary_spawns, list) + crypto_remove_spawn(spawn, list, &secondary_spawns); } } @@ -164,7 +175,7 @@ static int __crypto_register_alg(struct crypto_alg *alg, q->cra_priority > alg->cra_priority) continue; - crypto_remove_spawns(&q->cra_users, list); + crypto_remove_spawns(&q->cra_users, list, alg->cra_flags); } list_add(&alg->cra_list, &crypto_alg_list); @@ -214,7 +225,7 @@ static int crypto_remove_alg(struct crypto_alg *alg, struct list_head *list) crypto_notify(CRYPTO_MSG_ALG_UNREGISTER, alg); list_del_init(&alg->cra_list); - crypto_remove_spawns(&alg->cra_users, list); + crypto_remove_spawns(&alg->cra_users, list, alg->cra_flags); return 0; } @@ -351,11 +362,12 @@ err: EXPORT_SYMBOL_GPL(crypto_register_instance); int crypto_init_spawn(struct crypto_spawn *spawn, struct crypto_alg *alg, - struct crypto_instance *inst) + struct crypto_instance *inst, u32 mask) { int err = -EAGAIN; spawn->inst = inst; + spawn->mask = mask; down_write(&crypto_alg_sem); if (!crypto_is_moribund(alg)) { @@ -425,15 +437,45 @@ int crypto_unregister_notifier(struct notifier_block *nb) } EXPORT_SYMBOL_GPL(crypto_unregister_notifier); -struct crypto_alg *crypto_get_attr_alg(void *param, unsigned int len, - u32 type, u32 mask) +struct crypto_attr_type *crypto_get_attr_type(struct rtattr **tb) +{ + struct rtattr *rta = tb[CRYPTOA_TYPE - 1]; + struct crypto_attr_type *algt; + + if (!rta) + return ERR_PTR(-ENOENT); + if (RTA_PAYLOAD(rta) < sizeof(*algt)) + return ERR_PTR(-EINVAL); + + algt = RTA_DATA(rta); + + return algt; +} +EXPORT_SYMBOL_GPL(crypto_get_attr_type); + +int crypto_check_attr_type(struct rtattr **tb, u32 type) { - struct rtattr *rta = param; + struct crypto_attr_type *algt; + + algt = crypto_get_attr_type(tb); + if (IS_ERR(algt)) + return PTR_ERR(algt); + + if ((algt->type ^ type) & algt->mask) + return -EINVAL; + + return 0; +} +EXPORT_SYMBOL_GPL(crypto_check_attr_type); + +struct crypto_alg *crypto_get_attr_alg(struct rtattr **tb, u32 type, u32 mask) +{ + struct rtattr *rta = tb[CRYPTOA_ALG - 1]; struct crypto_attr_alg *alga; - if (!RTA_OK(rta, len)) - return ERR_PTR(-EBADR); - if (rta->rta_type != CRYPTOA_ALG || RTA_PAYLOAD(rta) < sizeof(*alga)) + if (!rta) + return ERR_PTR(-ENOENT); + if (RTA_PAYLOAD(rta) < sizeof(*alga)) return ERR_PTR(-EINVAL); alga = RTA_DATA(rta); @@ -464,7 +506,8 @@ struct crypto_instance *crypto_alloc_instance(const char *name, goto err_free_inst; spawn = crypto_instance_ctx(inst); - err = crypto_init_spawn(spawn, alg, inst); + err = crypto_init_spawn(spawn, alg, inst, + CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC); if (err) goto err_free_inst; @@ -477,6 +520,68 @@ err_free_inst: } EXPORT_SYMBOL_GPL(crypto_alloc_instance); +void crypto_init_queue(struct crypto_queue *queue, unsigned int max_qlen) +{ + INIT_LIST_HEAD(&queue->list); + queue->backlog = &queue->list; + queue->qlen = 0; + queue->max_qlen = max_qlen; +} +EXPORT_SYMBOL_GPL(crypto_init_queue); + +int crypto_enqueue_request(struct crypto_queue *queue, + struct crypto_async_request *request) +{ + int err = -EINPROGRESS; + + if (unlikely(queue->qlen >= queue->max_qlen)) { + err = -EBUSY; + if (!(request->flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) + goto out; + if (queue->backlog == &queue->list) + queue->backlog = &request->list; + } + + queue->qlen++; + list_add_tail(&request->list, &queue->list); + +out: + return err; +} +EXPORT_SYMBOL_GPL(crypto_enqueue_request); + +struct crypto_async_request *crypto_dequeue_request(struct crypto_queue *queue) +{ + struct list_head *request; + + if (unlikely(!queue->qlen)) + return NULL; + + queue->qlen--; + + if (queue->backlog != &queue->list) + queue->backlog = queue->backlog->next; + + request = queue->list.next; + list_del(request); + + return list_entry(request, struct crypto_async_request, list); +} +EXPORT_SYMBOL_GPL(crypto_dequeue_request); + +int crypto_tfm_in_queue(struct crypto_queue *queue, struct crypto_tfm *tfm) +{ + struct crypto_async_request *req; + + list_for_each_entry(req, &queue->list, list) { + if (req->tfm == tfm) + return 1; + } + + return 0; +} +EXPORT_SYMBOL_GPL(crypto_tfm_in_queue); + static int __init crypto_algapi_init(void) { crypto_init_proc(); diff --git a/crypto/blkcipher.c b/crypto/blkcipher.c index b5befe8c3a9..8edf40c835a 100644 --- a/crypto/blkcipher.c +++ b/crypto/blkcipher.c @@ -349,13 +349,48 @@ static int setkey(struct crypto_tfm *tfm, const u8 *key, return cipher->setkey(tfm, key, keylen); } +static int async_setkey(struct crypto_ablkcipher *tfm, const u8 *key, + unsigned int keylen) +{ + return setkey(crypto_ablkcipher_tfm(tfm), key, keylen); +} + +static int async_encrypt(struct ablkcipher_request *req) +{ + struct crypto_tfm *tfm = req->base.tfm; + struct blkcipher_alg *alg = &tfm->__crt_alg->cra_blkcipher; + struct blkcipher_desc desc = { + .tfm = __crypto_blkcipher_cast(tfm), + .info = req->info, + .flags = req->base.flags, + }; + + + return alg->encrypt(&desc, req->dst, req->src, req->nbytes); +} + +static int async_decrypt(struct ablkcipher_request *req) +{ + struct crypto_tfm *tfm = req->base.tfm; + struct blkcipher_alg *alg = &tfm->__crt_alg->cra_blkcipher; + struct blkcipher_desc desc = { + .tfm = __crypto_blkcipher_cast(tfm), + .info = req->info, + .flags = req->base.flags, + }; + + return alg->decrypt(&desc, req->dst, req->src, req->nbytes); +} + static unsigned int crypto_blkcipher_ctxsize(struct crypto_alg *alg, u32 type, u32 mask) { struct blkcipher_alg *cipher = &alg->cra_blkcipher; unsigned int len = alg->cra_ctxsize; - if (cipher->ivsize) { + type ^= CRYPTO_ALG_ASYNC; + mask &= CRYPTO_ALG_ASYNC; + if ((type & mask) && cipher->ivsize) { len = ALIGN(len, (unsigned long)alg->cra_alignmask + 1); len += cipher->ivsize; } @@ -363,16 +398,26 @@ static unsigned int crypto_blkcipher_ctxsize(struct crypto_alg *alg, u32 type, return len; } -static int crypto_init_blkcipher_ops(struct crypto_tfm *tfm, u32 type, u32 mask) +static int crypto_init_blkcipher_ops_async(struct crypto_tfm *tfm) +{ + struct ablkcipher_tfm *crt = &tfm->crt_ablkcipher; + struct blkcipher_alg *alg = &tfm->__crt_alg->cra_blkcipher; + + crt->setkey = async_setkey; + crt->encrypt = async_encrypt; + crt->decrypt = async_decrypt; + crt->ivsize = alg->ivsize; + + return 0; +} + +static int crypto_init_blkcipher_ops_sync(struct crypto_tfm *tfm) { struct blkcipher_tfm *crt = &tfm->crt_blkcipher; struct blkcipher_alg *alg = &tfm->__crt_alg->cra_blkcipher; unsigned long align = crypto_tfm_alg_alignmask(tfm) + 1; unsigned long addr; - if (alg->ivsize > PAGE_SIZE / 8) - return -EINVAL; - crt->setkey = setkey; crt->encrypt = alg->encrypt; crt->decrypt = alg->decrypt; @@ -385,8 +430,23 @@ static int crypto_init_blkcipher_ops(struct crypto_tfm *tfm, u32 type, u32 mask) return 0; } +static int crypto_init_blkcipher_ops(struct crypto_tfm *tfm, u32 type, u32 mask) +{ + struct blkcipher_alg *alg = &tfm->__crt_alg->cra_blkcipher; + + if (alg->ivsize > PAGE_SIZE / 8) + return -EINVAL; + + type ^= CRYPTO_ALG_ASYNC; + mask &= CRYPTO_ALG_ASYNC; + if (type & mask) + return crypto_init_blkcipher_ops_sync(tfm); + else + return crypto_init_blkcipher_ops_async(tfm); +} + static void crypto_blkcipher_show(struct seq_file *m, struct crypto_alg *alg) - __attribute_used__; + __attribute__ ((unused)); static void crypto_blkcipher_show(struct seq_file *m, struct crypto_alg *alg) { seq_printf(m, "type : blkcipher\n"); diff --git a/crypto/cbc.c b/crypto/cbc.c index 136fea7e700..1f2649e13b4 100644 --- a/crypto/cbc.c +++ b/crypto/cbc.c @@ -275,13 +275,18 @@ static void crypto_cbc_exit_tfm(struct crypto_tfm *tfm) crypto_free_cipher(ctx->child); } -static struct crypto_instance *crypto_cbc_alloc(void *param, unsigned int len) +static struct crypto_instance *crypto_cbc_alloc(struct rtattr **tb) { struct crypto_instance *inst; struct crypto_alg *alg; + int err; + + err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_BLKCIPHER); + if (err) + return ERR_PTR(err); - alg = crypto_get_attr_alg(param, len, CRYPTO_ALG_TYPE_CIPHER, - CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC); + alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER, + CRYPTO_ALG_TYPE_MASK); if (IS_ERR(alg)) return ERR_PTR(PTR_ERR(alg)); diff --git a/crypto/cryptd.c b/crypto/cryptd.c new file mode 100644 index 00000000000..3ff4e1f0f03 --- /dev/null +++ b/crypto/cryptd.c @@ -0,0 +1,375 @@ +/* + * Software async crypto daemon. + * + * Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + */ + +#include <crypto/algapi.h> +#include <linux/err.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/kthread.h> +#include <linux/list.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/scatterlist.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/spinlock.h> + +#define CRYPTD_MAX_QLEN 100 + +struct cryptd_state { + spinlock_t lock; + struct mutex mutex; + struct crypto_queue queue; + struct task_struct *task; +}; + +struct cryptd_instance_ctx { + struct crypto_spawn spawn; + struct cryptd_state *state; +}; + +struct cryptd_blkcipher_ctx { + struct crypto_blkcipher *child; +}; + +struct cryptd_blkcipher_request_ctx { + crypto_completion_t complete; +}; + + +static inline struct cryptd_state *cryptd_get_state(struct crypto_tfm *tfm) +{ + struct crypto_instance *inst = crypto_tfm_alg_instance(tfm); + struct cryptd_instance_ctx *ictx = crypto_instance_ctx(inst); + return ictx->state; +} + +static int cryptd_blkcipher_setkey(struct crypto_ablkcipher *parent, + const u8 *key, unsigned int keylen) +{ + struct cryptd_blkcipher_ctx *ctx = crypto_ablkcipher_ctx(parent); + struct crypto_blkcipher *child = ctx->child; + int err; + + crypto_blkcipher_clear_flags(child, CRYPTO_TFM_REQ_MASK); + crypto_blkcipher_set_flags(child, crypto_ablkcipher_get_flags(parent) & + CRYPTO_TFM_REQ_MASK); + err = crypto_blkcipher_setkey(child, key, keylen); + crypto_ablkcipher_set_flags(parent, crypto_blkcipher_get_flags(child) & + CRYPTO_TFM_RES_MASK); + return err; +} + +static void cryptd_blkcipher_crypt(struct ablkcipher_request *req, + struct crypto_blkcipher *child, + int err, + int (*crypt)(struct blkcipher_desc *desc, + struct scatterlist *dst, + struct scatterlist *src, + unsigned int len)) +{ + struct cryptd_blkcipher_request_ctx *rctx; + struct blkcipher_desc desc; + + rctx = ablkcipher_request_ctx(req); + + if (unlikely(err == -EINPROGRESS)) { + rctx->complete(&req->base, err); + return; + } + + desc.tfm = child; + desc.info = req->info; + desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP; + + err = crypt(&desc, req->dst, req->src, req->nbytes); + + req->base.complete = rctx->complete; + + local_bh_disable(); + req->base.complete(&req->base, err); + local_bh_enable(); +} + +static void cryptd_blkcipher_encrypt(struct crypto_async_request *req, int err) +{ + struct cryptd_blkcipher_ctx *ctx = crypto_tfm_ctx(req->tfm); + struct crypto_blkcipher *child = ctx->child; + + cryptd_blkcipher_crypt(ablkcipher_request_cast(req), child, err, + crypto_blkcipher_crt(child)->encrypt); +} + +static void cryptd_blkcipher_decrypt(struct crypto_async_request *req, int err) +{ + struct cryptd_blkcipher_ctx *ctx = crypto_tfm_ctx(req->tfm); + struct crypto_blkcipher *child = ctx->child; + + cryptd_blkcipher_crypt(ablkcipher_request_cast(req), child, err, + crypto_blkcipher_crt(child)->decrypt); +} + +static int cryptd_blkcipher_enqueue(struct ablkcipher_request *req, + crypto_completion_t complete) +{ + struct cryptd_blkcipher_request_ctx *rctx = ablkcipher_request_ctx(req); + struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req); + struct cryptd_state *state = + cryptd_get_state(crypto_ablkcipher_tfm(tfm)); + int err; + + rctx->complete = req->base.complete; + req->base.complete = complete; + + spin_lock_bh(&state->lock); + err = ablkcipher_enqueue_request(crypto_ablkcipher_alg(tfm), req); + spin_unlock_bh(&state->lock); + + wake_up_process(state->task); + return err; +} + +static int cryptd_blkcipher_encrypt_enqueue(struct ablkcipher_request *req) +{ + return cryptd_blkcipher_enqueue(req, cryptd_blkcipher_encrypt); +} + +static int cryptd_blkcipher_decrypt_enqueue(struct ablkcipher_request *req) +{ + return cryptd_blkcipher_enqueue(req, cryptd_blkcipher_decrypt); +} + +static int cryptd_blkcipher_init_tfm(struct crypto_tfm *tfm) +{ + struct crypto_instance *inst = crypto_tfm_alg_instance(tfm); + struct cryptd_instance_ctx *ictx = crypto_instance_ctx(inst); + struct crypto_spawn *spawn = &ictx->spawn; + struct cryptd_blkcipher_ctx *ctx = crypto_tfm_ctx(tfm); + struct crypto_blkcipher *cipher; + + cipher = crypto_spawn_blkcipher(spawn); + if (IS_ERR(cipher)) + return PTR_ERR(cipher); + + ctx->child = cipher; + tfm->crt_ablkcipher.reqsize = + sizeof(struct cryptd_blkcipher_request_ctx); + return 0; +} + +static void cryptd_blkcipher_exit_tfm(struct crypto_tfm *tfm) +{ + struct cryptd_blkcipher_ctx *ctx = crypto_tfm_ctx(tfm); + struct cryptd_state *state = cryptd_get_state(tfm); + int active; + + mutex_lock(&state->mutex); + active = ablkcipher_tfm_in_queue(__crypto_ablkcipher_cast(tfm)); + mutex_unlock(&state->mutex); + + BUG_ON(active); + + crypto_free_blkcipher(ctx->child); +} + +static struct crypto_instance *cryptd_alloc_instance(struct crypto_alg *alg, + struct cryptd_state *state) +{ + struct crypto_instance *inst; + struct cryptd_instance_ctx *ctx; + int err; + + inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL); + if (IS_ERR(inst)) + goto out; + + err = -ENAMETOOLONG; + if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME, + "cryptd(%s)", alg->cra_driver_name) >= CRYPTO_MAX_ALG_NAME) + goto out_free_inst; + + ctx = crypto_instance_ctx(inst); + err = crypto_init_spawn(&ctx->spawn, alg, inst, + CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC); + if (err) + goto out_free_inst; + + ctx->state = state; + + memcpy(inst->alg.cra_name, alg->cra_name, CRYPTO_MAX_ALG_NAME); + + inst->alg.cra_priority = alg->cra_priority + 50; + inst->alg.cra_blocksize = alg->cra_blocksize; + inst->alg.cra_alignmask = alg->cra_alignmask; + +out: + return inst; + +out_free_inst: + kfree(inst); + inst = ERR_PTR(err); + goto out; +} + +static struct crypto_instance *cryptd_alloc_blkcipher( + struct rtattr **tb, struct cryptd_state *state) +{ + struct crypto_instance *inst; + struct crypto_alg *alg; + + alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_BLKCIPHER, + CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC); + if (IS_ERR(alg)) + return ERR_PTR(PTR_ERR(alg)); + + inst = cryptd_alloc_instance(alg, state); + if (IS_ERR(inst)) + goto out_put_alg; + + inst->alg.cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER | CRYPTO_ALG_ASYNC; + inst->alg.cra_type = &crypto_ablkcipher_type; + + inst->alg.cra_ablkcipher.ivsize = alg->cra_blkcipher.ivsize; + inst->alg.cra_ablkcipher.min_keysize = alg->cra_blkcipher.min_keysize; + inst->alg.cra_ablkcipher.max_keysize = alg->cra_blkcipher.max_keysize; + + inst->alg.cra_ctxsize = sizeof(struct cryptd_blkcipher_ctx); + + inst->alg.cra_init = cryptd_blkcipher_init_tfm; + inst->alg.cra_exit = cryptd_blkcipher_exit_tfm; + + inst->alg.cra_ablkcipher.setkey = cryptd_blkcipher_setkey; + inst->alg.cra_ablkcipher.encrypt = cryptd_blkcipher_encrypt_enqueue; + inst->alg.cra_ablkcipher.decrypt = cryptd_blkcipher_decrypt_enqueue; + + inst->alg.cra_ablkcipher.queue = &state->queue; + +out_put_alg: + crypto_mod_put(alg); + return inst; +} + +static struct cryptd_state state; + +static struct crypto_instance *cryptd_alloc(struct rtattr **tb) +{ + struct crypto_attr_type *algt; + + algt = crypto_get_attr_type(tb); + if (IS_ERR(algt)) + return ERR_PTR(PTR_ERR(algt)); + + switch (algt->type & algt->mask & CRYPTO_ALG_TYPE_MASK) { + case CRYPTO_ALG_TYPE_BLKCIPHER: + return cryptd_alloc_blkcipher(tb, &state); + } + + return ERR_PTR(-EINVAL); +} + +static void cryptd_free(struct crypto_instance *inst) +{ + struct cryptd_instance_ctx *ctx = crypto_instance_ctx(inst); + + crypto_drop_spawn(&ctx->spawn); + kfree(inst); +} + +static struct crypto_template cryptd_tmpl = { + .name = "cryptd", + .alloc = cryptd_alloc, + .free = cryptd_free, + .module = THIS_MODULE, +}; + +static inline int cryptd_create_thread(struct cryptd_state *state, + int (*fn)(void *data), const char *name) +{ + spin_lock_init(&state->lock); + mutex_init(&state->mutex); + crypto_init_queue(&state->queue, CRYPTD_MAX_QLEN); + + state->task = kthread_create(fn, state, name); + if (IS_ERR(state->task)) + return PTR_ERR(state->task); + + return 0; +} + +static inline void cryptd_stop_thread(struct cryptd_state *state) +{ + BUG_ON(state->queue.qlen); + kthread_stop(state->task); +} + +static int cryptd_thread(void *data) +{ + struct cryptd_state *state = data; + int stop; + + do { + struct crypto_async_request *req, *backlog; + + mutex_lock(&state->mutex); + __set_current_state(TASK_INTERRUPTIBLE); + + spin_lock_bh(&state->lock); + backlog = crypto_get_backlog(&state->queue); + req = crypto_dequeue_request(&state->queue); + spin_unlock_bh(&state->lock); + + stop = kthread_should_stop(); + + if (stop || req) { + __set_current_state(TASK_RUNNING); + if (req) { + if (backlog) + backlog->complete(backlog, + -EINPROGRESS); + req->complete(req, 0); + } + } + + mutex_unlock(&state->mutex); + + schedule(); + } while (!stop); + + return 0; +} + +static int __init cryptd_init(void) +{ + int err; + + err = cryptd_create_thread(&state, cryptd_thread, "cryptd"); + if (err) + return err; + + err = crypto_register_template(&cryptd_tmpl); + if (err) + kthread_stop(state.task); + + return err; +} + +static void __exit cryptd_exit(void) +{ + cryptd_stop_thread(&state); + crypto_unregister_template(&cryptd_tmpl); +} + +module_init(cryptd_init); +module_exit(cryptd_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Software async crypto daemon"); diff --git a/crypto/cryptomgr.c b/crypto/cryptomgr.c index 2ebffb84f1d..6958ea83ee4 100644 --- a/crypto/cryptomgr.c +++ b/crypto/cryptomgr.c @@ -14,17 +14,24 @@ #include <linux/ctype.h> #include <linux/err.h> #include <linux/init.h> +#include <linux/kthread.h> #include <linux/module.h> #include <linux/notifier.h> #include <linux/rtnetlink.h> #include <linux/sched.h> #include <linux/string.h> -#include <linux/workqueue.h> #include "internal.h" struct cryptomgr_param { - struct work_struct work; + struct task_struct *thread; + + struct rtattr *tb[CRYPTOA_MAX]; + + struct { + struct rtattr attr; + struct crypto_attr_type data; + } type; struct { struct rtattr attr; @@ -32,18 +39,15 @@ struct cryptomgr_param { } alg; struct { - u32 type; - u32 mask; char name[CRYPTO_MAX_ALG_NAME]; } larval; char template[CRYPTO_MAX_ALG_NAME]; }; -static void cryptomgr_probe(struct work_struct *work) +static int cryptomgr_probe(void *data) { - struct cryptomgr_param *param = - container_of(work, struct cryptomgr_param, work); + struct cryptomgr_param *param = data; struct crypto_template *tmpl; struct crypto_instance *inst; int err; @@ -53,7 +57,7 @@ static void cryptomgr_probe(struct work_struct *work) goto err; do { - inst = tmpl->alloc(¶m->alg, sizeof(param->alg)); + inst = tmpl->alloc(param->tb); if (IS_ERR(inst)) err = PTR_ERR(inst); else if ((err = crypto_register_instance(tmpl, inst))) @@ -67,11 +71,11 @@ static void cryptomgr_probe(struct work_struct *work) out: kfree(param); - return; + module_put_and_exit(0); err: - crypto_larval_error(param->larval.name, param->larval.type, - param->larval.mask); + crypto_larval_error(param->larval.name, param->type.data.type, + param->type.data.mask); goto out; } @@ -82,10 +86,13 @@ static int cryptomgr_schedule_probe(struct crypto_larval *larval) const char *p; unsigned int len; - param = kmalloc(sizeof(*param), GFP_KERNEL); - if (!param) + if (!try_module_get(THIS_MODULE)) goto err; + param = kzalloc(sizeof(*param), GFP_KERNEL); + if (!param) + goto err_put_module; + for (p = name; isalnum(*p) || *p == '-' || *p == '_'; p++) ; @@ -94,32 +101,45 @@ static int cryptomgr_schedule_probe(struct crypto_larval *larval) goto err_free_param; memcpy(param->template, name, len); - param->template[len] = 0; name = p + 1; - for (p = name; isalnum(*p) || *p == '-' || *p == '_'; p++) - ; + len = 0; + for (p = name; *p; p++) { + for (; isalnum(*p) || *p == '-' || *p == '_' || *p == '('; p++) + ; - len = p - name; - if (!len || *p != ')' || p[1]) + if (*p != ')') + goto err_free_param; + + len = p - name; + } + + if (!len || name[len + 1]) goto err_free_param; + param->type.attr.rta_len = sizeof(param->type); + param->type.attr.rta_type = CRYPTOA_TYPE; + param->type.data.type = larval->alg.cra_flags; + param->type.data.mask = larval->mask; + param->tb[CRYPTOA_TYPE - 1] = ¶m->type.attr; + param->alg.attr.rta_len = sizeof(param->alg); param->alg.attr.rta_type = CRYPTOA_ALG; memcpy(param->alg.data.name, name, len); - param->alg.data.name[len] = 0; + param->tb[CRYPTOA_ALG - 1] = ¶m->alg.attr; memcpy(param->larval.name, larval->alg.cra_name, CRYPTO_MAX_ALG_NAME); - param->larval.type = larval->alg.cra_flags; - param->larval.mask = larval->mask; - INIT_WORK(¶m->work, cryptomgr_probe); - schedule_work(¶m->work); + param->thread = kthread_run(cryptomgr_probe, param, "cryptomgr"); + if (IS_ERR(param->thread)) + goto err_free_param; return NOTIFY_STOP; err_free_param: kfree(param); +err_put_module: + module_put(THIS_MODULE); err: return NOTIFY_OK; } diff --git a/crypto/ecb.c b/crypto/ecb.c index 839a0aed8c2..6310387a872 100644 --- a/crypto/ecb.c +++ b/crypto/ecb.c @@ -115,13 +115,18 @@ static void crypto_ecb_exit_tfm(struct crypto_tfm *tfm) crypto_free_cipher(ctx->child); } -static struct crypto_instance *crypto_ecb_alloc(void *param, unsigned int len) +static struct crypto_instance *crypto_ecb_alloc(struct rtattr **tb) { struct crypto_instance *inst; struct crypto_alg *alg; + int err; + + err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_BLKCIPHER); + if (err) + return ERR_PTR(err); - alg = crypto_get_attr_alg(param, len, CRYPTO_ALG_TYPE_CIPHER, - CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC); + alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER, + CRYPTO_ALG_TYPE_MASK); if (IS_ERR(alg)) return ERR_PTR(PTR_ERR(alg)); diff --git a/crypto/hash.c b/crypto/hash.c index 12c4514f347..4ccd22deef3 100644 --- a/crypto/hash.c +++ b/crypto/hash.c @@ -41,7 +41,7 @@ static int crypto_init_hash_ops(struct crypto_tfm *tfm, u32 type, u32 mask) } static void crypto_hash_show(struct seq_file *m, struct crypto_alg *alg) - __attribute_used__; + __attribute__ ((unused)); static void crypto_hash_show(struct seq_file *m, struct crypto_alg *alg) { seq_printf(m, "type : hash\n"); diff --git a/crypto/hmac.c b/crypto/hmac.c index 44187c5ee59..8802fb6dd5a 100644 --- a/crypto/hmac.c +++ b/crypto/hmac.c @@ -197,13 +197,18 @@ static void hmac_free(struct crypto_instance *inst) kfree(inst); } -static struct crypto_instance *hmac_alloc(void *param, unsigned int len) +static struct crypto_instance *hmac_alloc(struct rtattr **tb) { struct crypto_instance *inst; struct crypto_alg *alg; + int err; + + err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_HASH); + if (err) + return ERR_PTR(err); - alg = crypto_get_attr_alg(param, len, CRYPTO_ALG_TYPE_HASH, - CRYPTO_ALG_TYPE_HASH_MASK | CRYPTO_ALG_ASYNC); + alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_HASH, + CRYPTO_ALG_TYPE_HASH_MASK); if (IS_ERR(alg)) return ERR_PTR(PTR_ERR(alg)); diff --git a/crypto/lrw.c b/crypto/lrw.c index b4105080ac7..621095db28b 100644 --- a/crypto/lrw.c +++ b/crypto/lrw.c @@ -228,13 +228,18 @@ static void exit_tfm(struct crypto_tfm *tfm) crypto_free_cipher(ctx->child); } -static struct crypto_instance *alloc(void *param, unsigned int len) +static struct crypto_instance *alloc(struct rtattr **tb) { struct crypto_instance *inst; struct crypto_alg *alg; + int err; + + err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_BLKCIPHER); + if (err) + return ERR_PTR(err); - alg = crypto_get_attr_alg(param, len, CRYPTO_ALG_TYPE_CIPHER, - CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC); + alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER, + CRYPTO_ALG_TYPE_MASK); if (IS_ERR(alg)) return ERR_PTR(PTR_ERR(alg)); diff --git a/crypto/pcbc.c b/crypto/pcbc.c index 5174d7fdad6..c3ed8a1c9f4 100644 --- a/crypto/pcbc.c +++ b/crypto/pcbc.c @@ -279,13 +279,18 @@ static void crypto_pcbc_exit_tfm(struct crypto_tfm *tfm) crypto_free_cipher(ctx->child); } -static struct crypto_instance *crypto_pcbc_alloc(void *param, unsigned int len) +static struct crypto_instance *crypto_pcbc_alloc(struct rtattr **tb) { struct crypto_instance *inst; struct crypto_alg *alg; + int err; + + err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_BLKCIPHER); + if (err) + return ERR_PTR(err); - alg = crypto_get_attr_alg(param, len, CRYPTO_ALG_TYPE_CIPHER, - CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC); + alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER, + CRYPTO_ALG_TYPE_MASK); if (IS_ERR(alg)) return ERR_PTR(PTR_ERR(alg)); diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c index 8eaa5aa210b..f0aed0106ad 100644 --- a/crypto/tcrypt.c +++ b/crypto/tcrypt.c @@ -57,6 +57,11 @@ #define ENCRYPT 1 #define DECRYPT 0 +struct tcrypt_result { + struct completion completion; + int err; +}; + static unsigned int IDX[8] = { IDX1, IDX2, IDX3, IDX4, IDX5, IDX6, IDX7, IDX8 }; /* @@ -84,6 +89,17 @@ static void hexdump(unsigned char *buf, unsigned int len) printk("\n"); } +static void tcrypt_complete(struct crypto_async_request *req, int err) +{ + struct tcrypt_result *res = req->data; + + if (err == -EINPROGRESS) + return; + + res->err = err; + complete(&res->completion); +} + static void test_hash(char *algo, struct hash_testvec *template, unsigned int tcount) { @@ -203,15 +219,14 @@ static void test_cipher(char *algo, int enc, { unsigned int ret, i, j, k, temp; unsigned int tsize; - unsigned int iv_len; - unsigned int len; char *q; - struct crypto_blkcipher *tfm; + struct crypto_ablkcipher *tfm; char *key; struct cipher_testvec *cipher_tv; - struct blkcipher_desc desc; + struct ablkcipher_request *req; struct scatterlist sg[8]; const char *e; + struct tcrypt_result result; if (enc == ENCRYPT) e = "encryption"; @@ -232,15 +247,24 @@ static void test_cipher(char *algo, int enc, memcpy(tvmem, template, tsize); cipher_tv = (void *)tvmem; - tfm = crypto_alloc_blkcipher(algo, 0, CRYPTO_ALG_ASYNC); + init_completion(&result.completion); + + tfm = crypto_alloc_ablkcipher(algo, 0, 0); if (IS_ERR(tfm)) { printk("failed to load transform for %s: %ld\n", algo, PTR_ERR(tfm)); return; } - desc.tfm = tfm; - desc.flags = 0; + + req = ablkcipher_request_alloc(tfm, GFP_KERNEL); + if (!req) { + printk("failed to allocate request for %s\n", algo); + goto out; + } + + ablkcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, + tcrypt_complete, &result); j = 0; for (i = 0; i < tcount; i++) { @@ -249,17 +273,17 @@ static void test_cipher(char *algo, int enc, printk("test %u (%d bit key):\n", j, cipher_tv[i].klen * 8); - crypto_blkcipher_clear_flags(tfm, ~0); + crypto_ablkcipher_clear_flags(tfm, ~0); if (cipher_tv[i].wk) - crypto_blkcipher_set_flags( + crypto_ablkcipher_set_flags( tfm, CRYPTO_TFM_REQ_WEAK_KEY); key = cipher_tv[i].key; - ret = crypto_blkcipher_setkey(tfm, key, - cipher_tv[i].klen); + ret = crypto_ablkcipher_setkey(tfm, key, + cipher_tv[i].klen); if (ret) { printk("setkey() failed flags=%x\n", - crypto_blkcipher_get_flags(tfm)); + crypto_ablkcipher_get_flags(tfm)); if (!cipher_tv[i].fail) goto out; @@ -268,19 +292,28 @@ static void test_cipher(char *algo, int enc, sg_set_buf(&sg[0], cipher_tv[i].input, cipher_tv[i].ilen); - iv_len = crypto_blkcipher_ivsize(tfm); - if (iv_len) - crypto_blkcipher_set_iv(tfm, cipher_tv[i].iv, - iv_len); + ablkcipher_request_set_crypt(req, sg, sg, + cipher_tv[i].ilen, + cipher_tv[i].iv); - len = cipher_tv[i].ilen; ret = enc ? - crypto_blkcipher_encrypt(&desc, sg, sg, len) : - crypto_blkcipher_decrypt(&desc, sg, sg, len); + crypto_ablkcipher_encrypt(req) : + crypto_ablkcipher_decrypt(req); - if (ret) { - printk("%s () failed flags=%x\n", e, - desc.flags); + switch (ret) { + case 0: + break; + case -EINPROGRESS: + case -EBUSY: + ret = wait_for_completion_interruptible( + &result.completion); + if (!ret && !((ret = result.err))) { + INIT_COMPLETION(result.completion); + break; + } + /* fall through */ + default: + printk("%s () failed err=%d\n", e, -ret); goto out; } @@ -303,17 +336,17 @@ static void test_cipher(char *algo, int enc, printk("test %u (%d bit key):\n", j, cipher_tv[i].klen * 8); - crypto_blkcipher_clear_flags(tfm, ~0); + crypto_ablkcipher_clear_flags(tfm, ~0); if (cipher_tv[i].wk) - crypto_blkcipher_set_flags( + crypto_ablkcipher_set_flags( tfm, CRYPTO_TFM_REQ_WEAK_KEY); key = cipher_tv[i].key; - ret = crypto_blkcipher_setkey(tfm, key, - cipher_tv[i].klen); + ret = crypto_ablkcipher_setkey(tfm, key, + cipher_tv[i].klen); if (ret) { printk("setkey() failed flags=%x\n", - crypto_blkcipher_get_flags(tfm)); + crypto_ablkcipher_get_flags(tfm)); if (!cipher_tv[i].fail) goto out; @@ -329,19 +362,28 @@ static void test_cipher(char *algo, int enc, cipher_tv[i].tap[k]); } - iv_len = crypto_blkcipher_ivsize(tfm); - if (iv_len) - crypto_blkcipher_set_iv(tfm, cipher_tv[i].iv, - iv_len); + ablkcipher_request_set_crypt(req, sg, sg, + cipher_tv[i].ilen, + cipher_tv[i].iv); - len = cipher_tv[i].ilen; ret = enc ? - crypto_blkcipher_encrypt(&desc, sg, sg, len) : - crypto_blkcipher_decrypt(&desc, sg, sg, len); + crypto_ablkcipher_encrypt(req) : + crypto_ablkcipher_decrypt(req); - if (ret) { - printk("%s () failed flags=%x\n", e, - desc.flags); + switch (ret) { + case 0: + break; + case -EINPROGRESS: + case -EBUSY: + ret = wait_for_completion_interruptible( + &result.completion); + if (!ret && !((ret = result.err))) { + INIT_COMPLETION(result.completion); + break; + } + /* fall through */ + default: + printk("%s () failed err=%d\n", e, -ret); goto out; } @@ -360,7 +402,8 @@ static void test_cipher(char *algo, int enc, } out: - crypto_free_blkcipher(tfm); + crypto_free_ablkcipher(tfm); + ablkcipher_request_free(req); } static int test_cipher_jiffies(struct blkcipher_desc *desc, int enc, char *p, @@ -832,7 +875,7 @@ static void test_available(void) while (*name) { printk("alg %s ", *name); - printk(crypto_has_alg(*name, 0, CRYPTO_ALG_ASYNC) ? + printk(crypto_has_alg(*name, 0, 0) ? "found\n" : "not found\n"); name++; } diff --git a/crypto/xcbc.c b/crypto/xcbc.c index 53e8ccbf0f5..9f502b86e0e 100644 --- a/crypto/xcbc.c +++ b/crypto/xcbc.c @@ -288,12 +288,18 @@ static void xcbc_exit_tfm(struct crypto_tfm *tfm) crypto_free_cipher(ctx->child); } -static struct crypto_instance *xcbc_alloc(void *param, unsigned int len) +static struct crypto_instance *xcbc_alloc(struct rtattr **tb) { struct crypto_instance *inst; struct crypto_alg *alg; - alg = crypto_get_attr_alg(param, len, CRYPTO_ALG_TYPE_CIPHER, - CRYPTO_ALG_TYPE_HASH_MASK | CRYPTO_ALG_ASYNC); + int err; + + err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_HASH); + if (err) + return ERR_PTR(err); + + alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER, + CRYPTO_ALG_TYPE_MASK); if (IS_ERR(alg)) return ERR_PTR(PTR_ERR(alg)); diff --git a/drivers/Makefile b/drivers/Makefile index 920c975bb6d..26ca9031ea4 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -58,7 +58,7 @@ obj-$(CONFIG_GAMEPORT) += input/gameport/ obj-$(CONFIG_INPUT) += input/ obj-$(CONFIG_I2O) += message/ obj-$(CONFIG_RTC_LIB) += rtc/ -obj-$(CONFIG_I2C) += i2c/ +obj-y += i2c/ obj-$(CONFIG_W1) += w1/ obj-$(CONFIG_HWMON) += hwmon/ obj-$(CONFIG_PHONE) += telephony/ diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c index 2f2e7964226..c4efc0c17f8 100644 --- a/drivers/acpi/processor_perflib.c +++ b/drivers/acpi/processor_perflib.c @@ -433,49 +433,6 @@ static int acpi_processor_perf_open_fs(struct inode *inode, struct file *file) PDE(inode)->data); } -static ssize_t -acpi_processor_write_performance(struct file *file, - const char __user * buffer, - size_t count, loff_t * data) -{ - int result = 0; - struct seq_file *m = file->private_data; - struct acpi_processor *pr = m->private; - struct acpi_processor_performance *perf; - char state_string[12] = { '\0' }; - unsigned int new_state = 0; - struct cpufreq_policy policy; - - - if (!pr || (count > sizeof(state_string) - 1)) - return -EINVAL; - - perf = pr->performance; - if (!perf) - return -EINVAL; - - if (copy_from_user(state_string, buffer, count)) - return -EFAULT; - - state_string[count] = '\0'; - new_state = simple_strtoul(state_string, NULL, 0); - - if (new_state >= perf->state_count) - return -EINVAL; - - cpufreq_get_policy(&policy, pr->id); - - policy.cpu = pr->id; - policy.min = perf->states[new_state].core_frequency * 1000; - policy.max = perf->states[new_state].core_frequency * 1000; - - result = cpufreq_set_policy(&policy); - if (result) - return result; - - return count; -} - static void acpi_cpufreq_add_file(struct acpi_processor *pr) { struct proc_dir_entry *entry = NULL; @@ -487,10 +444,9 @@ static void acpi_cpufreq_add_file(struct acpi_processor *pr) /* add file 'performance' [R/W] */ entry = create_proc_entry(ACPI_PROCESSOR_FILE_PERFORMANCE, - S_IFREG | S_IRUGO | S_IWUSR, + S_IFREG | S_IRUGO, acpi_device_dir(device)); if (entry){ - acpi_processor_perf_fops.write = acpi_processor_write_performance; entry->proc_fops = &acpi_processor_perf_fops; entry->data = acpi_driver_data(device); entry->owner = THIS_MODULE; diff --git a/drivers/char/agp/ali-agp.c b/drivers/char/agp/ali-agp.c index 5b684fddcc0..4941ddb7893 100644 --- a/drivers/char/agp/ali-agp.c +++ b/drivers/char/agp/ali-agp.c @@ -145,6 +145,7 @@ static void *m1541_alloc_page(struct agp_bridge_data *bridge) void *addr = agp_generic_alloc_page(agp_bridge); u32 temp; + global_flush_tlb(); if (!addr) return NULL; @@ -160,6 +161,7 @@ static void ali_destroy_page(void * addr) if (addr) { global_cache_flush(); /* is this really needed? --hch */ agp_generic_destroy_page(addr); + global_flush_tlb(); } } diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c index f902d71947b..45aeb917ec6 100644 --- a/drivers/char/agp/generic.c +++ b/drivers/char/agp/generic.c @@ -51,28 +51,6 @@ int agp_memory_reserved; */ EXPORT_SYMBOL_GPL(agp_memory_reserved); -#if defined(CONFIG_X86) -int map_page_into_agp(struct page *page) -{ - int i; - i = change_page_attr(page, 1, PAGE_KERNEL_NOCACHE); - /* Caller's responsibility to call global_flush_tlb() for - * performance reasons */ - return i; -} -EXPORT_SYMBOL_GPL(map_page_into_agp); - -int unmap_page_from_agp(struct page *page) -{ - int i; - i = change_page_attr(page, 1, PAGE_KERNEL); - /* Caller's responsibility to call global_flush_tlb() for - * performance reasons */ - return i; -} -EXPORT_SYMBOL_GPL(unmap_page_from_agp); -#endif - /* * Generic routines for handling agp_memory structures - * They use the basic page allocation routines to do the brunt of the work. diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index 55392a45a14..9c69f2e761f 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -186,8 +186,9 @@ static void *i8xx_alloc_pages(void) return NULL; if (change_page_attr(page, 4, PAGE_KERNEL_NOCACHE) < 0) { + change_page_attr(page, 4, PAGE_KERNEL); global_flush_tlb(); - __free_page(page); + __free_pages(page, 2); return NULL; } global_flush_tlb(); @@ -209,7 +210,7 @@ static void i8xx_destroy_pages(void *addr) global_flush_tlb(); put_page(page); unlock_page(page); - free_pages((unsigned long)addr, 2); + __free_pages(page, 2); atomic_dec(&agp_bridge->current_memory_agp); } @@ -315,9 +316,6 @@ static struct agp_memory *alloc_agpphysmem_i8xx(size_t pg_count, int type) struct agp_memory *new; void *addr; - if (pg_count != 1 && pg_count != 4) - return NULL; - switch (pg_count) { case 1: addr = agp_bridge->driver->agp_alloc_page(agp_bridge); global_flush_tlb(); diff --git a/drivers/char/agp/nvidia-agp.c b/drivers/char/agp/nvidia-agp.c index 0c9dab557c9..6cd7373dcdf 100644 --- a/drivers/char/agp/nvidia-agp.c +++ b/drivers/char/agp/nvidia-agp.c @@ -320,11 +320,11 @@ static int __devinit agp_nvidia_probe(struct pci_dev *pdev, u8 cap_ptr; nvidia_private.dev_1 = - pci_find_slot((unsigned int)pdev->bus->number, PCI_DEVFN(0, 1)); + pci_get_bus_and_slot((unsigned int)pdev->bus->number, PCI_DEVFN(0, 1)); nvidia_private.dev_2 = - pci_find_slot((unsigned int)pdev->bus->number, PCI_DEVFN(0, 2)); + pci_get_bus_and_slot((unsigned int)pdev->bus->number, PCI_DEVFN(0, 2)); nvidia_private.dev_3 = - pci_find_slot((unsigned int)pdev->bus->number, PCI_DEVFN(30, 0)); + pci_get_bus_and_slot((unsigned int)pdev->bus->number, PCI_DEVFN(30, 0)); if (!nvidia_private.dev_1 || !nvidia_private.dev_2 || !nvidia_private.dev_3) { printk(KERN_INFO PFX "Detected an NVIDIA nForce/nForce2 " @@ -443,6 +443,9 @@ static int __init agp_nvidia_init(void) static void __exit agp_nvidia_cleanup(void) { pci_unregister_driver(&agp_nvidia_pci_driver); + pci_dev_put(nvidia_private.dev_1); + pci_dev_put(nvidia_private.dev_2); + pci_dev_put(nvidia_private.dev_3); } module_init(agp_nvidia_init); diff --git a/drivers/char/agp/sgi-agp.c b/drivers/char/agp/sgi-agp.c index ee8f50edde1..cda608c42be 100644 --- a/drivers/char/agp/sgi-agp.c +++ b/drivers/char/agp/sgi-agp.c @@ -47,9 +47,8 @@ static void *sgi_tioca_alloc_page(struct agp_bridge_data *bridge) nid = info->ca_closest_node; page = alloc_pages_node(nid, GFP_KERNEL, 0); - if (page == NULL) { - return 0; - } + if (!page) + return NULL; get_page(page); SetPageLocked(page); diff --git a/drivers/char/agp/sis-agp.c b/drivers/char/agp/sis-agp.c index 125f4282d95..eb1a1c73819 100644 --- a/drivers/char/agp/sis-agp.c +++ b/drivers/char/agp/sis-agp.c @@ -143,96 +143,6 @@ static struct agp_bridge_driver sis_driver = { .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; -static struct agp_device_ids sis_agp_device_ids[] __devinitdata = -{ - { - .device_id = PCI_DEVICE_ID_SI_5591_AGP, - .chipset_name = "5591", - }, - { - .device_id = PCI_DEVICE_ID_SI_530, - .chipset_name = "530", - }, - { - .device_id = PCI_DEVICE_ID_SI_540, - .chipset_name = "540", - }, - { - .device_id = PCI_DEVICE_ID_SI_550, - .chipset_name = "550", - }, - { - .device_id = PCI_DEVICE_ID_SI_620, - .chipset_name = "620", - }, - { - .device_id = PCI_DEVICE_ID_SI_630, - .chipset_name = "630", - }, - { - .device_id = PCI_DEVICE_ID_SI_635, - .chipset_name = "635", - }, - { - .device_id = PCI_DEVICE_ID_SI_645, - .chipset_name = "645", - }, - { - .device_id = PCI_DEVICE_ID_SI_646, - .chipset_name = "646", - }, - { - .device_id = PCI_DEVICE_ID_SI_648, - .chipset_name = "648", - }, - { - .device_id = PCI_DEVICE_ID_SI_650, - .chipset_name = "650", - }, - { - .device_id = PCI_DEVICE_ID_SI_651, - .chipset_name = "651", - }, - { - .device_id = PCI_DEVICE_ID_SI_655, - .chipset_name = "655", - }, - { - .device_id = PCI_DEVICE_ID_SI_661, - .chipset_name = "661", - }, - { - .device_id = PCI_DEVICE_ID_SI_730, - .chipset_name = "730", - }, - { - .device_id = PCI_DEVICE_ID_SI_735, - .chipset_name = "735", - }, - { - .device_id = PCI_DEVICE_ID_SI_740, - .chipset_name = "740", - }, - { - .device_id = PCI_DEVICE_ID_SI_741, - .chipset_name = "741", - }, - { - .device_id = PCI_DEVICE_ID_SI_745, - .chipset_name = "745", - }, - { - .device_id = PCI_DEVICE_ID_SI_746, - .chipset_name = "746", - }, - { - .device_id = PCI_DEVICE_ID_SI_760, - .chipset_name = "760", - }, - { }, /* dummy final entry, always present */ -}; - - // chipsets that require the 'delay hack' static int sis_broken_chipsets[] __devinitdata = { PCI_DEVICE_ID_SI_648, @@ -269,29 +179,15 @@ static void __devinit sis_get_driver(struct agp_bridge_data *bridge) static int __devinit agp_sis_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { - struct agp_device_ids *devs = sis_agp_device_ids; struct agp_bridge_data *bridge; u8 cap_ptr; - int j; cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP); if (!cap_ptr) return -ENODEV; - /* probe for known chipsets */ - for (j = 0; devs[j].chipset_name; j++) { - if (pdev->device == devs[j].device_id) { - printk(KERN_INFO PFX "Detected SiS %s chipset\n", - devs[j].chipset_name); - goto found; - } - } - - printk(KERN_ERR PFX "Unsupported SiS chipset (device id: %04x)\n", - pdev->device); - return -ENODEV; -found: + printk(KERN_INFO PFX "Detected SiS chipset - id:%i\n", pdev->device); bridge = agp_alloc_bridge(); if (!bridge) return -ENOMEM; @@ -320,12 +216,172 @@ static void __devexit agp_sis_remove(struct pci_dev *pdev) static struct pci_device_id agp_sis_pci_table[] = { { - .class = (PCI_CLASS_BRIDGE_HOST << 8), - .class_mask = ~0, - .vendor = PCI_VENDOR_ID_SI, - .device = PCI_ANY_ID, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, + .class = (PCI_CLASS_BRIDGE_HOST << 8), + .class_mask = ~0, + .vendor = PCI_VENDOR_ID_SI, + .device = PCI_DEVICE_ID_SI_5591_AGP, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { + .class = (PCI_CLASS_BRIDGE_HOST << 8), + .class_mask = ~0, + .vendor = PCI_VENDOR_ID_SI, + .device = PCI_DEVICE_ID_SI_530, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { + .class = (PCI_CLASS_BRIDGE_HOST << 8), + .class_mask = ~0, + .vendor = PCI_VENDOR_ID_SI, + .device = PCI_DEVICE_ID_SI_540, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { + .class = (PCI_CLASS_BRIDGE_HOST << 8), + .class_mask = ~0, + .vendor = PCI_VENDOR_ID_SI, + .device = PCI_DEVICE_ID_SI_550, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { + .class = (PCI_CLASS_BRIDGE_HOST << 8), + .class_mask = ~0, + .vendor = PCI_VENDOR_ID_SI, + .device = PCI_DEVICE_ID_SI_620, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { + .class = (PCI_CLASS_BRIDGE_HOST << 8), + .class_mask = ~0, + .vendor = PCI_VENDOR_ID_SI, + .device = PCI_DEVICE_ID_SI_630, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { + .class = (PCI_CLASS_BRIDGE_HOST << 8), + .class_mask = ~0, + .vendor = PCI_VENDOR_ID_SI, + .device = PCI_DEVICE_ID_SI_635, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { + .class = (PCI_CLASS_BRIDGE_HOST << 8), + .class_mask = ~0, + .vendor = PCI_VENDOR_ID_SI, + .device = PCI_DEVICE_ID_SI_645, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { + .class = (PCI_CLASS_BRIDGE_HOST << 8), + .class_mask = ~0, + .vendor = PCI_VENDOR_ID_SI, + .device = PCI_DEVICE_ID_SI_646, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { + .class = (PCI_CLASS_BRIDGE_HOST << 8), + .class_mask = ~0, + .vendor = PCI_VENDOR_ID_SI, + .device = PCI_DEVICE_ID_SI_648, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { + .class = (PCI_CLASS_BRIDGE_HOST << 8), + .class_mask = ~0, + .vendor = PCI_VENDOR_ID_SI, + .device = PCI_DEVICE_ID_SI_650, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { + .class = (PCI_CLASS_BRIDGE_HOST << 8), + .class_mask = ~0, + .vendor = PCI_VENDOR_ID_SI, + .device = PCI_DEVICE_ID_SI_651, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { + .class = (PCI_CLASS_BRIDGE_HOST << 8), + .class_mask = ~0, + .vendor = PCI_VENDOR_ID_SI, + .device = PCI_DEVICE_ID_SI_655, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { + .class = (PCI_CLASS_BRIDGE_HOST << 8), + .class_mask = ~0, + .vendor = PCI_VENDOR_ID_SI, + .device = PCI_DEVICE_ID_SI_661, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { + .class = (PCI_CLASS_BRIDGE_HOST << 8), + .class_mask = ~0, + .vendor = PCI_VENDOR_ID_SI, + .device = PCI_DEVICE_ID_SI_730, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { + .class = (PCI_CLASS_BRIDGE_HOST << 8), + .class_mask = ~0, + .vendor = PCI_VENDOR_ID_SI, + .device = PCI_DEVICE_ID_SI_735, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { + .class = (PCI_CLASS_BRIDGE_HOST << 8), + .class_mask = ~0, + .vendor = PCI_VENDOR_ID_SI, + .device = PCI_DEVICE_ID_SI_740, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { + .class = (PCI_CLASS_BRIDGE_HOST << 8), + .class_mask = ~0, + .vendor = PCI_VENDOR_ID_SI, + .device = PCI_DEVICE_ID_SI_741, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { + .class = (PCI_CLASS_BRIDGE_HOST << 8), + .class_mask = ~0, + .vendor = PCI_VENDOR_ID_SI, + .device = PCI_DEVICE_ID_SI_745, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { + .class = (PCI_CLASS_BRIDGE_HOST << 8), + .class_mask = ~0, + .vendor = PCI_VENDOR_ID_SI, + .device = PCI_DEVICE_ID_SI_746, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + { + .class = (PCI_CLASS_BRIDGE_HOST << 8), + .class_mask = ~0, + .vendor = PCI_VENDOR_ID_SI, + .device = PCI_DEVICE_ID_SI_760, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, }, { } }; diff --git a/drivers/char/agp/sworks-agp.c b/drivers/char/agp/sworks-agp.c index 55212a3811f..551ef25063e 100644 --- a/drivers/char/agp/sworks-agp.c +++ b/drivers/char/agp/sworks-agp.c @@ -455,15 +455,6 @@ static int __devinit agp_serverworks_probe(struct pci_dev *pdev, u32 temp, temp2; u8 cap_ptr = 0; - /* Everything is on func 1 here so we are hardcoding function one */ - bridge_dev = pci_find_slot((unsigned int)pdev->bus->number, - PCI_DEVFN(0, 1)); - if (!bridge_dev) { - printk(KERN_INFO PFX "Detected a Serverworks chipset " - "but could not find the secondary device.\n"); - return -ENODEV; - } - cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP); switch (pdev->device) { @@ -483,6 +474,15 @@ static int __devinit agp_serverworks_probe(struct pci_dev *pdev, return -ENODEV; } + /* Everything is on func 1 here so we are hardcoding function one */ + bridge_dev = pci_get_bus_and_slot((unsigned int)pdev->bus->number, + PCI_DEVFN(0, 1)); + if (!bridge_dev) { + printk(KERN_INFO PFX "Detected a Serverworks chipset " + "but could not find the secondary device.\n"); + return -ENODEV; + } + serverworks_private.svrwrks_dev = bridge_dev; serverworks_private.gart_addr_ofs = 0x10; @@ -515,7 +515,7 @@ static int __devinit agp_serverworks_probe(struct pci_dev *pdev, bridge->driver = &sworks_driver; bridge->dev_private_data = &serverworks_private, - bridge->dev = pdev; + bridge->dev = pci_dev_get(pdev); pci_set_drvdata(pdev, bridge); return agp_add_bridge(bridge); @@ -525,8 +525,11 @@ static void __devexit agp_serverworks_remove(struct pci_dev *pdev) { struct agp_bridge_data *bridge = pci_get_drvdata(pdev); + pci_dev_put(bridge->dev); agp_remove_bridge(bridge); agp_put_bridge(bridge); + pci_dev_put(serverworks_private.svrwrks_dev); + serverworks_private.svrwrks_dev = NULL; } static struct pci_device_id agp_serverworks_pci_table[] = { diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig index d155e81b5c9..993fa7b8925 100644 --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig @@ -9,6 +9,9 @@ config CPU_FREQ clock speed, you need to either enable a dynamic cpufreq governor (see below) after boot, or use a userspace tool. + To compile this driver as a module, choose M here: the + module will be called cpufreq. + For details, take a look at <file:Documentation/cpu-freq>. If in doubt, say N. @@ -16,7 +19,7 @@ config CPU_FREQ if CPU_FREQ config CPU_FREQ_TABLE - tristate + tristate config CPU_FREQ_DEBUG bool "Enable CPUfreq debugging" @@ -32,19 +35,26 @@ config CPU_FREQ_DEBUG 4 to activate CPUfreq governor debugging config CPU_FREQ_STAT - tristate "CPU frequency translation statistics" - select CPU_FREQ_TABLE - default y - help - This driver exports CPU frequency statistics information through sysfs - file system + tristate "CPU frequency translation statistics" + select CPU_FREQ_TABLE + default y + help + This driver exports CPU frequency statistics information through sysfs + file system. + + To compile this driver as a module, choose M here: the + module will be called cpufreq_stats. + + If in doubt, say N. config CPU_FREQ_STAT_DETAILS - bool "CPU frequency translation statistics details" - depends on CPU_FREQ_STAT - help - This will show detail CPU frequency translation table in sysfs file - system + bool "CPU frequency translation statistics details" + depends on CPU_FREQ_STAT + help + This will show detail CPU frequency translation table in sysfs file + system. + + If in doubt, say N. # Note that it is not currently possible to set the other governors (such as ondemand) # as the default, since if they fail to initialise, cpufreq will be @@ -78,29 +88,38 @@ config CPU_FREQ_DEFAULT_GOV_USERSPACE endchoice config CPU_FREQ_GOV_PERFORMANCE - tristate "'performance' governor" - help + tristate "'performance' governor" + help This cpufreq governor sets the frequency statically to the highest available CPU frequency. + To compile this driver as a module, choose M here: the + module will be called cpufreq_performance. + If in doubt, say Y. config CPU_FREQ_GOV_POWERSAVE - tristate "'powersave' governor" - help + tristate "'powersave' governor" + help This cpufreq governor sets the frequency statically to the lowest available CPU frequency. + To compile this driver as a module, choose M here: the + module will be called cpufreq_powersave. + If in doubt, say Y. config CPU_FREQ_GOV_USERSPACE - tristate "'userspace' governor for userspace frequency scaling" - help + tristate "'userspace' governor for userspace frequency scaling" + help Enable this cpufreq governor when you either want to set the CPU frequency manually or when an userspace program shall be able to set the CPU dynamically, like on LART <http://www.lartmaker.nl/>. + To compile this driver as a module, choose M here: the + module will be called cpufreq_userspace. + For details, take a look at <file:Documentation/cpu-freq/>. If in doubt, say Y. @@ -116,6 +135,9 @@ config CPU_FREQ_GOV_ONDEMAND do fast frequency switching (i.e, very low latency frequency transitions). + To compile this driver as a module, choose M here: the + module will be called cpufreq_ondemand. + For details, take a look at linux/Documentation/cpu-freq. If in doubt, say N. @@ -136,6 +158,9 @@ config CPU_FREQ_GOV_CONSERVATIVE step-by-step latency issues between the minimum and maximum frequency transitions in the CPU) you will probably want to use this governor. + To compile this driver as a module, choose M here: the + module will be called cpufreq_conservative. + For details, take a look at linux/Documentation/cpu-freq. If in doubt, say N. diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 3162010900c..893dbaf386f 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -768,6 +768,9 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) unlock_policy_rwsem_write(cpu); goto err_out; } + policy->user_policy.min = policy->cpuinfo.min_freq; + policy->user_policy.max = policy->cpuinfo.max_freq; + policy->user_policy.governor = policy->governor; #ifdef CONFIG_SMP for_each_cpu_mask(j, policy->cpus) { @@ -858,10 +861,13 @@ static int cpufreq_add_dev (struct sys_device * sys_dev) policy->governor = NULL; /* to assure that the starting sequence is * run in cpufreq_set_policy */ - unlock_policy_rwsem_write(cpu); /* set default policy */ - ret = cpufreq_set_policy(&new_policy); + ret = __cpufreq_set_policy(policy, &new_policy); + policy->user_policy.policy = policy->policy; + + unlock_policy_rwsem_write(cpu); + if (ret) { dprintk("setting policy failed\n"); goto err_out_unregister; @@ -1620,43 +1626,6 @@ error_out: } /** - * cpufreq_set_policy - set a new CPUFreq policy - * @policy: policy to be set. - * - * Sets a new CPU frequency and voltage scaling policy. - */ -int cpufreq_set_policy(struct cpufreq_policy *policy) -{ - int ret = 0; - struct cpufreq_policy *data; - - if (!policy) - return -EINVAL; - - data = cpufreq_cpu_get(policy->cpu); - if (!data) - return -EINVAL; - - if (unlikely(lock_policy_rwsem_write(policy->cpu))) - return -EINVAL; - - - ret = __cpufreq_set_policy(data, policy); - data->user_policy.min = data->min; - data->user_policy.max = data->max; - data->user_policy.policy = data->policy; - data->user_policy.governor = data->governor; - - unlock_policy_rwsem_write(policy->cpu); - - cpufreq_cpu_put(data); - - return ret; -} -EXPORT_SYMBOL(cpufreq_set_policy); - - -/** * cpufreq_update_policy - re-evaluate an existing cpufreq policy * @cpu: CPU which shall be re-evaluated * diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index ff8c4beaace..f21fe66c9ee 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -1,10 +1,10 @@ menu "Hardware crypto devices" config CRYPTO_DEV_PADLOCK - tristate "Support for VIA PadLock ACE" + bool "Support for VIA PadLock ACE" depends on X86_32 select CRYPTO_ALGAPI - default m + default y help Some VIA processors come with an integrated crypto engine (so called VIA PadLock ACE, Advanced Cryptography Engine) @@ -14,16 +14,6 @@ config CRYPTO_DEV_PADLOCK The instructions are used only when the CPU supports them. Otherwise software encryption is used. - Selecting M for this option will compile a helper module - padlock.ko that should autoload all below configured - algorithms. Don't worry if your hardware does not support - some or all of them. In such case padlock.ko will - simply write a single line into the kernel log informing - about its failure but everything will keep working fine. - - If you are unsure, say M. The compiled module will be - called padlock.ko - config CRYPTO_DEV_PADLOCK_AES tristate "PadLock driver for AES algorithm" depends on CRYPTO_DEV_PADLOCK @@ -55,7 +45,7 @@ source "arch/s390/crypto/Kconfig" config CRYPTO_DEV_GEODE tristate "Support for the Geode LX AES engine" - depends on CRYPTO && X86_32 && PCI + depends on X86_32 && PCI select CRYPTO_ALGAPI select CRYPTO_BLKCIPHER default m diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile index 6059cf86941..d070030f7d7 100644 --- a/drivers/crypto/Makefile +++ b/drivers/crypto/Makefile @@ -1,4 +1,3 @@ -obj-$(CONFIG_CRYPTO_DEV_PADLOCK) += padlock.o obj-$(CONFIG_CRYPTO_DEV_PADLOCK_AES) += padlock-aes.o obj-$(CONFIG_CRYPTO_DEV_PADLOCK_SHA) += padlock-sha.o obj-$(CONFIG_CRYPTO_DEV_GEODE) += geode-aes.o diff --git a/drivers/crypto/padlock.c b/drivers/crypto/padlock.c deleted file mode 100644 index d6d7dd5bb98..00000000000 --- a/drivers/crypto/padlock.c +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Cryptographic API. - * - * Support for VIA PadLock hardware crypto engine. - * - * Copyright (c) 2006 Michal Ludvig <michal@logix.cz> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - */ - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/errno.h> -#include <linux/crypto.h> -#include <linux/cryptohash.h> -#include <linux/interrupt.h> -#include <linux/kernel.h> -#include <linux/scatterlist.h> -#include "padlock.h" - -static int __init padlock_init(void) -{ - int success = 0; - - if (crypto_has_cipher("aes-padlock", 0, 0)) - success++; - - if (crypto_has_hash("sha1-padlock", 0, 0)) - success++; - - if (crypto_has_hash("sha256-padlock", 0, 0)) - success++; - - if (!success) { - printk(KERN_WARNING PFX "No VIA PadLock drivers have been loaded.\n"); - return -ENODEV; - } - - printk(KERN_NOTICE PFX "%d drivers are available.\n", success); - - return 0; -} - -static void __exit padlock_fini(void) -{ -} - -module_init(padlock_init); -module_exit(padlock_fini); - -MODULE_DESCRIPTION("Load all configured PadLock algorithms."); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Michal Ludvig"); - diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index 11935f66fcd..434a61b415a 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -2,9 +2,7 @@ # I2C subsystem configuration # -menu "I2C support" - -config I2C +menuconfig I2C tristate "I2C support" ---help--- I2C (pronounce: I-square-C) is a slow serial bus protocol used in @@ -22,9 +20,14 @@ config I2C This I2C support can also be built as a module. If so, the module will be called i2c-core. +if I2C + +config I2C_BOARDINFO + boolean + default y + config I2C_CHARDEV tristate "I2C device interface" - depends on I2C help Say Y here to use i2c-* device files, usually found in the /dev directory on your system. They make it possible to have user-space @@ -40,7 +43,6 @@ source drivers/i2c/chips/Kconfig config I2C_DEBUG_CORE bool "I2C Core debugging messages" - depends on I2C help Say Y here if you want the I2C core to produce a bunch of debug messages to the system log. Select this if you are having a @@ -48,7 +50,6 @@ config I2C_DEBUG_CORE config I2C_DEBUG_ALGO bool "I2C Algorithm debugging messages" - depends on I2C help Say Y here if you want the I2C algorithm drivers to produce a bunch of debug messages to the system log. Select this if you are having @@ -57,7 +58,6 @@ config I2C_DEBUG_ALGO config I2C_DEBUG_BUS bool "I2C Bus debugging messages" - depends on I2C help Say Y here if you want the I2C bus drivers to produce a bunch of debug messages to the system log. Select this if you are having @@ -66,12 +66,10 @@ config I2C_DEBUG_BUS config I2C_DEBUG_CHIP bool "I2C Chip debugging messages" - depends on I2C help Say Y here if you want the I2C chip drivers to produce a bunch of debug messages to the system log. Select this if you are having a problem with I2C support and want to see more of what is going on. -endmenu - +endif # I2C diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index 71c5a854ac5..ba26e6cbe74 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -2,6 +2,7 @@ # Makefile for the i2c core. # +obj-$(CONFIG_I2C_BOARDINFO) += i2c-boardinfo.o obj-$(CONFIG_I2C) += i2c-core.o obj-$(CONFIG_I2C_CHARDEV) += i2c-dev.o obj-y += busses/ chips/ algos/ diff --git a/drivers/i2c/algos/Kconfig b/drivers/i2c/algos/Kconfig index af0203409dd..58899078810 100644 --- a/drivers/i2c/algos/Kconfig +++ b/drivers/i2c/algos/Kconfig @@ -3,11 +3,9 @@ # menu "I2C Algorithms" - depends on I2C config I2C_ALGOBIT tristate "I2C bit-banging interfaces" - depends on I2C help This allows you to use a range of I2C adapters called bit-banging adapters. Say Y if you own an I2C adapter belonging to this class @@ -18,7 +16,6 @@ config I2C_ALGOBIT config I2C_ALGOPCF tristate "I2C PCF 8584 interfaces" - depends on I2C help This allows you to use a range of I2C adapters called PCF adapters. Say Y if you own an I2C adapter belonging to this class and then say @@ -29,7 +26,6 @@ config I2C_ALGOPCF config I2C_ALGOPCA tristate "I2C PCA 9564 interfaces" - depends on I2C help This allows you to use a range of I2C adapters called PCA adapters. Say Y if you own an I2C adapter belonging to this class and then say @@ -40,11 +36,11 @@ config I2C_ALGOPCA config I2C_ALGO8XX tristate "MPC8xx CPM I2C interface" - depends on 8xx && I2C + depends on 8xx config I2C_ALGO_SGI tristate "I2C SGI interfaces" - depends on I2C && (SGI_IP22 || SGI_IP32 || X86_VISWS) + depends on SGI_IP22 || SGI_IP32 || X86_VISWS help Supports the SGI interfaces like the ones found on SGI Indy VINO or SGI O2 MACE. diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c index 95aa5395a5b..8a5f5825bb7 100644 --- a/drivers/i2c/algos/i2c-algo-bit.c +++ b/drivers/i2c/algos/i2c-algo-bit.c @@ -33,19 +33,30 @@ /* ----- global defines ----------------------------------------------- */ -#define DEB(x) if (i2c_debug>=1) x; -#define DEB2(x) if (i2c_debug>=2) x; -#define DEBSTAT(x) if (i2c_debug>=3) x; /* print several statistical values*/ -#define DEBPROTO(x) if (i2c_debug>=9) { x; } - /* debug the protocol by showing transferred bits */ +#ifdef DEBUG +#define bit_dbg(level, dev, format, args...) \ + do { \ + if (i2c_debug >= level) \ + dev_dbg(dev, format, ##args); \ + } while (0) +#else +#define bit_dbg(level, dev, format, args...) \ + do {} while (0) +#endif /* DEBUG */ /* ----- global variables --------------------------------------------- */ -/* module parameters: - */ -static int i2c_debug; static int bit_test; /* see if the line-setting functions work */ +module_param(bit_test, bool, 0); +MODULE_PARM_DESC(bit_test, "Test the lines of the bus to see if it is stuck"); + +#ifdef DEBUG +static int i2c_debug = 1; +module_param(i2c_debug, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(i2c_debug, + "debug level - 0 off; 1 normal; 2 verbose; 3 very verbose"); +#endif /* --- setting states on the bus with the right timing: --------------- */ @@ -57,19 +68,19 @@ static int bit_test; /* see if the line-setting functions work */ static inline void sdalo(struct i2c_algo_bit_data *adap) { setsda(adap,0); - udelay(adap->udelay); + udelay((adap->udelay + 1) / 2); } static inline void sdahi(struct i2c_algo_bit_data *adap) { setsda(adap,1); - udelay(adap->udelay); + udelay((adap->udelay + 1) / 2); } static inline void scllo(struct i2c_algo_bit_data *adap) { setscl(adap,0); - udelay(adap->udelay); + udelay(adap->udelay / 2); } /* @@ -98,7 +109,11 @@ static int sclhi(struct i2c_algo_bit_data *adap) } cond_resched(); } - DEBSTAT(printk(KERN_DEBUG "needed %ld jiffies\n", jiffies-start)); +#ifdef DEBUG + if (jiffies != start && i2c_debug >= 3) + pr_debug("i2c-algo-bit: needed %ld jiffies for SCL to go " + "high\n", jiffies - start); +#endif done: udelay(adap->udelay); @@ -110,30 +125,29 @@ done: static void i2c_start(struct i2c_algo_bit_data *adap) { /* assert: scl, sda are high */ - DEBPROTO(printk("S ")); - sdalo(adap); + setsda(adap, 0); + udelay(adap->udelay); scllo(adap); } static void i2c_repstart(struct i2c_algo_bit_data *adap) { - /* scl, sda may not be high */ - DEBPROTO(printk(" Sr ")); - setsda(adap,1); + /* assert: scl is low */ + sdahi(adap); sclhi(adap); - - sdalo(adap); + setsda(adap, 0); + udelay(adap->udelay); scllo(adap); } static void i2c_stop(struct i2c_algo_bit_data *adap) { - DEBPROTO(printk("P\n")); /* assert: scl is low */ sdalo(adap); sclhi(adap); - sdahi(adap); + setsda(adap, 1); + udelay(adap->udelay); } @@ -145,7 +159,7 @@ static void i2c_stop(struct i2c_algo_bit_data *adap) * 0 if the device did not ack * -ETIMEDOUT if an error occurred (while raising the scl line) */ -static int i2c_outb(struct i2c_adapter *i2c_adap, char c) +static int i2c_outb(struct i2c_adapter *i2c_adap, unsigned char c) { int i; int sb; @@ -154,34 +168,32 @@ static int i2c_outb(struct i2c_adapter *i2c_adap, char c) /* assert: scl is low */ for ( i=7 ; i>=0 ; i-- ) { - sb = c & ( 1 << i ); + sb = (c >> i) & 1; setsda(adap,sb); - udelay(adap->udelay); - DEBPROTO(printk(KERN_DEBUG "%d",sb!=0)); + udelay((adap->udelay + 1) / 2); if (sclhi(adap)<0) { /* timed out */ - sdahi(adap); /* we don't want to block the net */ - DEB2(printk(KERN_DEBUG " i2c_outb: 0x%02x, timeout at bit #%d\n", c&0xff, i)); + bit_dbg(1, &i2c_adap->dev, "i2c_outb: 0x%02x, " + "timeout at bit #%d\n", (int)c, i); return -ETIMEDOUT; }; /* do arbitration here: * if ( sb && ! getsda(adap) ) -> ouch! Get out of here. */ - setscl(adap, 0 ); - udelay(adap->udelay); + scllo(adap); } sdahi(adap); if (sclhi(adap)<0){ /* timeout */ - DEB2(printk(KERN_DEBUG " i2c_outb: 0x%02x, timeout at ack\n", c&0xff)); - return -ETIMEDOUT; + bit_dbg(1, &i2c_adap->dev, "i2c_outb: 0x%02x, " + "timeout at ack\n", (int)c); + return -ETIMEDOUT; }; /* read ack: SDA should be pulled down by slave */ - ack=getsda(adap); /* ack: sda is pulled low ->success. */ - DEB2(printk(KERN_DEBUG " i2c_outb: 0x%02x , getsda() = %d\n", c & 0xff, ack)); + ack = !getsda(adap); /* ack: sda is pulled low -> success */ + bit_dbg(2, &i2c_adap->dev, "i2c_outb: 0x%02x %s\n", (int)c, + ack ? "A" : "NA"); - DEBPROTO( printk(KERN_DEBUG "[%2.2x]",c&0xff) ); - DEBPROTO(if (0==ack){ printk(KERN_DEBUG " A ");} else printk(KERN_DEBUG " NA ") ); scllo(adap); - return 0==ack; /* return 1 if device acked */ + return ack; /* assert: scl is low (sda undef) */ } @@ -198,19 +210,18 @@ static int i2c_inb(struct i2c_adapter *i2c_adap) sdahi(adap); for (i=0;i<8;i++) { if (sclhi(adap)<0) { /* timeout */ - DEB2(printk(KERN_DEBUG " i2c_inb: timeout at bit #%d\n", 7-i)); + bit_dbg(1, &i2c_adap->dev, "i2c_inb: timeout at bit " + "#%d\n", 7 - i); return -ETIMEDOUT; }; indata *= 2; if ( getsda(adap) ) indata |= 0x01; - scllo(adap); + setscl(adap, 0); + udelay(i == 7 ? adap->udelay / 2 : adap->udelay); } /* assert: scl is low */ - DEB2(printk(KERN_DEBUG "i2c_inb: 0x%02x\n", indata & 0xff)); - - DEBPROTO(printk(KERN_DEBUG " 0x%02x", indata & 0xff)); - return (int) (indata & 0xff); + return indata; } /* @@ -221,73 +232,67 @@ static int test_bus(struct i2c_algo_bit_data *adap, char* name) { int scl,sda; if (adap->getscl==NULL) - printk(KERN_INFO "i2c-algo-bit.o: Testing SDA only, " - "SCL is not readable.\n"); + pr_info("%s: Testing SDA only, SCL is not readable\n", name); sda=getsda(adap); scl=(adap->getscl==NULL?1:getscl(adap)); - printk(KERN_DEBUG "i2c-algo-bit.o: (0) scl=%d, sda=%d\n",scl,sda); if (!scl || !sda ) { - printk(KERN_WARNING "i2c-algo-bit.o: %s seems to be busy.\n", name); + printk(KERN_WARNING "%s: bus seems to be busy\n", name); goto bailout; } sdalo(adap); sda=getsda(adap); scl=(adap->getscl==NULL?1:getscl(adap)); - printk(KERN_DEBUG "i2c-algo-bit.o: (1) scl=%d, sda=%d\n",scl,sda); if ( 0 != sda ) { - printk(KERN_WARNING "i2c-algo-bit.o: SDA stuck high!\n"); + printk(KERN_WARNING "%s: SDA stuck high!\n", name); goto bailout; } if ( 0 == scl ) { - printk(KERN_WARNING "i2c-algo-bit.o: SCL unexpected low " - "while pulling SDA low!\n"); + printk(KERN_WARNING "%s: SCL unexpected low " + "while pulling SDA low!\n", name); goto bailout; } sdahi(adap); sda=getsda(adap); scl=(adap->getscl==NULL?1:getscl(adap)); - printk(KERN_DEBUG "i2c-algo-bit.o: (2) scl=%d, sda=%d\n",scl,sda); if ( 0 == sda ) { - printk(KERN_WARNING "i2c-algo-bit.o: SDA stuck low!\n"); + printk(KERN_WARNING "%s: SDA stuck low!\n", name); goto bailout; } if ( 0 == scl ) { - printk(KERN_WARNING "i2c-algo-bit.o: SCL unexpected low " - "while pulling SDA high!\n"); + printk(KERN_WARNING "%s: SCL unexpected low " + "while pulling SDA high!\n", name); goto bailout; } scllo(adap); sda=getsda(adap); scl=(adap->getscl==NULL?0:getscl(adap)); - printk(KERN_DEBUG "i2c-algo-bit.o: (3) scl=%d, sda=%d\n",scl,sda); if ( 0 != scl ) { - printk(KERN_WARNING "i2c-algo-bit.o: SCL stuck high!\n"); + printk(KERN_WARNING "%s: SCL stuck high!\n", name); goto bailout; } if ( 0 == sda ) { - printk(KERN_WARNING "i2c-algo-bit.o: SDA unexpected low " - "while pulling SCL low!\n"); + printk(KERN_WARNING "%s: SDA unexpected low " + "while pulling SCL low!\n", name); goto bailout; } sclhi(adap); sda=getsda(adap); scl=(adap->getscl==NULL?1:getscl(adap)); - printk(KERN_DEBUG "i2c-algo-bit.o: (4) scl=%d, sda=%d\n",scl,sda); if ( 0 == scl ) { - printk(KERN_WARNING "i2c-algo-bit.o: SCL stuck low!\n"); + printk(KERN_WARNING "%s: SCL stuck low!\n", name); goto bailout; } if ( 0 == sda ) { - printk(KERN_WARNING "i2c-algo-bit.o: SDA unexpected low " - "while pulling SCL high!\n"); + printk(KERN_WARNING "%s: SDA unexpected low " + "while pulling SCL high!\n", name); goto bailout; } - printk(KERN_INFO "i2c-algo-bit.o: %s passed test.\n",name); + pr_info("%s: Test OK\n", name); return 0; bailout: sdahi(adap); @@ -312,44 +317,39 @@ static int try_address(struct i2c_adapter *i2c_adap, int i,ret = -1; for (i=0;i<=retries;i++) { ret = i2c_outb(i2c_adap,addr); - if (ret==1) - break; /* success! */ - i2c_stop(adap); - udelay(5/*adap->udelay*/); - if (i==retries) /* no success */ + if (ret == 1 || i == retries) break; - i2c_start(adap); + bit_dbg(3, &i2c_adap->dev, "emitting stop condition\n"); + i2c_stop(adap); udelay(adap->udelay); + yield(); + bit_dbg(3, &i2c_adap->dev, "emitting start condition\n"); + i2c_start(adap); } - DEB2(if (i) - printk(KERN_DEBUG "i2c-algo-bit.o: Used %d tries to %s client at 0x%02x : %s\n", - i+1, addr & 1 ? "read" : "write", addr>>1, - ret==1 ? "success" : ret==0 ? "no ack" : "failed, timeout?" ) - ); + if (i && ret) + bit_dbg(1, &i2c_adap->dev, "Used %d tries to %s client at " + "0x%02x: %s\n", i + 1, + addr & 1 ? "read from" : "write to", addr >> 1, + ret == 1 ? "success" : "failed, timeout?"); return ret; } static int sendbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) { - struct i2c_algo_bit_data *adap = i2c_adap->algo_data; - char c; - const char *temp = msg->buf; + const unsigned char *temp = msg->buf; int count = msg->len; unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK; int retval; int wrcount=0; while (count > 0) { - c = *temp; - DEB2(dev_dbg(&i2c_adap->dev, "sendbytes: writing %2.2X\n", c&0xff)); - retval = i2c_outb(i2c_adap,c); + retval = i2c_outb(i2c_adap, *temp); if ((retval>0) || (nak_ok && (retval==0))) { /* ok or ignored NAK */ count--; temp++; wrcount++; } else { /* arbitration or no acknowledge */ dev_err(&i2c_adap->dev, "sendbytes: error - bailout.\n"); - i2c_stop(adap); return (retval<0)? retval : -EFAULT; /* got a better one ?? */ } @@ -362,7 +362,7 @@ static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) int inval; int rdcount=0; /* counts bytes read */ struct i2c_algo_bit_data *adap = i2c_adap->algo_data; - char *temp = msg->buf; + unsigned char *temp = msg->buf; int count = msg->len; while (count > 0) { @@ -371,30 +371,44 @@ static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) *temp = inval; rdcount++; } else { /* read timed out */ - printk(KERN_ERR "i2c-algo-bit.o: readbytes: i2c_inb timed out.\n"); break; } temp++; count--; - if (msg->flags & I2C_M_NO_RD_ACK) + if (msg->flags & I2C_M_NO_RD_ACK) { + bit_dbg(2, &i2c_adap->dev, "i2c_inb: 0x%02x\n", + inval); continue; - - if ( count > 0 ) { /* send ack */ - sdalo(adap); - DEBPROTO(printk(" Am ")); - } else { - sdahi(adap); /* neg. ack on last byte */ - DEBPROTO(printk(" NAm ")); } + + /* assert: sda is high */ + if (count) /* send ack */ + setsda(adap, 0); + udelay((adap->udelay + 1) / 2); + bit_dbg(2, &i2c_adap->dev, "i2c_inb: 0x%02x %s\n", inval, + count ? "A" : "NA"); if (sclhi(adap)<0) { /* timeout */ - sdahi(adap); - printk(KERN_ERR "i2c-algo-bit.o: readbytes: Timeout at ack\n"); + dev_err(&i2c_adap->dev, "readbytes: timeout at ack\n"); return -ETIMEDOUT; }; scllo(adap); - sdahi(adap); + + /* Some SMBus transactions require that we receive the + transaction length as the first read byte. */ + if (rdcount == 1 && (msg->flags & I2C_M_RECV_LEN)) { + if (inval <= 0 || inval > I2C_SMBUS_BLOCK_MAX) { + dev_err(&i2c_adap->dev, "readbytes: invalid " + "block length (%d)\n", inval); + return -EREMOTEIO; + } + /* The original count value accounts for the extra + bytes, that is, either 1 for a regular transaction, + or 2 for a PEC transaction. */ + count += inval; + msg->len += inval; + } } return rdcount; } @@ -421,27 +435,31 @@ static int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) if ( (flags & I2C_M_TEN) ) { /* a ten bit address */ addr = 0xf0 | (( msg->addr >> 7) & 0x03); - DEB2(printk(KERN_DEBUG "addr0: %d\n",addr)); + bit_dbg(2, &i2c_adap->dev, "addr0: %d\n", addr); /* try extended address code...*/ ret = try_address(i2c_adap, addr, retries); if ((ret != 1) && !nak_ok) { - printk(KERN_ERR "died at extended address code.\n"); + dev_err(&i2c_adap->dev, + "died at extended address code\n"); return -EREMOTEIO; } /* the remaining 8 bit address */ ret = i2c_outb(i2c_adap,msg->addr & 0x7f); if ((ret != 1) && !nak_ok) { /* the chip did not ack / xmission error occurred */ - printk(KERN_ERR "died at 2nd address code.\n"); + dev_err(&i2c_adap->dev, "died at 2nd address code\n"); return -EREMOTEIO; } if ( flags & I2C_M_RD ) { + bit_dbg(3, &i2c_adap->dev, "emitting repeated " + "start condition\n"); i2c_repstart(adap); /* okay, now switch into reading mode */ addr |= 0x01; ret = try_address(i2c_adap, addr, retries); if ((ret!=1) && !nak_ok) { - printk(KERN_ERR "died at extended address code.\n"); + dev_err(&i2c_adap->dev, + "died at repeated address code\n"); return -EREMOTEIO; } } @@ -468,44 +486,62 @@ static int bit_xfer(struct i2c_adapter *i2c_adap, int i,ret; unsigned short nak_ok; + bit_dbg(3, &i2c_adap->dev, "emitting start condition\n"); i2c_start(adap); for (i=0;i<num;i++) { pmsg = &msgs[i]; nak_ok = pmsg->flags & I2C_M_IGNORE_NAK; if (!(pmsg->flags & I2C_M_NOSTART)) { if (i) { + bit_dbg(3, &i2c_adap->dev, "emitting " + "repeated start condition\n"); i2c_repstart(adap); } ret = bit_doAddress(i2c_adap, pmsg); if ((ret != 0) && !nak_ok) { - DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: NAK from device addr %2.2x msg #%d\n" - ,msgs[i].addr,i)); - return (ret<0) ? ret : -EREMOTEIO; + bit_dbg(1, &i2c_adap->dev, "NAK from " + "device addr 0x%02x msg #%d\n", + msgs[i].addr, i); + goto bailout; } } if (pmsg->flags & I2C_M_RD ) { /* read bytes into buffer*/ ret = readbytes(i2c_adap, pmsg); - DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: read %d bytes.\n",ret)); - if (ret < pmsg->len ) { - return (ret<0)? ret : -EREMOTEIO; + if (ret >= 1) + bit_dbg(2, &i2c_adap->dev, "read %d byte%s\n", + ret, ret == 1 ? "" : "s"); + if (ret < pmsg->len) { + if (ret >= 0) + ret = -EREMOTEIO; + goto bailout; } } else { /* write bytes from buffer */ ret = sendbytes(i2c_adap, pmsg); - DEB2(printk(KERN_DEBUG "i2c-algo-bit.o: wrote %d bytes.\n",ret)); - if (ret < pmsg->len ) { - return (ret<0) ? ret : -EREMOTEIO; + if (ret >= 1) + bit_dbg(2, &i2c_adap->dev, "wrote %d byte%s\n", + ret, ret == 1 ? "" : "s"); + if (ret < pmsg->len) { + if (ret >= 0) + ret = -EREMOTEIO; + goto bailout; } } } + ret = i; + +bailout: + bit_dbg(3, &i2c_adap->dev, "emitting stop condition\n"); i2c_stop(adap); - return num; + return ret; } static u32 bit_func(struct i2c_adapter *adap) { return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | + I2C_FUNC_SMBUS_READ_BLOCK_DATA | + I2C_FUNC_SMBUS_BLOCK_PROC_CALL | I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING; } @@ -520,7 +556,7 @@ static const struct i2c_algorithm i2c_bit_algo = { /* * registering functions to load algorithms at runtime */ -int i2c_bit_add_bus(struct i2c_adapter *adap) +static int i2c_bit_prepare_bus(struct i2c_adapter *adap) { struct i2c_algo_bit_data *bit_adap = adap->algo_data; @@ -530,25 +566,39 @@ int i2c_bit_add_bus(struct i2c_adapter *adap) return -ENODEV; } - DEB2(dev_dbg(&adap->dev, "hw routines registered.\n")); - /* register new adapter to i2c module... */ adap->algo = &i2c_bit_algo; adap->timeout = 100; /* default values, should */ adap->retries = 3; /* be replaced by defines */ + return 0; +} + +int i2c_bit_add_bus(struct i2c_adapter *adap) +{ + int err; + + err = i2c_bit_prepare_bus(adap); + if (err) + return err; + return i2c_add_adapter(adap); } EXPORT_SYMBOL(i2c_bit_add_bus); +int i2c_bit_add_numbered_bus(struct i2c_adapter *adap) +{ + int err; + + err = i2c_bit_prepare_bus(adap); + if (err) + return err; + + return i2c_add_numbered_adapter(adap); +} +EXPORT_SYMBOL(i2c_bit_add_numbered_bus); + MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>"); MODULE_DESCRIPTION("I2C-Bus bit-banging algorithm"); MODULE_LICENSE("GPL"); - -module_param(bit_test, bool, 0); -module_param(i2c_debug, int, S_IRUGO | S_IWUSR); - -MODULE_PARM_DESC(bit_test, "Test the lines of the bus to see if it is stuck"); -MODULE_PARM_DESC(i2c_debug, - "debug level - 0 off; 1 normal; 2,3 more verbose; 9 bit-protocol"); diff --git a/drivers/i2c/algos/i2c-algo-sgi.c b/drivers/i2c/algos/i2c-algo-sgi.c index ac2d5053078..6eaf145e1ad 100644 --- a/drivers/i2c/algos/i2c-algo-sgi.c +++ b/drivers/i2c/algos/i2c-algo-sgi.c @@ -1,6 +1,7 @@ /* - * i2c-algo-sgi.c: i2c driver algorithms for SGI adapters. - * + * i2c-algo-sgi.c: i2c driver algorithm used by the VINO (SGI Indy) and + * MACE (SGI O2) chips. + * * This file is subject to the terms and conditions of the GNU General Public * License version 2 as published by the Free Software Foundation. * @@ -162,8 +163,8 @@ static const struct i2c_algorithm sgi_algo = { .functionality = sgi_func, }; -/* - * registering functions to load algorithms at runtime +/* + * registering functions to load algorithms at runtime */ int i2c_sgi_add_bus(struct i2c_adapter *adap) { diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index ece31d2c6c6..838dc1c19d6 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -3,11 +3,10 @@ # menu "I2C Hardware Bus support" - depends on I2C config I2C_ALI1535 tristate "ALI 1535" - depends on I2C && PCI + depends on PCI help If you say yes to this option, support will be included for the SMB Host controller on Acer Labs Inc. (ALI) M1535 South Bridges. The SMB @@ -19,7 +18,7 @@ config I2C_ALI1535 config I2C_ALI1563 tristate "ALI 1563" - depends on I2C && PCI && EXPERIMENTAL + depends on PCI && EXPERIMENTAL help If you say yes to this option, support will be included for the SMB Host controller on Acer Labs Inc. (ALI) M1563 South Bridges. The SMB @@ -31,7 +30,7 @@ config I2C_ALI1563 config I2C_ALI15X3 tristate "ALI 15x3" - depends on I2C && PCI + depends on PCI help If you say yes to this option, support will be included for the Acer Labs Inc. (ALI) M1514 and M1543 motherboard I2C interfaces. @@ -41,7 +40,7 @@ config I2C_ALI15X3 config I2C_AMD756 tristate "AMD 756/766/768/8111 and nVidia nForce" - depends on I2C && PCI + depends on PCI help If you say yes to this option, support will be included for the AMD 756/766/768 mainboard I2C interfaces. The driver also includes @@ -66,7 +65,7 @@ config I2C_AMD756_S4882 config I2C_AMD8111 tristate "AMD 8111" - depends on I2C && PCI + depends on PCI help If you say yes to this option, support will be included for the second (SMBus 2.0) AMD 8111 mainboard I2C interface. @@ -76,14 +75,14 @@ config I2C_AMD8111 config I2C_AT91 tristate "Atmel AT91 I2C Two-Wire interface (TWI)" - depends on I2C && ARCH_AT91 && EXPERIMENTAL + depends on ARCH_AT91 && EXPERIMENTAL help This supports the use of the I2C interface on Atmel AT91 processors. config I2C_AU1550 tristate "Au1550/Au1200 SMBus interface" - depends on I2C && (SOC_AU1550 || SOC_AU1200) + depends on SOC_AU1550 || SOC_AU1200 help If you say yes to this option, support will be included for the Au1550 and Au1200 SMBus interface. @@ -91,9 +90,25 @@ config I2C_AU1550 This driver can also be built as a module. If so, the module will be called i2c-au1550. +config I2C_BLACKFIN_TWI + tristate "Blackfin TWI I2C support" + depends on BF534 || BF536 || BF537 + help + This is the TWI I2C device driver for Blackfin 534/536/537. + This driver can also be built as a module. If so, the module + will be called i2c-bfin-twi. + +config I2C_BLACKFIN_TWI_CLK_KHZ + int "Blackfin TWI I2C clock (kHz)" + depends on I2C_BLACKFIN_TWI + range 10 400 + default 50 + help + The unit of the TWI clock is kHz. + config I2C_ELEKTOR tristate "Elektor ISA card" - depends on I2C && ISA && BROKEN_ON_SMP + depends on ISA && BROKEN_ON_SMP select I2C_ALGOPCF help This supports the PCF8584 ISA bus I2C adapter. Say Y if you own @@ -102,9 +117,17 @@ config I2C_ELEKTOR This support is also available as a module. If so, the module will be called i2c-elektor. +config I2C_GPIO + tristate "GPIO-based bitbanging I2C" + depends on GENERIC_GPIO + select I2C_ALGOBIT + help + This is a very simple bitbanging I2C driver utilizing the + arch-neutral GPIO API to control the SCL and SDA lines. + config I2C_HYDRA tristate "CHRP Apple Hydra Mac I/O I2C interface" - depends on I2C && PCI && PPC_CHRP && EXPERIMENTAL + depends on PCI && PPC_CHRP && EXPERIMENTAL select I2C_ALGOBIT help This supports the use of the I2C interface in the Apple Hydra Mac @@ -116,7 +139,7 @@ config I2C_HYDRA config I2C_I801 tristate "Intel 82801 (ICH)" - depends on I2C && PCI + depends on PCI help If you say yes to this option, support will be included for the Intel 801 family of mainboard I2C interfaces. Specifically, the following @@ -139,7 +162,7 @@ config I2C_I801 config I2C_I810 tristate "Intel 810/815" - depends on I2C && PCI + depends on PCI select I2C_ALGOBIT help If you say yes to this option, support will be included for the Intel @@ -156,7 +179,7 @@ config I2C_I810 config I2C_PXA tristate "Intel PXA2XX I2C adapter (EXPERIMENTAL)" - depends on I2C && EXPERIMENTAL && ARCH_PXA + depends on EXPERIMENTAL && ARCH_PXA help If you have devices in the PXA I2C bus, say yes to this option. This driver can also be built as a module. If so, the module @@ -172,7 +195,7 @@ config I2C_PXA_SLAVE config I2C_PIIX4 tristate "Intel PIIX4 and compatible (ATI/Serverworks/Broadcom/SMSC)" - depends on I2C && PCI + depends on PCI help If you say yes to this option, support will be included for the Intel PIIX4 family of mainboard I2C interfaces. Specifically, the following @@ -195,7 +218,7 @@ config I2C_PIIX4 config I2C_IBM_IIC tristate "IBM PPC 4xx on-chip I2C interface" - depends on IBM_OCP && I2C + depends on IBM_OCP help Say Y here if you want to use IIC peripheral found on embedded IBM PPC 4xx based systems. @@ -205,7 +228,7 @@ config I2C_IBM_IIC config I2C_IOP3XX tristate "Intel IOPx3xx and IXP4xx on-chip I2C interface" - depends on (ARCH_IOP32X || ARCH_IOP33X || ARCH_IXP4XX || ARCH_IOP13XX) && I2C + depends on ARCH_IOP32X || ARCH_IOP33X || ARCH_IXP4XX || ARCH_IOP13XX help Say Y here if you want to use the IIC bus controller on the Intel IOPx3xx I/O Processors or IXP4xx Network Processors. @@ -215,11 +238,10 @@ config I2C_IOP3XX config I2C_ISA tristate - depends on I2C config I2C_IXP4XX - tristate "IXP4xx GPIO-Based I2C Interface" - depends on I2C && ARCH_IXP4XX + tristate "IXP4xx GPIO-Based I2C Interface (DEPRECATED)" + depends on ARCH_IXP4XX select I2C_ALGOBIT help Say Y here if you have an Intel IXP4xx(420,421,422,425) based @@ -228,9 +250,12 @@ config I2C_IXP4XX This support is also available as a module. If so, the module will be called i2c-ixp4xx. + This driver is deprecated and will be dropped soon. Use i2c-gpio + instead. + config I2C_IXP2000 - tristate "IXP2000 GPIO-Based I2C Interface" - depends on I2C && ARCH_IXP2000 + tristate "IXP2000 GPIO-Based I2C Interface (DEPRECATED)" + depends on ARCH_IXP2000 select I2C_ALGOBIT help Say Y here if you have an Intel IXP2000(2400, 2800, 2850) based @@ -239,9 +264,12 @@ config I2C_IXP2000 This support is also available as a module. If so, the module will be called i2c-ixp2000. + This driver is deprecated and will be dropped soon. Use i2c-gpio + instead. + config I2C_POWERMAC tristate "Powermac I2C interface" - depends on I2C && PPC_PMAC + depends on PPC_PMAC default y help This exposes the various PowerMac i2c interfaces to the linux i2c @@ -253,7 +281,7 @@ config I2C_POWERMAC config I2C_MPC tristate "MPC107/824x/85xx/52xx/86xx" - depends on I2C && PPC32 + depends on PPC32 help If you say yes to this option, support will be included for the built-in I2C interface on the MPC107/Tsi107/MPC8240/MPC8245 and @@ -265,7 +293,7 @@ config I2C_MPC config I2C_NFORCE2 tristate "Nvidia nForce2, nForce3 and nForce4" - depends on I2C && PCI + depends on PCI help If you say yes to this option, support will be included for the Nvidia nForce2, nForce3 and nForce4 families of mainboard I2C interfaces. @@ -275,7 +303,7 @@ config I2C_NFORCE2 config I2C_OCORES tristate "OpenCores I2C Controller" - depends on I2C && EXPERIMENTAL + depends on EXPERIMENTAL help If you say yes to this option, support will be included for the OpenCores I2C controller. For details see @@ -286,7 +314,7 @@ config I2C_OCORES config I2C_OMAP tristate "OMAP I2C adapter" - depends on I2C && ARCH_OMAP + depends on ARCH_OMAP default y if MACH_OMAP_H3 || MACH_OMAP_OSK help If you say yes to this option, support will be included for the @@ -296,7 +324,7 @@ config I2C_OMAP config I2C_PARPORT tristate "Parallel port adapter" - depends on I2C && PARPORT + depends on PARPORT select I2C_ALGOBIT help This supports parallel port I2C adapters such as the ones made by @@ -320,7 +348,6 @@ config I2C_PARPORT config I2C_PARPORT_LIGHT tristate "Parallel port adapter (light)" - depends on I2C select I2C_ALGOBIT help This supports parallel port I2C adapters such as the ones made by @@ -344,13 +371,13 @@ config I2C_PARPORT_LIGHT config I2C_PASEMI tristate "PA Semi SMBus interface" - depends on PPC_PASEMI && I2C && PCI + depends on PPC_PASEMI && PCI help Supports the PA Semi PWRficient on-chip SMBus interfaces. config I2C_PROSAVAGE tristate "S3/VIA (Pro)Savage" - depends on I2C && PCI + depends on PCI select I2C_ALGOBIT help If you say yes to this option, support will be included for the @@ -365,19 +392,19 @@ config I2C_PROSAVAGE config I2C_RPXLITE tristate "Embedded Planet RPX Lite/Classic support" - depends on (RPXLITE || RPXCLASSIC) && I2C + depends on RPXLITE || RPXCLASSIC select I2C_ALGO8XX config I2C_S3C2410 tristate "S3C2410 I2C Driver" - depends on I2C && ARCH_S3C2410 + depends on ARCH_S3C2410 help Say Y here to include support for I2C controller in the Samsung S3C2410 based System-on-Chip devices. config I2C_SAVAGE4 tristate "S3 Savage 4" - depends on I2C && PCI && EXPERIMENTAL + depends on PCI && EXPERIMENTAL select I2C_ALGOBIT help If you say yes to this option, support will be included for the @@ -388,13 +415,25 @@ config I2C_SAVAGE4 config I2C_SIBYTE tristate "SiByte SMBus interface" - depends on SIBYTE_SB1xxx_SOC && I2C + depends on SIBYTE_SB1xxx_SOC help Supports the SiByte SOC on-chip I2C interfaces (2 channels). +config I2C_SIMTEC + tristate "Simtec Generic I2C interface" + select I2C_ALGOBIT + help + If you say yes to this option, support will be inclyded for + the Simtec Generic I2C interface. This driver is for the + simple I2C bus used on newer Simtec products for general + I2C, such as DDC on the Simtec BBD2016A. + + This driver can also be build as a module. If so, the module + will be called i2c-simtec. + config SCx200_I2C - tristate "NatSemi SCx200 I2C using GPIO pins" - depends on SCx200_GPIO && I2C + tristate "NatSemi SCx200 I2C using GPIO pins (DEPRECATED)" + depends on SCx200_GPIO select I2C_ALGOBIT help Enable the use of two GPIO pins of a SCx200 processor as an I2C bus. @@ -404,6 +443,9 @@ config SCx200_I2C This support is also available as a module. If so, the module will be called scx200_i2c. + This driver is deprecated and will be dropped soon. Use i2c-gpio + (or scx200_acb) instead. + config SCx200_I2C_SCL int "GPIO pin used for SCL" depends on SCx200_I2C @@ -422,7 +464,7 @@ config SCx200_I2C_SDA config SCx200_ACB tristate "Geode ACCESS.bus support" - depends on X86_32 && I2C && PCI + depends on X86_32 && PCI help Enable the use of the ACCESS.bus controllers on the Geode SCx200 and SC1100 processors and the CS5535 and CS5536 Geode companion devices. @@ -434,7 +476,7 @@ config SCx200_ACB config I2C_SIS5595 tristate "SiS 5595" - depends on I2C && PCI + depends on PCI help If you say yes to this option, support will be included for the SiS5595 SMBus (a subset of I2C) interface. @@ -444,7 +486,7 @@ config I2C_SIS5595 config I2C_SIS630 tristate "SiS 630/730" - depends on I2C && PCI + depends on PCI help If you say yes to this option, support will be included for the SiS630 and SiS730 SMBus (a subset of I2C) interface. @@ -454,7 +496,7 @@ config I2C_SIS630 config I2C_SIS96X tristate "SiS 96x" - depends on I2C && PCI + depends on PCI help If you say yes to this option, support will be included for the SiS 96x SMBus (a subset of I2C) interfaces. Specifically, the following @@ -472,7 +514,7 @@ config I2C_SIS96X config I2C_STUB tristate "I2C/SMBus Test Stub" - depends on I2C && EXPERIMENTAL && 'm' + depends on EXPERIMENTAL && m default 'n' help This module may be useful to developers of SMBus client drivers, @@ -483,9 +525,20 @@ config I2C_STUB If you don't know what to do here, definitely say N. +config I2C_TINY_USB + tristate "I2C-Tiny-USB" + depends on USB + help + If you say yes to this option, support will be included for the + i2c-tiny-usb, a simple do-it-yourself USB to I2C interface. See + http://www.harbaum.org/till/i2c_tiny_usb for hardware details. + + This driver can also be built as a module. If so, the module + will be called i2c-tiny-usb. + config I2C_VERSATILE tristate "ARM Versatile/Realview I2C bus support" - depends on I2C && (ARCH_VERSATILE || ARCH_REALVIEW) + depends on ARCH_VERSATILE || ARCH_REALVIEW select I2C_ALGOBIT help Say yes if you want to support the I2C serial bus on ARMs Versatile @@ -496,7 +549,7 @@ config I2C_VERSATILE config I2C_ACORN bool "Acorn IOC/IOMD I2C bus support" - depends on I2C && ARCH_ACORN + depends on ARCH_ACORN default y select I2C_ALGOBIT help @@ -506,7 +559,7 @@ config I2C_ACORN config I2C_VIA tristate "VIA 82C586B" - depends on I2C && PCI && EXPERIMENTAL + depends on PCI && EXPERIMENTAL select I2C_ALGOBIT help If you say yes to this option, support will be included for the VIA @@ -517,7 +570,7 @@ config I2C_VIA config I2C_VIAPRO tristate "VIA VT82C596/82C686/82xx and CX700" - depends on I2C && PCI + depends on PCI help If you say yes to this option, support will be included for the VIA VT82C596 and later SMBus interface. Specifically, the following @@ -536,7 +589,7 @@ config I2C_VIAPRO config I2C_VOODOO3 tristate "Voodoo 3" - depends on I2C && PCI + depends on PCI select I2C_ALGOBIT help If you say yes to this option, support will be included for the @@ -547,7 +600,7 @@ config I2C_VOODOO3 config I2C_PCA_ISA tristate "PCA9564 on an ISA bus" - depends on I2C + depends on ISA select I2C_ALGOPCA default n help @@ -564,7 +617,7 @@ config I2C_PCA_ISA config I2C_MV64XXX tristate "Marvell mv64xxx I2C Controller" - depends on I2C && MV64X60 && EXPERIMENTAL + depends on MV64X60 && EXPERIMENTAL help If you say yes to this option, support will be included for the built-in I2C interface on the Marvell 64xxx line of host bridges. @@ -574,7 +627,7 @@ config I2C_MV64XXX config I2C_PNX tristate "I2C bus support for Philips PNX targets" - depends on ARCH_PNX4008 && I2C + depends on ARCH_PNX4008 help This driver supports the Philips IP3204 I2C IP block master and/or slave controller diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 290b5401835..14d1432f698 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -10,7 +10,9 @@ obj-$(CONFIG_I2C_AMD756_S4882) += i2c-amd756-s4882.o obj-$(CONFIG_I2C_AMD8111) += i2c-amd8111.o obj-$(CONFIG_I2C_AT91) += i2c-at91.o obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o +obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o obj-$(CONFIG_I2C_ELEKTOR) += i2c-elektor.o +obj-$(CONFIG_I2C_GPIO) += i2c-gpio.o obj-$(CONFIG_I2C_HYDRA) += i2c-hydra.o obj-$(CONFIG_I2C_I801) += i2c-i801.o obj-$(CONFIG_I2C_I810) += i2c-i810.o @@ -37,10 +39,12 @@ obj-$(CONFIG_I2C_RPXLITE) += i2c-rpx.o obj-$(CONFIG_I2C_S3C2410) += i2c-s3c2410.o obj-$(CONFIG_I2C_SAVAGE4) += i2c-savage4.o obj-$(CONFIG_I2C_SIBYTE) += i2c-sibyte.o +obj-$(CONFIG_I2C_SIMTEC) += i2c-simtec.o obj-$(CONFIG_I2C_SIS5595) += i2c-sis5595.o obj-$(CONFIG_I2C_SIS630) += i2c-sis630.o obj-$(CONFIG_I2C_SIS96X) += i2c-sis96x.o obj-$(CONFIG_I2C_STUB) += i2c-stub.o +obj-$(CONFIG_I2C_TINY_USB) += i2c-tiny-usb.o obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o obj-$(CONFIG_I2C_ACORN) += i2c-acorn.o obj-$(CONFIG_I2C_VIA) += i2c-via.o diff --git a/drivers/i2c/busses/i2c-ali1535.c b/drivers/i2c/busses/i2c-ali1535.c index 1e277ba5a9f..f14372ac2fc 100644 --- a/drivers/i2c/busses/i2c-ali1535.c +++ b/drivers/i2c/busses/i2c-ali1535.c @@ -497,7 +497,7 @@ static int __devinit ali1535_probe(struct pci_dev *dev, const struct pci_device_ /* set up the sysfs linkage to our parent device */ ali1535_adapter.dev.parent = &dev->dev; - snprintf(ali1535_adapter.name, I2C_NAME_SIZE, + snprintf(ali1535_adapter.name, sizeof(ali1535_adapter.name), "SMBus ALI1535 adapter at %04x", ali1535_smba); return i2c_add_adapter(&ali1535_adapter); } diff --git a/drivers/i2c/busses/i2c-ali15x3.c b/drivers/i2c/busses/i2c-ali15x3.c index e47fe01bf42..93bf87d7096 100644 --- a/drivers/i2c/busses/i2c-ali15x3.c +++ b/drivers/i2c/busses/i2c-ali15x3.c @@ -492,7 +492,7 @@ static int __devinit ali15x3_probe(struct pci_dev *dev, const struct pci_device_ /* set up the sysfs linkage to our parent device */ ali15x3_adapter.dev.parent = &dev->dev; - snprintf(ali15x3_adapter.name, I2C_NAME_SIZE, + snprintf(ali15x3_adapter.name, sizeof(ali15x3_adapter.name), "SMBus ALI15X3 adapter at %04x", ali15x3_smba); return i2c_add_adapter(&ali15x3_adapter); } diff --git a/drivers/i2c/busses/i2c-amd8111.c b/drivers/i2c/busses/i2c-amd8111.c index 0c70f829334..c9fca7b4926 100644 --- a/drivers/i2c/busses/i2c-amd8111.c +++ b/drivers/i2c/busses/i2c-amd8111.c @@ -365,7 +365,7 @@ static int __devinit amd8111_probe(struct pci_dev *dev, } smbus->adapter.owner = THIS_MODULE; - snprintf(smbus->adapter.name, I2C_NAME_SIZE, + snprintf(smbus->adapter.name, sizeof(smbus->adapter.name), "SMBus2 AMD8111 adapter at %04x", smbus->base); smbus->adapter.id = I2C_HW_SMBUS_AMD8111; smbus->adapter.class = I2C_CLASS_HWMON; diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c new file mode 100644 index 00000000000..6311039dfe6 --- /dev/null +++ b/drivers/i2c/busses/i2c-bfin-twi.c @@ -0,0 +1,644 @@ +/* + * drivers/i2c/busses/i2c-bfin-twi.c + * + * Description: Driver for Blackfin Two Wire Interface + * + * Author: sonicz <sonic.zhang@analog.com> + * + * Copyright (c) 2005-2007 Analog Devices, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/i2c.h> +#include <linux/mm.h> +#include <linux/timer.h> +#include <linux/spinlock.h> +#include <linux/completion.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> + +#include <asm/blackfin.h> +#include <asm/irq.h> + +#define POLL_TIMEOUT (2 * HZ) + +/* SMBus mode*/ +#define TWI_I2C_MODE_STANDARD 0x01 +#define TWI_I2C_MODE_STANDARDSUB 0x02 +#define TWI_I2C_MODE_COMBINED 0x04 + +struct bfin_twi_iface { + struct mutex twi_lock; + int irq; + spinlock_t lock; + char read_write; + u8 command; + u8 *transPtr; + int readNum; + int writeNum; + int cur_mode; + int manual_stop; + int result; + int timeout_count; + struct timer_list timeout_timer; + struct i2c_adapter adap; + struct completion complete; +}; + +static struct bfin_twi_iface twi_iface; + +static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface) +{ + unsigned short twi_int_status = bfin_read_TWI_INT_STAT(); + unsigned short mast_stat = bfin_read_TWI_MASTER_STAT(); + + if (twi_int_status & XMTSERV) { + /* Transmit next data */ + if (iface->writeNum > 0) { + bfin_write_TWI_XMT_DATA8(*(iface->transPtr++)); + iface->writeNum--; + } + /* start receive immediately after complete sending in + * combine mode. + */ + else if (iface->cur_mode == TWI_I2C_MODE_COMBINED) { + bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() + | MDIR | RSTART); + } else if (iface->manual_stop) + bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() + | STOP); + SSYNC(); + /* Clear status */ + bfin_write_TWI_INT_STAT(XMTSERV); + SSYNC(); + } + if (twi_int_status & RCVSERV) { + if (iface->readNum > 0) { + /* Receive next data */ + *(iface->transPtr) = bfin_read_TWI_RCV_DATA8(); + if (iface->cur_mode == TWI_I2C_MODE_COMBINED) { + /* Change combine mode into sub mode after + * read first data. + */ + iface->cur_mode = TWI_I2C_MODE_STANDARDSUB; + /* Get read number from first byte in block + * combine mode. + */ + if (iface->readNum == 1 && iface->manual_stop) + iface->readNum = *iface->transPtr + 1; + } + iface->transPtr++; + iface->readNum--; + } else if (iface->manual_stop) { + bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() + | STOP); + SSYNC(); + } + /* Clear interrupt source */ + bfin_write_TWI_INT_STAT(RCVSERV); + SSYNC(); + } + if (twi_int_status & MERR) { + bfin_write_TWI_INT_STAT(MERR); + bfin_write_TWI_INT_MASK(0); + bfin_write_TWI_MASTER_STAT(0x3e); + bfin_write_TWI_MASTER_CTL(0); + SSYNC(); + iface->result = -1; + /* if both err and complete int stats are set, return proper + * results. + */ + if (twi_int_status & MCOMP) { + bfin_write_TWI_INT_STAT(MCOMP); + bfin_write_TWI_INT_MASK(0); + bfin_write_TWI_MASTER_CTL(0); + SSYNC(); + /* If it is a quick transfer, only address bug no data, + * not an err, return 1. + */ + if (iface->writeNum == 0 && (mast_stat & BUFRDERR)) + iface->result = 1; + /* If address not acknowledged return -1, + * else return 0. + */ + else if (!(mast_stat & ANAK)) + iface->result = 0; + } + complete(&iface->complete); + return; + } + if (twi_int_status & MCOMP) { + bfin_write_TWI_INT_STAT(MCOMP); + SSYNC(); + if (iface->cur_mode == TWI_I2C_MODE_COMBINED) { + if (iface->readNum == 0) { + /* set the read number to 1 and ask for manual + * stop in block combine mode + */ + iface->readNum = 1; + iface->manual_stop = 1; + bfin_write_TWI_MASTER_CTL( + bfin_read_TWI_MASTER_CTL() + | (0xff << 6)); + } else { + /* set the readd number in other + * combine mode. + */ + bfin_write_TWI_MASTER_CTL( + (bfin_read_TWI_MASTER_CTL() & + (~(0xff << 6))) | + ( iface->readNum << 6)); + } + /* remove restart bit and enable master receive */ + bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() & + ~RSTART); + bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() | + MEN | MDIR); + SSYNC(); + } else { + iface->result = 1; + bfin_write_TWI_INT_MASK(0); + bfin_write_TWI_MASTER_CTL(0); + SSYNC(); + complete(&iface->complete); + } + } +} + +/* Interrupt handler */ +static irqreturn_t bfin_twi_interrupt_entry(int irq, void *dev_id) +{ + struct bfin_twi_iface *iface = dev_id; + unsigned long flags; + + spin_lock_irqsave(&iface->lock, flags); + del_timer(&iface->timeout_timer); + bfin_twi_handle_interrupt(iface); + spin_unlock_irqrestore(&iface->lock, flags); + return IRQ_HANDLED; +} + +static void bfin_twi_timeout(unsigned long data) +{ + struct bfin_twi_iface *iface = (struct bfin_twi_iface *)data; + unsigned long flags; + + spin_lock_irqsave(&iface->lock, flags); + bfin_twi_handle_interrupt(iface); + if (iface->result == 0) { + iface->timeout_count--; + if (iface->timeout_count > 0) { + iface->timeout_timer.expires = jiffies + POLL_TIMEOUT; + add_timer(&iface->timeout_timer); + } else { + iface->result = -1; + complete(&iface->complete); + } + } + spin_unlock_irqrestore(&iface->lock, flags); +} + +/* + * Generic i2c master transfer entrypoint + */ +static int bfin_twi_master_xfer(struct i2c_adapter *adap, + struct i2c_msg *msgs, int num) +{ + struct bfin_twi_iface *iface = adap->algo_data; + struct i2c_msg *pmsg; + int i, ret; + int rc = 0; + + if (!(bfin_read_TWI_CONTROL() & TWI_ENA)) + return -ENXIO; + + mutex_lock(&iface->twi_lock); + + while (bfin_read_TWI_MASTER_STAT() & BUSBUSY) { + mutex_unlock(&iface->twi_lock); + yield(); + mutex_lock(&iface->twi_lock); + } + + ret = 0; + for (i = 0; rc >= 0 && i < num; i++) { + pmsg = &msgs[i]; + if (pmsg->flags & I2C_M_TEN) { + dev_err(&(adap->dev), "i2c-bfin-twi: 10 bits addr " + "not supported !\n"); + rc = -EINVAL; + break; + } + + iface->cur_mode = TWI_I2C_MODE_STANDARD; + iface->manual_stop = 0; + iface->transPtr = pmsg->buf; + iface->writeNum = iface->readNum = pmsg->len; + iface->result = 0; + iface->timeout_count = 10; + /* Set Transmit device address */ + bfin_write_TWI_MASTER_ADDR(pmsg->addr); + + /* FIFO Initiation. Data in FIFO should be + * discarded before start a new operation. + */ + bfin_write_TWI_FIFO_CTL(0x3); + SSYNC(); + bfin_write_TWI_FIFO_CTL(0); + SSYNC(); + + if (pmsg->flags & I2C_M_RD) + iface->read_write = I2C_SMBUS_READ; + else { + iface->read_write = I2C_SMBUS_WRITE; + /* Transmit first data */ + if (iface->writeNum > 0) { + bfin_write_TWI_XMT_DATA8(*(iface->transPtr++)); + iface->writeNum--; + SSYNC(); + } + } + + /* clear int stat */ + bfin_write_TWI_INT_STAT(MERR|MCOMP|XMTSERV|RCVSERV); + + /* Interrupt mask . Enable XMT, RCV interrupt */ + bfin_write_TWI_INT_MASK(MCOMP | MERR | + ((iface->read_write == I2C_SMBUS_READ)? + RCVSERV : XMTSERV)); + SSYNC(); + + if (pmsg->len > 0 && pmsg->len <= 255) + bfin_write_TWI_MASTER_CTL(pmsg->len << 6); + else if (pmsg->len > 255) { + bfin_write_TWI_MASTER_CTL(0xff << 6); + iface->manual_stop = 1; + } else + break; + + iface->timeout_timer.expires = jiffies + POLL_TIMEOUT; + add_timer(&iface->timeout_timer); + + /* Master enable */ + bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() | MEN | + ((iface->read_write == I2C_SMBUS_READ) ? MDIR : 0) | + ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ>100) ? FAST : 0)); + SSYNC(); + + wait_for_completion(&iface->complete); + + rc = iface->result; + if (rc == 1) + ret++; + else if (rc == -1) + break; + } + + /* Release mutex */ + mutex_unlock(&iface->twi_lock); + + return ret; +} + +/* + * SMBus type transfer entrypoint + */ + +int bfin_twi_smbus_xfer(struct i2c_adapter *adap, u16 addr, + unsigned short flags, char read_write, + u8 command, int size, union i2c_smbus_data *data) +{ + struct bfin_twi_iface *iface = adap->algo_data; + int rc = 0; + + if (!(bfin_read_TWI_CONTROL() & TWI_ENA)) + return -ENXIO; + + mutex_lock(&iface->twi_lock); + + while (bfin_read_TWI_MASTER_STAT() & BUSBUSY) { + mutex_unlock(&iface->twi_lock); + yield(); + mutex_lock(&iface->twi_lock); + } + + iface->writeNum = 0; + iface->readNum = 0; + + /* Prepare datas & select mode */ + switch (size) { + case I2C_SMBUS_QUICK: + iface->transPtr = NULL; + iface->cur_mode = TWI_I2C_MODE_STANDARD; + break; + case I2C_SMBUS_BYTE: + if (data == NULL) + iface->transPtr = NULL; + else { + if (read_write == I2C_SMBUS_READ) + iface->readNum = 1; + else + iface->writeNum = 1; + iface->transPtr = &data->byte; + } + iface->cur_mode = TWI_I2C_MODE_STANDARD; + break; + case I2C_SMBUS_BYTE_DATA: + if (read_write == I2C_SMBUS_READ) { + iface->readNum = 1; + iface->cur_mode = TWI_I2C_MODE_COMBINED; + } else { + iface->writeNum = 1; + iface->cur_mode = TWI_I2C_MODE_STANDARDSUB; + } + iface->transPtr = &data->byte; + break; + case I2C_SMBUS_WORD_DATA: + if (read_write == I2C_SMBUS_READ) { + iface->readNum = 2; + iface->cur_mode = TWI_I2C_MODE_COMBINED; + } else { + iface->writeNum = 2; + iface->cur_mode = TWI_I2C_MODE_STANDARDSUB; + } + iface->transPtr = (u8 *)&data->word; + break; + case I2C_SMBUS_PROC_CALL: + iface->writeNum = 2; + iface->readNum = 2; + iface->cur_mode = TWI_I2C_MODE_COMBINED; + iface->transPtr = (u8 *)&data->word; + break; + case I2C_SMBUS_BLOCK_DATA: + if (read_write == I2C_SMBUS_READ) { + iface->readNum = 0; + iface->cur_mode = TWI_I2C_MODE_COMBINED; + } else { + iface->writeNum = data->block[0] + 1; + iface->cur_mode = TWI_I2C_MODE_STANDARDSUB; + } + iface->transPtr = data->block; + break; + default: + return -1; + } + + iface->result = 0; + iface->manual_stop = 0; + iface->read_write = read_write; + iface->command = command; + iface->timeout_count = 10; + + /* FIFO Initiation. Data in FIFO should be discarded before + * start a new operation. + */ + bfin_write_TWI_FIFO_CTL(0x3); + SSYNC(); + bfin_write_TWI_FIFO_CTL(0); + + /* clear int stat */ + bfin_write_TWI_INT_STAT(MERR|MCOMP|XMTSERV|RCVSERV); + + /* Set Transmit device address */ + bfin_write_TWI_MASTER_ADDR(addr); + SSYNC(); + + iface->timeout_timer.expires = jiffies + POLL_TIMEOUT; + add_timer(&iface->timeout_timer); + + switch (iface->cur_mode) { + case TWI_I2C_MODE_STANDARDSUB: + bfin_write_TWI_XMT_DATA8(iface->command); + bfin_write_TWI_INT_MASK(MCOMP | MERR | + ((iface->read_write == I2C_SMBUS_READ) ? + RCVSERV : XMTSERV)); + SSYNC(); + + if (iface->writeNum + 1 <= 255) + bfin_write_TWI_MASTER_CTL((iface->writeNum + 1) << 6); + else { + bfin_write_TWI_MASTER_CTL(0xff << 6); + iface->manual_stop = 1; + } + /* Master enable */ + bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() | MEN | + ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ>100) ? FAST : 0)); + break; + case TWI_I2C_MODE_COMBINED: + bfin_write_TWI_XMT_DATA8(iface->command); + bfin_write_TWI_INT_MASK(MCOMP | MERR | RCVSERV | XMTSERV); + SSYNC(); + + if (iface->writeNum > 0) + bfin_write_TWI_MASTER_CTL((iface->writeNum + 1) << 6); + else + bfin_write_TWI_MASTER_CTL(0x1 << 6); + /* Master enable */ + bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() | MEN | + ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ>100) ? FAST : 0)); + break; + default: + bfin_write_TWI_MASTER_CTL(0); + if (size != I2C_SMBUS_QUICK) { + /* Don't access xmit data register when this is a + * read operation. + */ + if (iface->read_write != I2C_SMBUS_READ) { + if (iface->writeNum > 0) { + bfin_write_TWI_XMT_DATA8(*(iface->transPtr++)); + if (iface->writeNum <= 255) + bfin_write_TWI_MASTER_CTL(iface->writeNum << 6); + else { + bfin_write_TWI_MASTER_CTL(0xff << 6); + iface->manual_stop = 1; + } + iface->writeNum--; + } else { + bfin_write_TWI_XMT_DATA8(iface->command); + bfin_write_TWI_MASTER_CTL(1 << 6); + } + } else { + if (iface->readNum > 0 && iface->readNum <= 255) + bfin_write_TWI_MASTER_CTL(iface->readNum << 6); + else if (iface->readNum > 255) { + bfin_write_TWI_MASTER_CTL(0xff << 6); + iface->manual_stop = 1; + } else { + del_timer(&iface->timeout_timer); + break; + } + } + } + bfin_write_TWI_INT_MASK(MCOMP | MERR | + ((iface->read_write == I2C_SMBUS_READ) ? + RCVSERV : XMTSERV)); + SSYNC(); + + /* Master enable */ + bfin_write_TWI_MASTER_CTL(bfin_read_TWI_MASTER_CTL() | MEN | + ((iface->read_write == I2C_SMBUS_READ) ? MDIR : 0) | + ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ > 100) ? FAST : 0)); + break; + } + SSYNC(); + + wait_for_completion(&iface->complete); + + rc = (iface->result >= 0) ? 0 : -1; + + /* Release mutex */ + mutex_unlock(&iface->twi_lock); + + return rc; +} + +/* + * Return what the adapter supports + */ +static u32 bfin_twi_functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | + I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | + I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_PROC_CALL | + I2C_FUNC_I2C; +} + + +static struct i2c_algorithm bfin_twi_algorithm = { + .master_xfer = bfin_twi_master_xfer, + .smbus_xfer = bfin_twi_smbus_xfer, + .functionality = bfin_twi_functionality, +}; + + +static int i2c_bfin_twi_suspend(struct platform_device *dev, pm_message_t state) +{ +/* struct bfin_twi_iface *iface = platform_get_drvdata(dev);*/ + + /* Disable TWI */ + bfin_write_TWI_CONTROL(bfin_read_TWI_CONTROL() & ~TWI_ENA); + SSYNC(); + + return 0; +} + +static int i2c_bfin_twi_resume(struct platform_device *dev) +{ +/* struct bfin_twi_iface *iface = platform_get_drvdata(dev);*/ + + /* Enable TWI */ + bfin_write_TWI_CONTROL(bfin_read_TWI_CONTROL() | TWI_ENA); + SSYNC(); + + return 0; +} + +static int i2c_bfin_twi_probe(struct platform_device *dev) +{ + struct bfin_twi_iface *iface = &twi_iface; + struct i2c_adapter *p_adap; + int rc; + + mutex_init(&(iface->twi_lock)); + spin_lock_init(&(iface->lock)); + init_completion(&(iface->complete)); + iface->irq = IRQ_TWI; + + init_timer(&(iface->timeout_timer)); + iface->timeout_timer.function = bfin_twi_timeout; + iface->timeout_timer.data = (unsigned long)iface; + + p_adap = &iface->adap; + p_adap->id = I2C_HW_BLACKFIN; + strlcpy(p_adap->name, dev->name, sizeof(p_adap->name)); + p_adap->algo = &bfin_twi_algorithm; + p_adap->algo_data = iface; + p_adap->class = I2C_CLASS_ALL; + p_adap->dev.parent = &dev->dev; + + rc = request_irq(iface->irq, bfin_twi_interrupt_entry, + IRQF_DISABLED, dev->name, iface); + if (rc) { + dev_err(&(p_adap->dev), "i2c-bfin-twi: can't get IRQ %d !\n", + iface->irq); + return -ENODEV; + } + + /* Set TWI internal clock as 10MHz */ + bfin_write_TWI_CONTROL(((get_sclk() / 1024 / 1024 + 5) / 10) & 0x7F); + + /* Set Twi interface clock as specified */ + bfin_write_TWI_CLKDIV((( 5*1024 / CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ ) + << 8) | (( 5*1024 / CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ ) + & 0xFF)); + + /* Enable TWI */ + bfin_write_TWI_CONTROL(bfin_read_TWI_CONTROL() | TWI_ENA); + SSYNC(); + + rc = i2c_add_adapter(p_adap); + if (rc < 0) + free_irq(iface->irq, iface); + else + platform_set_drvdata(dev, iface); + + return rc; +} + +static int i2c_bfin_twi_remove(struct platform_device *pdev) +{ + struct bfin_twi_iface *iface = platform_get_drvdata(pdev); + + platform_set_drvdata(pdev, NULL); + + i2c_del_adapter(&(iface->adap)); + free_irq(iface->irq, iface); + + return 0; +} + +static struct platform_driver i2c_bfin_twi_driver = { + .probe = i2c_bfin_twi_probe, + .remove = i2c_bfin_twi_remove, + .suspend = i2c_bfin_twi_suspend, + .resume = i2c_bfin_twi_resume, + .driver = { + .name = "i2c-bfin-twi", + .owner = THIS_MODULE, + }, +}; + +static int __init i2c_bfin_twi_init(void) +{ + pr_info("I2C: Blackfin I2C TWI driver\n"); + + return platform_driver_register(&i2c_bfin_twi_driver); +} + +static void __exit i2c_bfin_twi_exit(void) +{ + platform_driver_unregister(&i2c_bfin_twi_driver); +} + +MODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>"); +MODULE_DESCRIPTION("I2C-Bus adapter routines for Blackfin TWI"); +MODULE_LICENSE("GPL"); + +module_init(i2c_bfin_twi_init); +module_exit(i2c_bfin_twi_exit); diff --git a/drivers/i2c/busses/i2c-elektor.c b/drivers/i2c/busses/i2c-elektor.c index 83496746481..804f0a551c0 100644 --- a/drivers/i2c/busses/i2c-elektor.c +++ b/drivers/i2c/busses/i2c-elektor.c @@ -35,6 +35,7 @@ #include <linux/pci.h> #include <linux/wait.h> +#include <linux/isa.h> #include <linux/i2c.h> #include <linux/i2c-algo-pcf.h> @@ -207,7 +208,7 @@ static struct i2c_adapter pcf_isa_ops = { .name = "i2c-elektor", }; -static int __init i2c_pcfisa_init(void) +static int __devinit elektor_match(struct device *dev, unsigned int id) { #ifdef __alpha__ /* check to see we have memory mapped PCF8584 connected to the @@ -222,9 +223,8 @@ static int __init i2c_pcfisa_init(void) /* yeap, we've found cypress, let's check config */ if (!pci_read_config_byte(cy693_dev, 0x47, &config)) { - pr_debug("%s: found cy82c693, config " - "register 0x47 = 0x%02x\n", - pcf_isa_ops.name, config); + dev_dbg(dev, "found cy82c693, config " + "register 0x47 = 0x%02x\n", config); /* UP2000 board has this register set to 0xe1, but the most significant bit as seems can be @@ -244,9 +244,9 @@ static int __init i2c_pcfisa_init(void) 8.25 MHz (PCI/4) clock (this can be read from cypress) */ clock = I2C_PCF_CLK | I2C_PCF_TRNS90; - pr_info("%s: found API UP2000 like " - "board, will probe PCF8584 " - "later\n", pcf_isa_ops.name); + dev_info(dev, "found API UP2000 like " + "board, will probe PCF8584 " + "later\n"); } } pci_dev_put(cy693_dev); @@ -256,22 +256,27 @@ static int __init i2c_pcfisa_init(void) /* sanity checks for mmapped I/O */ if (mmapped && base < 0xc8000) { - printk(KERN_ERR "%s: incorrect base address (%#x) specified " - "for mmapped I/O\n", pcf_isa_ops.name, base); - return -ENODEV; + dev_err(dev, "incorrect base address (%#x) specified " + "for mmapped I/O\n", base); + return 0; } if (base == 0) { base = DEFAULT_BASE; } + return 1; +} +static int __devinit elektor_probe(struct device *dev, unsigned int id) +{ init_waitqueue_head(&pcf_wait); if (pcf_isa_init()) return -ENODEV; + pcf_isa_ops.dev.parent = dev; if (i2c_pcf_add_bus(&pcf_isa_ops) < 0) goto fail; - dev_info(&pcf_isa_ops.dev, "found device at %#x\n", base); + dev_info(dev, "found device at %#x\n", base); return 0; @@ -291,7 +296,7 @@ static int __init i2c_pcfisa_init(void) return -ENODEV; } -static void i2c_pcfisa_exit(void) +static int __devexit elektor_remove(struct device *dev, unsigned int id) { i2c_del_adapter(&pcf_isa_ops); @@ -307,6 +312,28 @@ static void i2c_pcfisa_exit(void) iounmap(base_iomem); release_mem_region(base, 2); } + + return 0; +} + +static struct isa_driver i2c_elektor_driver = { + .match = elektor_match, + .probe = elektor_probe, + .remove = __devexit_p(elektor_remove), + .driver = { + .owner = THIS_MODULE, + .name = "i2c-elektor", + }, +}; + +static int __init i2c_pcfisa_init(void) +{ + return isa_register_driver(&i2c_elektor_driver, 1); +} + +static void __exit i2c_pcfisa_exit(void) +{ + isa_unregister_driver(&i2c_elektor_driver); } MODULE_AUTHOR("Hans Berglund <hb@spacetec.no>"); diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c new file mode 100644 index 00000000000..a7dd54654a9 --- /dev/null +++ b/drivers/i2c/busses/i2c-gpio.c @@ -0,0 +1,215 @@ +/* + * Bitbanging I2C bus driver using the GPIO API + * + * Copyright (C) 2007 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/i2c.h> +#include <linux/i2c-algo-bit.h> +#include <linux/i2c-gpio.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/platform_device.h> + +#include <asm/gpio.h> + +/* Toggle SDA by changing the direction of the pin */ +static void i2c_gpio_setsda_dir(void *data, int state) +{ + struct i2c_gpio_platform_data *pdata = data; + + if (state) + gpio_direction_input(pdata->sda_pin); + else + gpio_direction_output(pdata->sda_pin, 0); +} + +/* + * Toggle SDA by changing the output value of the pin. This is only + * valid for pins configured as open drain (i.e. setting the value + * high effectively turns off the output driver.) + */ +static void i2c_gpio_setsda_val(void *data, int state) +{ + struct i2c_gpio_platform_data *pdata = data; + + gpio_set_value(pdata->sda_pin, state); +} + +/* Toggle SCL by changing the direction of the pin. */ +static void i2c_gpio_setscl_dir(void *data, int state) +{ + struct i2c_gpio_platform_data *pdata = data; + + if (state) + gpio_direction_input(pdata->scl_pin); + else + gpio_direction_output(pdata->scl_pin, 0); +} + +/* + * Toggle SCL by changing the output value of the pin. This is used + * for pins that are configured as open drain and for output-only + * pins. The latter case will break the i2c protocol, but it will + * often work in practice. + */ +static void i2c_gpio_setscl_val(void *data, int state) +{ + struct i2c_gpio_platform_data *pdata = data; + + gpio_set_value(pdata->scl_pin, state); +} + +int i2c_gpio_getsda(void *data) +{ + struct i2c_gpio_platform_data *pdata = data; + + return gpio_get_value(pdata->sda_pin); +} + +int i2c_gpio_getscl(void *data) +{ + struct i2c_gpio_platform_data *pdata = data; + + return gpio_get_value(pdata->scl_pin); +} + +static int __init i2c_gpio_probe(struct platform_device *pdev) +{ + struct i2c_gpio_platform_data *pdata; + struct i2c_algo_bit_data *bit_data; + struct i2c_adapter *adap; + int ret; + + pdata = pdev->dev.platform_data; + if (!pdata) + return -ENXIO; + + ret = -ENOMEM; + adap = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL); + if (!adap) + goto err_alloc_adap; + bit_data = kzalloc(sizeof(struct i2c_algo_bit_data), GFP_KERNEL); + if (!bit_data) + goto err_alloc_bit_data; + + ret = gpio_request(pdata->sda_pin, "sda"); + if (ret) + goto err_request_sda; + ret = gpio_request(pdata->scl_pin, "scl"); + if (ret) + goto err_request_scl; + + if (pdata->sda_is_open_drain) { + gpio_direction_output(pdata->sda_pin, 1); + bit_data->setsda = i2c_gpio_setsda_val; + } else { + gpio_direction_input(pdata->sda_pin); + bit_data->setsda = i2c_gpio_setsda_dir; + } + + if (pdata->scl_is_open_drain || pdata->scl_is_output_only) { + gpio_direction_output(pdata->scl_pin, 1); + bit_data->setscl = i2c_gpio_setscl_val; + } else { + gpio_direction_input(pdata->scl_pin); + bit_data->setscl = i2c_gpio_setscl_dir; + } + + if (!pdata->scl_is_output_only) + bit_data->getscl = i2c_gpio_getscl; + bit_data->getsda = i2c_gpio_getsda; + + if (pdata->udelay) + bit_data->udelay = pdata->udelay; + else if (pdata->scl_is_output_only) + bit_data->udelay = 50; /* 10 kHz */ + else + bit_data->udelay = 5; /* 100 kHz */ + + if (pdata->timeout) + bit_data->timeout = pdata->timeout; + else + bit_data->timeout = HZ / 10; /* 100 ms */ + + bit_data->data = pdata; + + adap->owner = THIS_MODULE; + snprintf(adap->name, sizeof(adap->name), "i2c-gpio%d", pdev->id); + adap->algo_data = bit_data; + adap->dev.parent = &pdev->dev; + + ret = i2c_bit_add_bus(adap); + if (ret) + goto err_add_bus; + + platform_set_drvdata(pdev, adap); + + dev_info(&pdev->dev, "using pins %u (SDA) and %u (SCL%s)\n", + pdata->sda_pin, pdata->scl_pin, + pdata->scl_is_output_only + ? ", no clock stretching" : ""); + + return 0; + +err_add_bus: + gpio_free(pdata->scl_pin); +err_request_scl: + gpio_free(pdata->sda_pin); +err_request_sda: + kfree(bit_data); +err_alloc_bit_data: + kfree(adap); +err_alloc_adap: + return ret; +} + +static int __exit i2c_gpio_remove(struct platform_device *pdev) +{ + struct i2c_gpio_platform_data *pdata; + struct i2c_adapter *adap; + + adap = platform_get_drvdata(pdev); + pdata = pdev->dev.platform_data; + + i2c_del_adapter(adap); + gpio_free(pdata->scl_pin); + gpio_free(pdata->sda_pin); + kfree(adap->algo_data); + kfree(adap); + + return 0; +} + +static struct platform_driver i2c_gpio_driver = { + .driver = { + .name = "i2c-gpio", + .owner = THIS_MODULE, + }, + .remove = __exit_p(i2c_gpio_remove), +}; + +static int __init i2c_gpio_init(void) +{ + int ret; + + ret = platform_driver_probe(&i2c_gpio_driver, i2c_gpio_probe); + if (ret) + printk(KERN_ERR "i2c-gpio: probe failed: %d\n", ret); + + return ret; +} +module_init(i2c_gpio_init); + +static void __exit i2c_gpio_exit(void) +{ + platform_driver_unregister(&i2c_gpio_driver); +} +module_exit(i2c_gpio_exit); + +MODULE_AUTHOR("Haavard Skinnemoen <hskinnemoen@atmel.com>"); +MODULE_DESCRIPTION("Platform-independent bitbanging I2C driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index a320e7d82c1..611b57192c9 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -527,7 +527,7 @@ static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id /* set up the sysfs linkage to our parent device */ i801_adapter.dev.parent = &dev->dev; - snprintf(i801_adapter.name, I2C_NAME_SIZE, + snprintf(i801_adapter.name, sizeof(i801_adapter.name), "SMBus I801 adapter at %04lx", i801_smba); err = i2c_add_adapter(&i801_adapter); if (err) { diff --git a/drivers/i2c/busses/i2c-isa.c b/drivers/i2c/busses/i2c-isa.c index 5f33bc9c1e0..b0e1370075d 100644 --- a/drivers/i2c/busses/i2c-isa.c +++ b/drivers/i2c/busses/i2c-isa.c @@ -41,6 +41,10 @@ #include <linux/platform_device.h> #include <linux/completion.h> +/* Exported by i2c-core for i2c-isa only */ +extern void i2c_adapter_dev_release(struct device *dev); +extern struct class i2c_adapter_class; + static u32 isa_func(struct i2c_adapter *adapter); /* This is the actual algorithm we define */ @@ -64,16 +68,6 @@ static u32 isa_func(struct i2c_adapter *adapter) } -/* Copied from i2c-core */ -static ssize_t show_adapter_name(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct i2c_adapter *adap = dev_to_i2c_adapter(dev); - return sprintf(buf, "%s\n", adap->name); -} -static DEVICE_ATTR(name, S_IRUGO, show_adapter_name, NULL); - - /* We implement an interface which resembles i2c_{add,del}_driver, but for i2c-isa drivers. We don't have to remember and handle lists of drivers and adapters so this is much more simple, of course. */ @@ -139,41 +133,18 @@ static int __init i2c_isa_init(void) isa_adapter.nr = ANY_I2C_ISA_BUS; isa_adapter.dev.parent = &platform_bus; sprintf(isa_adapter.dev.bus_id, "i2c-%d", isa_adapter.nr); - isa_adapter.dev.driver = &i2c_adapter_driver; isa_adapter.dev.release = &i2c_adapter_dev_release; + isa_adapter.dev.class = &i2c_adapter_class; err = device_register(&isa_adapter.dev); if (err) { printk(KERN_ERR "i2c-isa: Failed to register device\n"); goto exit; } - err = device_create_file(&isa_adapter.dev, &dev_attr_name); - if (err) { - printk(KERN_ERR "i2c-isa: Failed to create name file\n"); - goto exit_unregister; - } - - /* Add this adapter to the i2c_adapter class */ - memset(&isa_adapter.class_dev, 0x00, sizeof(struct class_device)); - isa_adapter.class_dev.dev = &isa_adapter.dev; - isa_adapter.class_dev.class = &i2c_adapter_class; - strlcpy(isa_adapter.class_dev.class_id, isa_adapter.dev.bus_id, - BUS_ID_SIZE); - err = class_device_register(&isa_adapter.class_dev); - if (err) { - printk(KERN_ERR "i2c-isa: Failed to register class device\n"); - goto exit_remove_name; - } dev_dbg(&isa_adapter.dev, "%s registered\n", isa_adapter.name); return 0; -exit_remove_name: - device_remove_file(&isa_adapter.dev, &dev_attr_name); -exit_unregister: - init_completion(&isa_adapter.dev_released); /* Needed? */ - device_unregister(&isa_adapter.dev); - wait_for_completion(&isa_adapter.dev_released); exit: return err; } @@ -201,15 +172,11 @@ static void __exit i2c_isa_exit(void) /* Clean up the sysfs representation */ dev_dbg(&isa_adapter.dev, "Unregistering from sysfs\n"); init_completion(&isa_adapter.dev_released); - init_completion(&isa_adapter.class_dev_released); - class_device_unregister(&isa_adapter.class_dev); - device_remove_file(&isa_adapter.dev, &dev_attr_name); device_unregister(&isa_adapter.dev); /* Wait for sysfs to drop all references */ dev_dbg(&isa_adapter.dev, "Waiting for sysfs completion\n"); wait_for_completion(&isa_adapter.dev_released); - wait_for_completion(&isa_adapter.class_dev_released); dev_dbg(&isa_adapter.dev, "%s unregistered\n", isa_adapter.name); } diff --git a/drivers/i2c/busses/i2c-ixp2000.c b/drivers/i2c/busses/i2c-ixp2000.c index efa3ecc5522..6352121a282 100644 --- a/drivers/i2c/busses/i2c-ixp2000.c +++ b/drivers/i2c/busses/i2c-ixp2000.c @@ -118,7 +118,7 @@ static int ixp2000_i2c_probe(struct platform_device *plat_dev) drv_data->adapter.id = I2C_HW_B_IXP2000, strlcpy(drv_data->adapter.name, plat_dev->dev.driver->name, - I2C_NAME_SIZE); + sizeof(drv_data->adapter.name)); drv_data->adapter.algo_data = &drv_data->algo_data, drv_data->adapter.dev.parent = &plat_dev->dev; diff --git a/drivers/i2c/busses/i2c-ixp4xx.c b/drivers/i2c/busses/i2c-ixp4xx.c index 08e89b83984..069ed7f3b39 100644 --- a/drivers/i2c/busses/i2c-ixp4xx.c +++ b/drivers/i2c/busses/i2c-ixp4xx.c @@ -127,7 +127,7 @@ static int ixp4xx_i2c_probe(struct platform_device *plat_dev) drv_data->adapter.id = I2C_HW_B_IXP4XX; drv_data->adapter.class = I2C_CLASS_HWMON; strlcpy(drv_data->adapter.name, plat_dev->dev.driver->name, - I2C_NAME_SIZE); + sizeof(drv_data->adapter.name)); drv_data->adapter.algo_data = &drv_data->algo_data; drv_data->adapter.dev.parent = &plat_dev->dev; diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index a3283b907eb..a55b3335d1b 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -508,7 +508,7 @@ mv64xxx_i2c_probe(struct platform_device *pd) } strlcpy(drv_data->adapter.name, MV64XXX_I2C_CTLR_NAME " adapter", - I2C_NAME_SIZE); + sizeof(drv_data->adapter.name)); init_waitqueue_head(&drv_data->waitq); spin_lock_init(&drv_data->lock); diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c index 1514ec5b77f..3cd0d63e7b5 100644 --- a/drivers/i2c/busses/i2c-nforce2.c +++ b/drivers/i2c/busses/i2c-nforce2.c @@ -33,6 +33,8 @@ nForce4 MCP-04 0034 nForce4 MCP51 0264 nForce4 MCP55 0368 + nForce MCP61 03EB + nForce MCP65 0446 This driver supports the 2 SMBuses that are included in the MCP of the nForce2/3/4/5xx chipsets. @@ -200,6 +202,8 @@ static struct pci_device_id nforce2_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SMBUS) }, + { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_SMBUS) }, { 0 } }; @@ -240,7 +244,7 @@ static int __devinit nforce2_probe_smb (struct pci_dev *dev, int bar, smbus->adapter.algo = &smbus_algorithm; smbus->adapter.algo_data = smbus; smbus->adapter.dev.parent = &dev->dev; - snprintf(smbus->adapter.name, I2C_NAME_SIZE, + snprintf(smbus->adapter.name, sizeof(smbus->adapter.name), "SMBus nForce2 adapter at %04x", smbus->base); error = i2c_add_adapter(&smbus->adapter); diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index bcd8367cede..e471e3bfdc1 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -605,7 +605,8 @@ omap_i2c_probe(struct platform_device *pdev) adap->dev.parent = &pdev->dev; /* i2c device drivers may be active on return from add_adapter() */ - r = i2c_add_adapter(adap); + adap->nr = pdev->id; + r = i2c_add_numbered_adapter(adap); if (r) { dev_err(dev->dev, "failure adding adapter\n"); goto err_free_irq; diff --git a/drivers/i2c/busses/i2c-parport-light.c b/drivers/i2c/busses/i2c-parport-light.c index 4bc42810b9a..49a95e2887b 100644 --- a/drivers/i2c/busses/i2c-parport-light.c +++ b/drivers/i2c/busses/i2c-parport-light.c @@ -1,7 +1,7 @@ /* ------------------------------------------------------------------------ * - * i2c-parport.c I2C bus over parallel port * + * i2c-parport-light.c I2C bus over parallel port * * ------------------------------------------------------------------------ * - Copyright (C) 2003-2004 Jean Delvare <khali@linux-fr.org> + Copyright (C) 2003-2007 Jean Delvare <khali@linux-fr.org> Based on older i2c-velleman.c driver Copyright (C) 1995-2000 Simon G. Vogl @@ -27,6 +27,7 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> +#include <linux/platform_device.h> #include <linux/ioport.h> #include <linux/i2c.h> #include <linux/i2c-algo-bit.h> @@ -34,6 +35,9 @@ #include "i2c-parport.h" #define DEFAULT_BASE 0x378 +#define DRVNAME "i2c-parport-light" + +static struct platform_device *pdev; static u16 base; module_param(base, ushort, 0); @@ -106,7 +110,7 @@ static struct i2c_algo_bit_data parport_algo_data = { .timeout = HZ, }; -/* ----- I2c structure ---------------------------------------------------- */ +/* ----- Driver registration ---------------------------------------------- */ static struct i2c_adapter parport_adapter = { .owner = THIS_MODULE, @@ -116,55 +120,141 @@ static struct i2c_adapter parport_adapter = { .name = "Parallel port adapter (light)", }; -/* ----- Module loading, unloading and information ------------------------ */ +static int __devinit i2c_parport_probe(struct platform_device *pdev) +{ + int err; + struct resource *res; + + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (!request_region(res->start, res->end - res->start + 1, DRVNAME)) + return -EBUSY; + + /* Reset hardware to a sane state (SCL and SDA high) */ + parport_setsda(NULL, 1); + parport_setscl(NULL, 1); + /* Other init if needed (power on...) */ + if (adapter_parm[type].init.val) + line_set(1, &adapter_parm[type].init); + + parport_adapter.dev.parent = &pdev->dev; + err = i2c_bit_add_bus(&parport_adapter); + if (err) { + dev_err(&pdev->dev, "Unable to register with I2C\n"); + goto exit_region; + } + return 0; + +exit_region: + release_region(res->start, res->end - res->start + 1); + return err; +} + +static int __devexit i2c_parport_remove(struct platform_device *pdev) +{ + struct resource *res; + + i2c_del_adapter(&parport_adapter); + + /* Un-init if needed (power off...) */ + if (adapter_parm[type].init.val) + line_set(0, &adapter_parm[type].init); + + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + release_region(res->start, res->end - res->start + 1); + return 0; +} + +static struct platform_driver i2c_parport_driver = { + .driver = { + .owner = THIS_MODULE, + .name = DRVNAME, + }, + .probe = i2c_parport_probe, + .remove = __devexit_p(i2c_parport_remove), +}; + +static int __init i2c_parport_device_add(u16 address) +{ + struct resource res = { + .start = address, + .end = address + 2, + .name = DRVNAME, + .flags = IORESOURCE_IO, + }; + int err; + + pdev = platform_device_alloc(DRVNAME, -1); + if (!pdev) { + err = -ENOMEM; + printk(KERN_ERR DRVNAME ": Device allocation failed\n"); + goto exit; + } + + err = platform_device_add_resources(pdev, &res, 1); + if (err) { + printk(KERN_ERR DRVNAME ": Device resource addition failed " + "(%d)\n", err); + goto exit_device_put; + } + + err = platform_device_add(pdev); + if (err) { + printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n", + err); + goto exit_device_put; + } + + return 0; + +exit_device_put: + platform_device_put(pdev); +exit: + return err; +} static int __init i2c_parport_init(void) { + int err; + if (type < 0) { - printk(KERN_WARNING "i2c-parport: adapter type unspecified\n"); + printk(KERN_ERR DRVNAME ": adapter type unspecified\n"); return -ENODEV; } if (type >= ARRAY_SIZE(adapter_parm)) { - printk(KERN_WARNING "i2c-parport: invalid type (%d)\n", type); + printk(KERN_ERR DRVNAME ": invalid type (%d)\n", type); return -ENODEV; } if (base == 0) { - printk(KERN_INFO "i2c-parport: using default base 0x%x\n", DEFAULT_BASE); + pr_info(DRVNAME ": using default base 0x%x\n", DEFAULT_BASE); base = DEFAULT_BASE; } - if (!request_region(base, 3, "i2c-parport")) - return -ENODEV; - if (!adapter_parm[type].getscl.val) parport_algo_data.getscl = NULL; - /* Reset hardware to a sane state (SCL and SDA high) */ - parport_setsda(NULL, 1); - parport_setscl(NULL, 1); - /* Other init if needed (power on...) */ - if (adapter_parm[type].init.val) - line_set(1, &adapter_parm[type].init); + /* Sets global pdev as a side effect */ + err = i2c_parport_device_add(base); + if (err) + goto exit; - if (i2c_bit_add_bus(&parport_adapter) < 0) { - printk(KERN_ERR "i2c-parport: Unable to register with I2C\n"); - release_region(base, 3); - return -ENODEV; - } + err = platform_driver_register(&i2c_parport_driver); + if (err) + goto exit_device; return 0; + +exit_device: + platform_device_unregister(pdev); +exit: + return err; } static void __exit i2c_parport_exit(void) { - /* Un-init if needed (power off...) */ - if (adapter_parm[type].init.val) - line_set(0, &adapter_parm[type].init); - - i2c_del_adapter(&parport_adapter); - release_region(base, 3); + platform_driver_unregister(&i2c_parport_driver); + platform_device_unregister(pdev); } MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>"); diff --git a/drivers/i2c/busses/i2c-parport.c b/drivers/i2c/busses/i2c-parport.c index 66696a40c7b..8c953707253 100644 --- a/drivers/i2c/busses/i2c-parport.c +++ b/drivers/i2c/busses/i2c-parport.c @@ -1,7 +1,7 @@ /* ------------------------------------------------------------------------ * * i2c-parport.c I2C bus over parallel port * * ------------------------------------------------------------------------ * - Copyright (C) 2003-2004 Jean Delvare <khali@linux-fr.org> + Copyright (C) 2003-2007 Jean Delvare <khali@linux-fr.org> Based on older i2c-philips-par.c driver Copyright (C) 1995-2000 Simon G. Vogl @@ -137,19 +137,12 @@ static struct i2c_algo_bit_data parport_algo_data = { .setscl = parport_setscl, .getsda = parport_getsda, .getscl = parport_getscl, - .udelay = 60, + .udelay = 10, /* ~50 kbps */ .timeout = HZ, }; /* ----- I2c and parallel port call-back functions and structures --------- */ -static struct i2c_adapter parport_adapter = { - .owner = THIS_MODULE, - .class = I2C_CLASS_HWMON, - .id = I2C_HW_B_LP, - .name = "Parallel port adapter", -}; - static void i2c_parport_attach (struct parport *port) { struct i2c_par *adapter; @@ -169,10 +162,17 @@ static void i2c_parport_attach (struct parport *port) } /* Fill the rest of the structure */ - adapter->adapter = parport_adapter; + adapter->adapter.owner = THIS_MODULE; + adapter->adapter.class = I2C_CLASS_HWMON; + adapter->adapter.id = I2C_HW_B_LP; + strlcpy(adapter->adapter.name, "Parallel port adapter", + sizeof(adapter->adapter.name)); adapter->algo_data = parport_algo_data; - if (!adapter_parm[type].getscl.val) + /* Slow down if we can't sense SCL */ + if (!adapter_parm[type].getscl.val) { adapter->algo_data.getscl = NULL; + adapter->algo_data.udelay = 50; /* ~10 kbps */ + } adapter->algo_data.data = port; adapter->adapter.algo_data = &adapter->algo_data; @@ -214,11 +214,12 @@ static void i2c_parport_detach (struct parport *port) for (prev = NULL, adapter = adapter_list; adapter; prev = adapter, adapter = adapter->next) { if (adapter->pdev->port == port) { + i2c_del_adapter(&adapter->adapter); + /* Un-init if needed (power off...) */ if (adapter_parm[type].init.val) line_set(port, 0, &adapter_parm[type].init); - i2c_del_adapter(&adapter->adapter); parport_unregister_device(adapter->pdev); if (prev) prev->next = adapter->next; diff --git a/drivers/i2c/busses/i2c-pasemi.c b/drivers/i2c/busses/i2c-pasemi.c index bf89eeef74e..58e32714afb 100644 --- a/drivers/i2c/busses/i2c-pasemi.c +++ b/drivers/i2c/busses/i2c-pasemi.c @@ -358,7 +358,7 @@ static int __devinit pasemi_smb_probe(struct pci_dev *dev, } smbus->adapter.owner = THIS_MODULE; - snprintf(smbus->adapter.name, I2C_NAME_SIZE, + snprintf(smbus->adapter.name, sizeof(smbus->adapter.name), "PA Semi SMBus adapter at 0x%lx", smbus->base); smbus->adapter.class = I2C_CLASS_HWMON; smbus->adapter.algo = &smbus_algorithm; diff --git a/drivers/i2c/busses/i2c-pca-isa.c b/drivers/i2c/busses/i2c-pca-isa.c index 6b03e0d0a8e..5161aaf9341 100644 --- a/drivers/i2c/busses/i2c-pca-isa.c +++ b/drivers/i2c/busses/i2c-pca-isa.c @@ -27,6 +27,7 @@ #include <linux/interrupt.h> #include <linux/wait.h> +#include <linux/isa.h> #include <linux/i2c.h> #include <linux/i2c-algo-pca.h> @@ -118,27 +119,26 @@ static struct i2c_adapter pca_isa_ops = { .name = "PCA9564 ISA Adapter", }; -static int __init pca_isa_init(void) +static int __devinit pca_isa_probe(struct device *dev, unsigned int id) { - init_waitqueue_head(&pca_wait); - printk(KERN_INFO "i2c-pca-isa: i/o base %#08lx. irq %d\n", base, irq); + dev_info(dev, "i/o base %#08lx. irq %d\n", base, irq); if (!request_region(base, IO_SIZE, "i2c-pca-isa")) { - printk(KERN_ERR "i2c-pca-isa: I/O address %#08lx is in use.\n", base); + dev_err(dev, "I/O address %#08lx is in use\n", base); goto out; } if (irq > -1) { if (request_irq(irq, pca_handler, 0, "i2c-pca-isa", &pca_isa_ops) < 0) { - printk(KERN_ERR "i2c-pca-isa: Request irq%d failed\n", irq); + dev_err(dev, "Request irq%d failed\n", irq); goto out_region; } } if (i2c_pca_add_bus(&pca_isa_ops) < 0) { - printk(KERN_ERR "i2c-pca-isa: Failed to add i2c bus\n"); + dev_err(dev, "Failed to add i2c bus\n"); goto out_irq; } @@ -153,7 +153,7 @@ static int __init pca_isa_init(void) return -ENODEV; } -static void pca_isa_exit(void) +static int __devexit pca_isa_remove(struct device *dev, unsigned int id) { i2c_del_adapter(&pca_isa_ops); @@ -162,6 +162,27 @@ static void pca_isa_exit(void) free_irq(irq, &pca_isa_ops); } release_region(base, IO_SIZE); + + return 0; +} + +static struct isa_driver pca_isa_driver = { + .probe = pca_isa_probe, + .remove = __devexit_p(pca_isa_remove), + .driver = { + .owner = THIS_MODULE, + .name = "i2c-pca-isa", + } +}; + +static int __init pca_isa_init(void) +{ + return isa_register_driver(&pca_isa_driver, 1); +} + +static void __exit pca_isa_exit(void) +{ + isa_unregister_driver(&pca_isa_driver); } MODULE_AUTHOR("Ian Campbell <icampbell@arcom.com>"); diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c index 21b18090408..5a52bf5e3fb 100644 --- a/drivers/i2c/busses/i2c-piix4.c +++ b/drivers/i2c/busses/i2c-piix4.c @@ -428,7 +428,7 @@ static int __devinit piix4_probe(struct pci_dev *dev, /* set up the sysfs linkage to our parent device */ piix4_adapter.dev.parent = &dev->dev; - snprintf(piix4_adapter.name, I2C_NAME_SIZE, + snprintf(piix4_adapter.name, sizeof(piix4_adapter.name), "SMBus PIIX4 adapter at %04x", piix4_smba); if ((retval = i2c_add_adapter(&piix4_adapter))) { diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index 14e83d0aac8..c059b27fa88 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -539,6 +539,18 @@ static inline void i2c_pxa_start_message(struct pxa_i2c *i2c) writel(icr | ICR_START | ICR_TB, _ICR(i2c)); } +static inline void i2c_pxa_stop_message(struct pxa_i2c *i2c) +{ + u32 icr; + + /* + * Clear the STOP and ACK flags + */ + icr = readl(_ICR(i2c)); + icr &= ~(ICR_STOP | ICR_ACKNAK); + writel(icr, _IRC(i2c)); +} + /* * We are protected by the adapter bus mutex. */ @@ -581,6 +593,7 @@ static int i2c_pxa_do_xfer(struct pxa_i2c *i2c, struct i2c_msg *msg, int num) * The rest of the processing occurs in the interrupt handler. */ timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5); + i2c_pxa_stop_message(i2c); /* * We place the return code in i2c->msg_idx. @@ -825,7 +838,7 @@ static const struct i2c_algorithm i2c_pxa_algorithm = { }; static struct pxa_i2c i2c_pxa = { - .lock = SPIN_LOCK_UNLOCKED, + .lock = __SPIN_LOCK_UNLOCKED(i2c_pxa.lock), .adap = { .owner = THIS_MODULE, .algo = &i2c_pxa_algorithm, diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 556f244aae7..e68a96f589f 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -61,6 +61,8 @@ struct s3c24xx_i2c { unsigned int msg_idx; unsigned int msg_ptr; + unsigned int tx_setup; + enum s3c24xx_i2c_state state; void __iomem *regs; @@ -199,8 +201,11 @@ static void s3c24xx_i2c_message_start(struct s3c24xx_i2c *i2c, dev_dbg(i2c->dev, "START: %08lx to IICSTAT, %02x to DS\n", stat, addr); writeb(addr, i2c->regs + S3C2410_IICDS); - // delay a bit and reset iiccon before setting start (per samsung) - udelay(1); + /* delay here to ensure the data byte has gotten onto the bus + * before the transaction is started */ + + ndelay(i2c->tx_setup); + dev_dbg(i2c->dev, "iiccon, %08lx\n", iiccon); writel(iiccon, i2c->regs + S3C2410_IICCON); @@ -322,7 +327,15 @@ static int i2s_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat) if (!is_msgend(i2c)) { byte = i2c->msg->buf[i2c->msg_ptr++]; writeb(byte, i2c->regs + S3C2410_IICDS); - + + /* delay after writing the byte to allow the + * data setup time on the bus, as writing the + * data to the register causes the first bit + * to appear on SDA, and SCL will change as + * soon as the interrupt is acknowledged */ + + ndelay(i2c->tx_setup); + } else if (!is_lastmsg(i2c)) { /* we need to go to the next i2c message */ @@ -570,9 +583,10 @@ static const struct i2c_algorithm s3c24xx_i2c_algorithm = { }; static struct s3c24xx_i2c s3c24xx_i2c = { - .lock = SPIN_LOCK_UNLOCKED, - .wait = __WAIT_QUEUE_HEAD_INITIALIZER(s3c24xx_i2c.wait), - .adap = { + .lock = __SPIN_LOCK_UNLOCKED(s3c24xx_i2c.lock), + .wait = __WAIT_QUEUE_HEAD_INITIALIZER(s3c24xx_i2c.wait), + .tx_setup = 50, + .adap = { .name = "s3c2410-i2c", .owner = THIS_MODULE, .algo = &s3c24xx_i2c_algorithm, @@ -731,26 +745,6 @@ static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c) return 0; } -static void s3c24xx_i2c_free(struct s3c24xx_i2c *i2c) -{ - if (i2c->clk != NULL && !IS_ERR(i2c->clk)) { - clk_disable(i2c->clk); - clk_put(i2c->clk); - i2c->clk = NULL; - } - - if (i2c->regs != NULL) { - iounmap(i2c->regs); - i2c->regs = NULL; - } - - if (i2c->ioarea != NULL) { - release_resource(i2c->ioarea); - kfree(i2c->ioarea); - i2c->ioarea = NULL; - } -} - /* s3c24xx_i2c_probe * * called by the bus driver when a suitable device is found @@ -769,7 +763,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) if (IS_ERR(i2c->clk)) { dev_err(&pdev->dev, "cannot get clock\n"); ret = -ENOENT; - goto out; + goto err_noclk; } dev_dbg(&pdev->dev, "clock source %p\n", i2c->clk); @@ -782,7 +776,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) if (res == NULL) { dev_err(&pdev->dev, "cannot find IO resource\n"); ret = -ENOENT; - goto out; + goto err_clk; } i2c->ioarea = request_mem_region(res->start, (res->end-res->start)+1, @@ -791,7 +785,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) if (i2c->ioarea == NULL) { dev_err(&pdev->dev, "cannot request IO\n"); ret = -ENXIO; - goto out; + goto err_clk; } i2c->regs = ioremap(res->start, (res->end-res->start)+1); @@ -799,7 +793,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) if (i2c->regs == NULL) { dev_err(&pdev->dev, "cannot map IO\n"); ret = -ENXIO; - goto out; + goto err_ioarea; } dev_dbg(&pdev->dev, "registers %p (%p, %p)\n", i2c->regs, i2c->ioarea, res); @@ -813,7 +807,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) ret = s3c24xx_i2c_init(i2c); if (ret != 0) - goto out; + goto err_iomap; /* find the IRQ for this unit (note, this relies on the init call to * ensure no current IRQs pending @@ -823,7 +817,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) if (res == NULL) { dev_err(&pdev->dev, "cannot find IRQ\n"); ret = -ENOENT; - goto out; + goto err_iomap; } ret = request_irq(res->start, s3c24xx_i2c_irq, IRQF_DISABLED, @@ -831,7 +825,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) if (ret != 0) { dev_err(&pdev->dev, "cannot claim IRQ\n"); - goto out; + goto err_iomap; } i2c->irq = res; @@ -841,17 +835,29 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) ret = i2c_add_adapter(&i2c->adap); if (ret < 0) { dev_err(&pdev->dev, "failed to add bus to i2c core\n"); - goto out; + goto err_irq; } platform_set_drvdata(pdev, i2c); dev_info(&pdev->dev, "%s: S3C I2C adapter\n", i2c->adap.dev.bus_id); + return 0; - out: - if (ret < 0) - s3c24xx_i2c_free(i2c); + err_irq: + free_irq(i2c->irq->start, i2c); + + err_iomap: + iounmap(i2c->regs); + err_ioarea: + release_resource(i2c->ioarea); + kfree(i2c->ioarea); + + err_clk: + clk_disable(i2c->clk); + clk_put(i2c->clk); + + err_noclk: return ret; } @@ -863,11 +869,17 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) static int s3c24xx_i2c_remove(struct platform_device *pdev) { struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev); - - if (i2c != NULL) { - s3c24xx_i2c_free(i2c); - platform_set_drvdata(pdev, NULL); - } + + i2c_del_adapter(&i2c->adap); + free_irq(i2c->irq->start, i2c); + + clk_disable(i2c->clk); + clk_put(i2c->clk); + + iounmap(i2c->regs); + + release_resource(i2c->ioarea); + kfree(i2c->ioarea); return 0; } diff --git a/drivers/i2c/busses/i2c-simtec.c b/drivers/i2c/busses/i2c-simtec.c new file mode 100644 index 00000000000..10af8d31e12 --- /dev/null +++ b/drivers/i2c/busses/i2c-simtec.c @@ -0,0 +1,186 @@ +/* + * Copyright (C) 2005 Simtec Electronics + * Ben Dooks <ben@simtec.co.uk> + * + * Simtec Generic I2C Controller + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/platform_device.h> + +#include <linux/i2c.h> +#include <linux/i2c-algo-bit.h> + +#include <asm/io.h> + +struct simtec_i2c_data { + struct resource *ioarea; + void __iomem *reg; + struct i2c_adapter adap; + struct i2c_algo_bit_data bit; +}; + +#define CMD_SET_SDA (1<<2) +#define CMD_SET_SCL (1<<3) + +#define STATE_SDA (1<<0) +#define STATE_SCL (1<<1) + +/* i2c bit-bus functions */ + +static void simtec_i2c_setsda(void *pw, int state) +{ + struct simtec_i2c_data *pd = pw; + writeb(CMD_SET_SDA | (state ? STATE_SDA : 0), pd->reg); +} + +static void simtec_i2c_setscl(void *pw, int state) +{ + struct simtec_i2c_data *pd = pw; + writeb(CMD_SET_SCL | (state ? STATE_SCL : 0), pd->reg); +} + +static int simtec_i2c_getsda(void *pw) +{ + struct simtec_i2c_data *pd = pw; + return readb(pd->reg) & STATE_SDA ? 1 : 0; +} + +static int simtec_i2c_getscl(void *pw) +{ + struct simtec_i2c_data *pd = pw; + return readb(pd->reg) & STATE_SCL ? 1 : 0; +} + +/* device registration */ + +static int simtec_i2c_probe(struct platform_device *dev) +{ + struct simtec_i2c_data *pd; + struct resource *res; + int size; + int ret; + + pd = kzalloc(sizeof(struct simtec_i2c_data), GFP_KERNEL); + if (pd == NULL) { + dev_err(&dev->dev, "cannot allocate private data\n"); + return -ENOMEM; + } + + platform_set_drvdata(dev, pd); + + res = platform_get_resource(dev, IORESOURCE_MEM, 0); + if (res == NULL) { + dev_err(&dev->dev, "cannot find IO resource\n"); + ret = -ENOENT; + goto err; + } + + size = (res->end-res->start)+1; + + pd->ioarea = request_mem_region(res->start, size, dev->name); + if (pd->ioarea == NULL) { + dev_err(&dev->dev, "cannot request IO\n"); + ret = -ENXIO; + goto err; + } + + pd->reg = ioremap(res->start, size); + if (pd->reg == NULL) { + dev_err(&dev->dev, "cannot map IO\n"); + ret = -ENXIO; + goto err_res; + } + + /* setup the private data */ + + pd->adap.owner = THIS_MODULE; + pd->adap.algo_data = &pd->bit; + pd->adap.dev.parent = &dev->dev; + + strlcpy(pd->adap.name, "Simtec I2C", sizeof(pd->adap.name)); + + pd->bit.data = pd; + pd->bit.setsda = simtec_i2c_setsda; + pd->bit.setscl = simtec_i2c_setscl; + pd->bit.getsda = simtec_i2c_getsda; + pd->bit.getscl = simtec_i2c_getscl; + pd->bit.timeout = HZ; + pd->bit.udelay = 20; + + ret = i2c_bit_add_bus(&pd->adap); + if (ret) + goto err_all; + + return 0; + + err_all: + iounmap(pd->reg); + + err_res: + release_resource(pd->ioarea); + kfree(pd->ioarea); + + err: + kfree(pd); + return ret; +} + +static int simtec_i2c_remove(struct platform_device *dev) +{ + struct simtec_i2c_data *pd = platform_get_drvdata(dev); + + i2c_del_adapter(&pd->adap); + + iounmap(pd->reg); + release_resource(pd->ioarea); + kfree(pd->ioarea); + kfree(pd); + + return 0; +} + + +/* device driver */ + +static struct platform_driver simtec_i2c_driver = { + .driver = { + .name = "simtec-i2c", + .owner = THIS_MODULE, + }, + .probe = simtec_i2c_probe, + .remove = simtec_i2c_remove, +}; + +static int __init i2c_adap_simtec_init(void) +{ + return platform_driver_register(&simtec_i2c_driver); +} + +static void __exit i2c_adap_simtec_exit(void) +{ + platform_driver_unregister(&simtec_i2c_driver); +} + +module_init(i2c_adap_simtec_init); +module_exit(i2c_adap_simtec_exit); + +MODULE_DESCRIPTION("Simtec Generic I2C Bus driver"); +MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/i2c/busses/i2c-sis96x.c b/drivers/i2c/busses/i2c-sis96x.c index 4157b0cd604..dc235bb8e24 100644 --- a/drivers/i2c/busses/i2c-sis96x.c +++ b/drivers/i2c/busses/i2c-sis96x.c @@ -300,7 +300,7 @@ static int __devinit sis96x_probe(struct pci_dev *dev, /* set up the sysfs linkage to our parent device */ sis96x_adapter.dev.parent = &dev->dev; - snprintf(sis96x_adapter.name, I2C_NAME_SIZE, + snprintf(sis96x_adapter.name, sizeof(sis96x_adapter.name), "SiS96x SMBus adapter at 0x%04x", sis96x_smbus_base); if ((retval = i2c_add_adapter(&sis96x_adapter))) { diff --git a/drivers/i2c/busses/i2c-tiny-usb.c b/drivers/i2c/busses/i2c-tiny-usb.c new file mode 100644 index 00000000000..907999049d5 --- /dev/null +++ b/drivers/i2c/busses/i2c-tiny-usb.c @@ -0,0 +1,277 @@ +/* + * driver for the i2c-tiny-usb adapter - 1.0 + * http://www.harbaum.org/till/i2c_tiny_usb + * + * Copyright (C) 2006-2007 Till Harbaum (Till@Harbaum.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 Free Software Foundation, version 2. + * + */ + +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/module.h> + +/* include interfaces to usb layer */ +#include <linux/usb.h> + +/* include interface to i2c layer */ +#include <linux/i2c.h> + +/* commands via USB, must match command ids in the firmware */ +#define CMD_ECHO 0 +#define CMD_GET_FUNC 1 +#define CMD_SET_DELAY 2 +#define CMD_GET_STATUS 3 + +#define CMD_I2C_IO 4 +#define CMD_I2C_IO_BEGIN (1<<0) +#define CMD_I2C_IO_END (1<<1) + +/* i2c bit delay, default is 10us -> 100kHz */ +static int delay = 10; +module_param(delay, int, 0); +MODULE_PARM_DESC(delay, "bit delay in microseconds, " + "e.g. 10 for 100kHz (default is 100kHz)"); + +static int usb_read(struct i2c_adapter *adapter, int cmd, + int value, int index, void *data, int len); + +static int usb_write(struct i2c_adapter *adapter, int cmd, + int value, int index, void *data, int len); + +/* ----- begin of i2c layer ---------------------------------------------- */ + +#define STATUS_IDLE 0 +#define STATUS_ADDRESS_ACK 1 +#define STATUS_ADDRESS_NAK 2 + +static int usb_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num) +{ + unsigned char status; + struct i2c_msg *pmsg; + int i; + + dev_dbg(&adapter->dev, "master xfer %d messages:\n", num); + + for (i = 0 ; i < num ; i++) { + int cmd = CMD_I2C_IO; + + if (i == 0) + cmd |= CMD_I2C_IO_BEGIN; + + if (i == num-1) + cmd |= CMD_I2C_IO_END; + + pmsg = &msgs[i]; + + dev_dbg(&adapter->dev, + " %d: %s (flags %d) %d bytes to 0x%02x\n", + i, pmsg->flags & I2C_M_RD ? "read" : "write", + pmsg->flags, pmsg->len, pmsg->addr); + + /* and directly send the message */ + if (pmsg->flags & I2C_M_RD) { + /* read data */ + if (usb_read(adapter, cmd, + pmsg->flags, pmsg->addr, + pmsg->buf, pmsg->len) != pmsg->len) { + dev_err(&adapter->dev, + "failure reading data\n"); + return -EREMOTEIO; + } + } else { + /* write data */ + if (usb_write(adapter, cmd, + pmsg->flags, pmsg->addr, + pmsg->buf, pmsg->len) != pmsg->len) { + dev_err(&adapter->dev, + "failure writing data\n"); + return -EREMOTEIO; + } + } + + /* read status */ + if (usb_read(adapter, CMD_GET_STATUS, 0, 0, &status, 1) != 1) { + dev_err(&adapter->dev, "failure reading status\n"); + return -EREMOTEIO; + } + + dev_dbg(&adapter->dev, " status = %d\n", status); + if (status == STATUS_ADDRESS_NAK) + return -EREMOTEIO; + } + + return i; +} + +static u32 usb_func(struct i2c_adapter *adapter) +{ + u32 func; + + /* get functionality from adapter */ + if (usb_read(adapter, CMD_GET_FUNC, 0, 0, &func, sizeof(func)) != + sizeof(func)) { + dev_err(&adapter->dev, "failure reading functionality\n"); + return 0; + } + + return func; +} + +/* This is the actual algorithm we define */ +static const struct i2c_algorithm usb_algorithm = { + .master_xfer = usb_xfer, + .functionality = usb_func, +}; + +/* ----- end of i2c layer ------------------------------------------------ */ + +/* ----- begin of usb layer ---------------------------------------------- */ + +/* The usb i2c interface uses a vid/pid pair donated by */ +/* Future Technology Devices International Ltd. */ +static struct usb_device_id i2c_tiny_usb_table [] = { + { USB_DEVICE(0x0403, 0xc631) }, + { } /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE(usb, i2c_tiny_usb_table); + +/* Structure to hold all of our device specific stuff */ +struct i2c_tiny_usb { + struct usb_device *usb_dev; /* the usb device for this device */ + struct usb_interface *interface; /* the interface for this device */ + struct i2c_adapter adapter; /* i2c related things */ +}; + +static int usb_read(struct i2c_adapter *adapter, int cmd, + int value, int index, void *data, int len) +{ + struct i2c_tiny_usb *dev = (struct i2c_tiny_usb *)adapter->algo_data; + + /* do control transfer */ + return usb_control_msg(dev->usb_dev, usb_rcvctrlpipe(dev->usb_dev, 0), + cmd, USB_TYPE_VENDOR | USB_RECIP_INTERFACE | + USB_DIR_IN, value, index, data, len, 2000); +} + +static int usb_write(struct i2c_adapter *adapter, int cmd, + int value, int index, void *data, int len) +{ + struct i2c_tiny_usb *dev = (struct i2c_tiny_usb *)adapter->algo_data; + + /* do control transfer */ + return usb_control_msg(dev->usb_dev, usb_sndctrlpipe(dev->usb_dev, 0), + cmd, USB_TYPE_VENDOR | USB_RECIP_INTERFACE, + value, index, data, len, 2000); +} + +static void i2c_tiny_usb_free(struct i2c_tiny_usb *dev) +{ + usb_put_dev(dev->usb_dev); + kfree(dev); +} + +static int i2c_tiny_usb_probe(struct usb_interface *interface, + const struct usb_device_id *id) +{ + struct i2c_tiny_usb *dev; + int retval = -ENOMEM; + u16 version; + + dev_dbg(&interface->dev, "probing usb device\n"); + + /* allocate memory for our device state and initialize it */ + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (dev == NULL) { + dev_err(&interface->dev, "Out of memory\n"); + goto error; + } + + dev->usb_dev = usb_get_dev(interface_to_usbdev(interface)); + dev->interface = interface; + + /* save our data pointer in this interface device */ + usb_set_intfdata(interface, dev); + + version = le16_to_cpu(dev->usb_dev->descriptor.bcdDevice); + dev_info(&interface->dev, + "version %x.%02x found at bus %03d address %03d\n", + version >> 8, version & 0xff, + dev->usb_dev->bus->busnum, dev->usb_dev->devnum); + + /* setup i2c adapter description */ + dev->adapter.owner = THIS_MODULE; + dev->adapter.class = I2C_CLASS_HWMON; + dev->adapter.algo = &usb_algorithm; + dev->adapter.algo_data = dev; + snprintf(dev->adapter.name, I2C_NAME_SIZE, + "i2c-tiny-usb at bus %03d device %03d", + dev->usb_dev->bus->busnum, dev->usb_dev->devnum); + + if (usb_write(&dev->adapter, CMD_SET_DELAY, + cpu_to_le16(delay), 0, NULL, 0) != 0) { + dev_err(&dev->adapter.dev, + "failure setting delay to %dus\n", delay); + retval = -EIO; + goto error; + } + + dev->adapter.dev.parent = &dev->interface->dev; + + /* and finally attach to i2c layer */ + i2c_add_adapter(&dev->adapter); + + /* inform user about successful attachment to i2c layer */ + dev_info(&dev->adapter.dev, "connected i2c-tiny-usb device\n"); + + return 0; + + error: + if (dev) + i2c_tiny_usb_free(dev); + + return retval; +} + +static void i2c_tiny_usb_disconnect(struct usb_interface *interface) +{ + struct i2c_tiny_usb *dev = usb_get_intfdata(interface); + + i2c_del_adapter(&dev->adapter); + usb_set_intfdata(interface, NULL); + i2c_tiny_usb_free(dev); + + dev_dbg(&interface->dev, "disconnected\n"); +} + +static struct usb_driver i2c_tiny_usb_driver = { + .name = "i2c-tiny-usb", + .probe = i2c_tiny_usb_probe, + .disconnect = i2c_tiny_usb_disconnect, + .id_table = i2c_tiny_usb_table, +}; + +static int __init usb_i2c_tiny_usb_init(void) +{ + /* register this driver with the USB subsystem */ + return usb_register(&i2c_tiny_usb_driver); +} + +static void __exit usb_i2c_tiny_usb_exit(void) +{ + /* deregister this driver with the USB subsystem */ + usb_deregister(&i2c_tiny_usb_driver); +} + +module_init(usb_i2c_tiny_usb_init); +module_exit(usb_i2c_tiny_usb_exit); + +/* ----- end of usb layer ------------------------------------------------ */ + +MODULE_AUTHOR("Till Harbaum <Till@Harbaum.org>"); +MODULE_DESCRIPTION("i2c-tiny-usb driver v1.0"); +MODULE_LICENSE("GPL"); diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c index 03c5fc86854..7a2bc06304f 100644 --- a/drivers/i2c/busses/i2c-viapro.c +++ b/drivers/i2c/busses/i2c-viapro.c @@ -404,7 +404,7 @@ found: } vt596_adapter.dev.parent = &pdev->dev; - snprintf(vt596_adapter.name, I2C_NAME_SIZE, + snprintf(vt596_adapter.name, sizeof(vt596_adapter.name), "SMBus Via Pro adapter at %04x", vt596_smba); vt596_pdev = pci_dev_get(pdev); diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c index 0b082c5a019..0db56e7bc34 100644 --- a/drivers/i2c/busses/scx200_acb.c +++ b/drivers/i2c/busses/scx200_acb.c @@ -441,7 +441,7 @@ static __init struct scx200_acb_iface *scx200_create_iface(const char *text, adapter = &iface->adapter; i2c_set_adapdata(adapter, iface); - snprintf(adapter->name, I2C_NAME_SIZE, "%s ACB%d", text, index); + snprintf(adapter->name, sizeof(adapter->name), "%s ACB%d", text, index); adapter->owner = THIS_MODULE; adapter->id = I2C_HW_SMBUS_SCX200; adapter->algo = &scx200_acb_algorithm; @@ -599,6 +599,7 @@ static __init int scx200_scan_pci(void) else { int i; + pci_dev_put(pdev); for (i = 0; i < MAX_DEVICES; ++i) { if (base[i] == 0) continue; diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig index 87ee3ce5861..ea085a006ea 100644 --- a/drivers/i2c/chips/Kconfig +++ b/drivers/i2c/chips/Kconfig @@ -3,11 +3,10 @@ # menu "Miscellaneous I2C Chip support" - depends on I2C config SENSORS_DS1337 tristate "Dallas Semiconductor DS1337 and DS1339 Real Time Clock" - depends on I2C && EXPERIMENTAL + depends on EXPERIMENTAL help If you say yes here you get support for Dallas Semiconductor DS1337 and DS1339 real-time clock chips. @@ -17,7 +16,7 @@ config SENSORS_DS1337 config SENSORS_DS1374 tristate "Maxim/Dallas Semiconductor DS1374 Real Time Clock" - depends on I2C && EXPERIMENTAL + depends on EXPERIMENTAL help If you say yes here you get support for Dallas Semiconductor DS1374 real-time clock chips. @@ -27,7 +26,7 @@ config SENSORS_DS1374 config SENSORS_EEPROM tristate "EEPROM reader" - depends on I2C && EXPERIMENTAL + depends on EXPERIMENTAL help If you say yes here you get read-only access to the EEPROM data available on modern memory DIMMs and Sony Vaio laptops. Such @@ -38,7 +37,7 @@ config SENSORS_EEPROM config SENSORS_PCF8574 tristate "Philips PCF8574 and PCF8574A" - depends on I2C && EXPERIMENTAL + depends on EXPERIMENTAL default n help If you say yes here you get support for Philips PCF8574 and @@ -52,7 +51,7 @@ config SENSORS_PCF8574 config SENSORS_PCA9539 tristate "Philips PCA9539 16-bit I/O port" - depends on I2C && EXPERIMENTAL + depends on EXPERIMENTAL help If you say yes here you get support for the Philips PCA9539 16-bit I/O port. @@ -62,7 +61,7 @@ config SENSORS_PCA9539 config SENSORS_PCF8591 tristate "Philips PCF8591" - depends on I2C && EXPERIMENTAL + depends on EXPERIMENTAL default n help If you say yes here you get support for Philips PCF8591 chips. @@ -75,7 +74,7 @@ config SENSORS_PCF8591 config ISP1301_OMAP tristate "Philips ISP1301 with OMAP OTG" - depends on I2C && ARCH_OMAP_OTG + depends on ARCH_OMAP_OTG help If you say yes here you get support for the Philips ISP1301 USB-On-The-Go transceiver working with the OMAP OTG controller. @@ -90,7 +89,7 @@ config ISP1301_OMAP # and having mostly OMAP-specific board support config TPS65010 tristate "TPS6501x Power Management chips" - depends on I2C && ARCH_OMAP + depends on ARCH_OMAP default y if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_OSK help If you say yes here you get support for the TPS6501x series of @@ -103,7 +102,7 @@ config TPS65010 config SENSORS_M41T00 tristate "ST M41T00 RTC chip" - depends on I2C && PPC32 + depends on PPC32 help If you say yes here you get support for the ST M41T00 RTC chip. @@ -112,7 +111,7 @@ config SENSORS_M41T00 config SENSORS_MAX6875 tristate "Maxim MAX6875 Power supply supervisor" - depends on I2C && EXPERIMENTAL + depends on EXPERIMENTAL help If you say yes here you get support for the Maxim MAX6875 EEPROM-programmable, quad power-supply sequencer/supervisor. diff --git a/drivers/i2c/i2c-boardinfo.c b/drivers/i2c/i2c-boardinfo.c new file mode 100644 index 00000000000..ffb35f09df0 --- /dev/null +++ b/drivers/i2c/i2c-boardinfo.c @@ -0,0 +1,90 @@ +/* + * i2c-boardinfo.h - collect pre-declarations of I2C devices + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <linux/kernel.h> +#include <linux/i2c.h> + +#include "i2c-core.h" + + +/* These symbols are exported ONLY FOR the i2c core. + * No other users will be supported. + */ +DEFINE_MUTEX(__i2c_board_lock); +EXPORT_SYMBOL_GPL(__i2c_board_lock); + +LIST_HEAD(__i2c_board_list); +EXPORT_SYMBOL_GPL(__i2c_board_list); + +int __i2c_first_dynamic_bus_num; +EXPORT_SYMBOL_GPL(__i2c_first_dynamic_bus_num); + + +/** + * i2c_register_board_info - statically declare I2C devices + * @busnum: identifies the bus to which these devices belong + * @info: vector of i2c device descriptors + * @len: how many descriptors in the vector; may be zero to reserve + * the specified bus number. + * + * Systems using the Linux I2C driver stack can declare tables of board info + * while they initialize. This should be done in board-specific init code + * near arch_initcall() time, or equivalent, before any I2C adapter driver is + * registered. For example, mainboard init code could define several devices, + * as could the init code for each daughtercard in a board stack. + * + * The I2C devices will be created later, after the adapter for the relevant + * bus has been registered. After that moment, standard driver model tools + * are used to bind "new style" I2C drivers to the devices. The bus number + * for any device declared using this routine is not available for dynamic + * allocation. + * + * The board info passed can safely be __initdata, but be careful of embedded + * pointers (for platform_data, functions, etc) since that won't be copied. + */ +int __init +i2c_register_board_info(int busnum, + struct i2c_board_info const *info, unsigned len) +{ + int status; + + mutex_lock(&__i2c_board_lock); + + /* dynamic bus numbers will be assigned after the last static one */ + if (busnum >= __i2c_first_dynamic_bus_num) + __i2c_first_dynamic_bus_num = busnum + 1; + + for (status = 0; len; len--, info++) { + struct i2c_devinfo *devinfo; + + devinfo = kzalloc(sizeof(*devinfo), GFP_KERNEL); + if (!devinfo) { + pr_debug("i2c-core: can't register boardinfo!\n"); + status = -ENOMEM; + break; + } + + devinfo->busnum = busnum; + devinfo->board_info = *info; + list_add_tail(&devinfo->list, &__i2c_board_list); + } + + mutex_unlock(&__i2c_board_lock); + + return status; +} diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 21fe1406c8b..64f8e56d300 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -35,29 +35,92 @@ #include <linux/completion.h> #include <asm/uaccess.h> +#include "i2c-core.h" + static LIST_HEAD(adapters); static LIST_HEAD(drivers); static DEFINE_MUTEX(core_lists); static DEFINE_IDR(i2c_adapter_idr); +#define is_newstyle_driver(d) ((d)->probe || (d)->remove) /* ------------------------------------------------------------------------- */ -/* match always succeeds, as we want the probe() to tell if we really accept this match */ static int i2c_device_match(struct device *dev, struct device_driver *drv) { - return 1; + struct i2c_client *client = to_i2c_client(dev); + struct i2c_driver *driver = to_i2c_driver(drv); + + /* make legacy i2c drivers bypass driver model probing entirely; + * such drivers scan each i2c adapter/bus themselves. + */ + if (!is_newstyle_driver(driver)) + return 0; + + /* new style drivers use the same kind of driver matching policy + * as platform devices or SPI: compare device and driver IDs. + */ + return strcmp(client->driver_name, drv->name) == 0; +} + +#ifdef CONFIG_HOTPLUG + +/* uevent helps with hotplug: modprobe -q $(MODALIAS) */ +static int i2c_device_uevent(struct device *dev, char **envp, int num_envp, + char *buffer, int buffer_size) +{ + struct i2c_client *client = to_i2c_client(dev); + int i = 0, length = 0; + + /* by definition, legacy drivers can't hotplug */ + if (dev->driver || !client->driver_name) + return 0; + + if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length, + "MODALIAS=%s", client->driver_name)) + return -ENOMEM; + envp[i] = NULL; + dev_dbg(dev, "uevent\n"); + return 0; } +#else +#define i2c_device_uevent NULL +#endif /* CONFIG_HOTPLUG */ + static int i2c_device_probe(struct device *dev) { - return -ENODEV; + struct i2c_client *client = to_i2c_client(dev); + struct i2c_driver *driver = to_i2c_driver(dev->driver); + + if (!driver->probe) + return -ENODEV; + client->driver = driver; + dev_dbg(dev, "probe\n"); + return driver->probe(client); } static int i2c_device_remove(struct device *dev) { - return 0; + struct i2c_client *client = to_i2c_client(dev); + struct i2c_driver *driver; + int status; + + if (!dev->driver) + return 0; + + driver = to_i2c_driver(dev->driver); + if (driver->remove) { + dev_dbg(dev, "remove\n"); + status = driver->remove(client); + } else { + dev->driver = NULL; + status = 0; + } + if (status == 0) + client->driver = NULL; + return status; } static void i2c_device_shutdown(struct device *dev) @@ -95,122 +158,184 @@ static int i2c_device_resume(struct device * dev) return driver->resume(to_i2c_client(dev)); } +static void i2c_client_release(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + complete(&client->released); +} + +static void i2c_client_dev_release(struct device *dev) +{ + kfree(to_i2c_client(dev)); +} + +static ssize_t show_client_name(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + return sprintf(buf, "%s\n", client->name); +} + +static ssize_t show_modalias(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + return client->driver_name + ? sprintf(buf, "%s\n", client->driver_name) + : 0; +} + +static struct device_attribute i2c_dev_attrs[] = { + __ATTR(name, S_IRUGO, show_client_name, NULL), + /* modalias helps coldplug: modprobe $(cat .../modalias) */ + __ATTR(modalias, S_IRUGO, show_modalias, NULL), + { }, +}; + struct bus_type i2c_bus_type = { .name = "i2c", + .dev_attrs = i2c_dev_attrs, .match = i2c_device_match, + .uevent = i2c_device_uevent, .probe = i2c_device_probe, .remove = i2c_device_remove, .shutdown = i2c_device_shutdown, .suspend = i2c_device_suspend, .resume = i2c_device_resume, }; +EXPORT_SYMBOL_GPL(i2c_bus_type); -/* ------------------------------------------------------------------------- */ +/** + * i2c_new_device - instantiate an i2c device for use with a new style driver + * @adap: the adapter managing the device + * @info: describes one I2C device; bus_num is ignored + * + * Create a device to work with a new style i2c driver, where binding is + * handled through driver model probe()/remove() methods. This call is not + * appropriate for use by mainboad initialization logic, which usually runs + * during an arch_initcall() long before any i2c_adapter could exist. + * + * This returns the new i2c client, which may be saved for later use with + * i2c_unregister_device(); or NULL to indicate an error. + */ +struct i2c_client * +i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) +{ + struct i2c_client *client; + int status; -void i2c_adapter_dev_release(struct device *dev) + client = kzalloc(sizeof *client, GFP_KERNEL); + if (!client) + return NULL; + + client->adapter = adap; + + client->dev.platform_data = info->platform_data; + client->flags = info->flags; + client->addr = info->addr; + client->irq = info->irq; + + strlcpy(client->driver_name, info->driver_name, + sizeof(client->driver_name)); + strlcpy(client->name, info->type, sizeof(client->name)); + + /* a new style driver may be bound to this device when we + * return from this function, or any later moment (e.g. maybe + * hotplugging will load the driver module). and the device + * refcount model is the standard driver model one. + */ + status = i2c_attach_client(client); + if (status < 0) { + kfree(client); + client = NULL; + } + return client; +} +EXPORT_SYMBOL_GPL(i2c_new_device); + + +/** + * i2c_unregister_device - reverse effect of i2c_new_device() + * @client: value returned from i2c_new_device() + */ +void i2c_unregister_device(struct i2c_client *client) { - struct i2c_adapter *adap = dev_to_i2c_adapter(dev); - complete(&adap->dev_released); + struct i2c_adapter *adapter = client->adapter; + struct i2c_driver *driver = client->driver; + + if (driver && !is_newstyle_driver(driver)) { + dev_err(&client->dev, "can't unregister devices " + "with legacy drivers\n"); + WARN_ON(1); + return; + } + + mutex_lock(&adapter->clist_lock); + list_del(&client->list); + mutex_unlock(&adapter->clist_lock); + + device_unregister(&client->dev); } +EXPORT_SYMBOL_GPL(i2c_unregister_device); -struct device_driver i2c_adapter_driver = { - .owner = THIS_MODULE, - .name = "i2c_adapter", - .bus = &i2c_bus_type, -}; /* ------------------------------------------------------------------------- */ /* I2C bus adapters -- one roots each I2C or SMBUS segment */ -static void i2c_adapter_class_dev_release(struct class_device *dev) +void i2c_adapter_dev_release(struct device *dev) { - struct i2c_adapter *adap = class_dev_to_i2c_adapter(dev); - complete(&adap->class_dev_released); + struct i2c_adapter *adap = to_i2c_adapter(dev); + complete(&adap->dev_released); } +EXPORT_SYMBOL_GPL(i2c_adapter_dev_release); /* exported to i2c-isa */ -static ssize_t i2c_adapter_show_name(struct class_device *cdev, char *buf) +static ssize_t +show_adapter_name(struct device *dev, struct device_attribute *attr, char *buf) { - struct i2c_adapter *adap = class_dev_to_i2c_adapter(cdev); + struct i2c_adapter *adap = to_i2c_adapter(dev); return sprintf(buf, "%s\n", adap->name); } -static struct class_device_attribute i2c_adapter_attrs[] = { - __ATTR(name, S_IRUGO, i2c_adapter_show_name, NULL), +static struct device_attribute i2c_adapter_attrs[] = { + __ATTR(name, S_IRUGO, show_adapter_name, NULL), { }, }; struct class i2c_adapter_class = { .owner = THIS_MODULE, .name = "i2c-adapter", - .class_dev_attrs = i2c_adapter_attrs, - .release = &i2c_adapter_class_dev_release, + .dev_attrs = i2c_adapter_attrs, }; +EXPORT_SYMBOL_GPL(i2c_adapter_class); /* exported to i2c-isa */ -static ssize_t show_adapter_name(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct i2c_adapter *adap = dev_to_i2c_adapter(dev); - return sprintf(buf, "%s\n", adap->name); -} -static DEVICE_ATTR(name, S_IRUGO, show_adapter_name, NULL); - - -static void i2c_client_release(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - complete(&client->released); -} - -static ssize_t show_client_name(struct device *dev, struct device_attribute *attr, char *buf) +static void i2c_scan_static_board_info(struct i2c_adapter *adapter) { - struct i2c_client *client = to_i2c_client(dev); - return sprintf(buf, "%s\n", client->name); + struct i2c_devinfo *devinfo; + + mutex_lock(&__i2c_board_lock); + list_for_each_entry(devinfo, &__i2c_board_list, list) { + if (devinfo->busnum == adapter->nr + && !i2c_new_device(adapter, + &devinfo->board_info)) + printk(KERN_ERR "i2c-core: can't create i2c%d-%04x\n", + i2c_adapter_id(adapter), + devinfo->board_info.addr); + } + mutex_unlock(&__i2c_board_lock); } -/* - * We can't use the DEVICE_ATTR() macro here, as we used the same name for - * an i2c adapter attribute (above). - */ -static struct device_attribute dev_attr_client_name = - __ATTR(name, S_IRUGO, &show_client_name, NULL); - - -/* --------------------------------------------------- - * registering functions - * --------------------------------------------------- - */ - -/* ----- - * i2c_add_adapter is called from within the algorithm layer, - * when a new hw adapter registers. A new device is register to be - * available for clients. - */ -int i2c_add_adapter(struct i2c_adapter *adap) +static int i2c_register_adapter(struct i2c_adapter *adap) { - int id, res = 0; + int res = 0; struct list_head *item; struct i2c_driver *driver; - mutex_lock(&core_lists); - - if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0) { - res = -ENOMEM; - goto out_unlock; - } - - res = idr_get_new(&i2c_adapter_idr, adap, &id); - if (res < 0) { - if (res == -EAGAIN) - res = -ENOMEM; - goto out_unlock; - } - - adap->nr = id & MAX_ID_MASK; mutex_init(&adap->bus_lock); mutex_init(&adap->clist_lock); - list_add_tail(&adap->list,&adapters); INIT_LIST_HEAD(&adap->clients); + mutex_lock(&core_lists); + list_add_tail(&adap->list, &adapters); + /* Add the adapter to the driver core. * If the parent pointer is not set up, * we add this adapter to the host bus. @@ -221,27 +346,19 @@ int i2c_add_adapter(struct i2c_adapter *adap) "physical device\n", adap->name); } sprintf(adap->dev.bus_id, "i2c-%d", adap->nr); - adap->dev.driver = &i2c_adapter_driver; adap->dev.release = &i2c_adapter_dev_release; + adap->dev.class = &i2c_adapter_class; res = device_register(&adap->dev); if (res) goto out_list; - res = device_create_file(&adap->dev, &dev_attr_name); - if (res) - goto out_unregister; - - /* Add this adapter to the i2c_adapter class */ - memset(&adap->class_dev, 0x00, sizeof(struct class_device)); - adap->class_dev.dev = &adap->dev; - adap->class_dev.class = &i2c_adapter_class; - strlcpy(adap->class_dev.class_id, adap->dev.bus_id, BUS_ID_SIZE); - res = class_device_register(&adap->class_dev); - if (res) - goto out_remove_name; dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name); - /* inform drivers of new adapters */ + /* create pre-declared device nodes for new-style drivers */ + if (adap->nr < __i2c_first_dynamic_bus_num) + i2c_scan_static_board_info(adap); + + /* let legacy drivers scan this bus for matching devices */ list_for_each(item,&drivers) { driver = list_entry(item, struct i2c_driver, list); if (driver->attach_adapter) @@ -253,18 +370,98 @@ out_unlock: mutex_unlock(&core_lists); return res; -out_remove_name: - device_remove_file(&adap->dev, &dev_attr_name); -out_unregister: - init_completion(&adap->dev_released); /* Needed? */ - device_unregister(&adap->dev); - wait_for_completion(&adap->dev_released); out_list: list_del(&adap->list); idr_remove(&i2c_adapter_idr, adap->nr); goto out_unlock; } +/** + * i2c_add_adapter - declare i2c adapter, use dynamic bus number + * @adapter: the adapter to add + * + * This routine is used to declare an I2C adapter when its bus number + * doesn't matter. Examples: for I2C adapters dynamically added by + * USB links or PCI plugin cards. + * + * When this returns zero, a new bus number was allocated and stored + * in adap->nr, and the specified adapter became available for clients. + * Otherwise, a negative errno value is returned. + */ +int i2c_add_adapter(struct i2c_adapter *adapter) +{ + int id, res = 0; + +retry: + if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0) + return -ENOMEM; + + mutex_lock(&core_lists); + /* "above" here means "above or equal to", sigh */ + res = idr_get_new_above(&i2c_adapter_idr, adapter, + __i2c_first_dynamic_bus_num, &id); + mutex_unlock(&core_lists); + + if (res < 0) { + if (res == -EAGAIN) + goto retry; + return res; + } + + adapter->nr = id; + return i2c_register_adapter(adapter); +} +EXPORT_SYMBOL(i2c_add_adapter); + +/** + * i2c_add_numbered_adapter - declare i2c adapter, use static bus number + * @adap: the adapter to register (with adap->nr initialized) + * + * This routine is used to declare an I2C adapter when its bus number + * matters. Example: for I2C adapters from system-on-chip CPUs, or + * otherwise built in to the system's mainboard, and where i2c_board_info + * is used to properly configure I2C devices. + * + * If no devices have pre-been declared for this bus, then be sure to + * register the adapter before any dynamically allocated ones. Otherwise + * the required bus ID may not be available. + * + * When this returns zero, the specified adapter became available for + * clients using the bus number provided in adap->nr. Also, the table + * of I2C devices pre-declared using i2c_register_board_info() is scanned, + * and the appropriate driver model device nodes are created. Otherwise, a + * negative errno value is returned. + */ +int i2c_add_numbered_adapter(struct i2c_adapter *adap) +{ + int id; + int status; + + if (adap->nr & ~MAX_ID_MASK) + return -EINVAL; + +retry: + if (idr_pre_get(&i2c_adapter_idr, GFP_KERNEL) == 0) + return -ENOMEM; + + mutex_lock(&core_lists); + /* "above" here means "above or equal to", sigh; + * we need the "equal to" result to force the result + */ + status = idr_get_new_above(&i2c_adapter_idr, adap, adap->nr, &id); + if (status == 0 && id != adap->nr) { + status = -EBUSY; + idr_remove(&i2c_adapter_idr, id); + } + mutex_unlock(&core_lists); + if (status == -EAGAIN) + goto retry; + + if (status == 0) + status = i2c_register_adapter(adap); + return status; +} +EXPORT_SYMBOL_GPL(i2c_add_numbered_adapter); int i2c_del_adapter(struct i2c_adapter *adap) { @@ -302,9 +499,19 @@ int i2c_del_adapter(struct i2c_adapter *adap) /* detach any active clients. This must be done first, because * it can fail; in which case we give up. */ list_for_each_safe(item, _n, &adap->clients) { + struct i2c_driver *driver; + client = list_entry(item, struct i2c_client, list); + driver = client->driver; + + /* new style, follow standard driver model */ + if (!driver || is_newstyle_driver(driver)) { + i2c_unregister_device(client); + continue; + } - if ((res=client->driver->detach_client(client))) { + /* legacy drivers create and remove clients themselves */ + if ((res = driver->detach_client(client))) { dev_err(&adap->dev, "detach_client failed for client " "[%s] at address 0x%02x\n", client->name, client->addr); @@ -314,17 +521,13 @@ int i2c_del_adapter(struct i2c_adapter *adap) /* clean up the sysfs representation */ init_completion(&adap->dev_released); - init_completion(&adap->class_dev_released); - class_device_unregister(&adap->class_dev); - device_remove_file(&adap->dev, &dev_attr_name); device_unregister(&adap->dev); list_del(&adap->list); /* wait for sysfs to drop all references */ wait_for_completion(&adap->dev_released); - wait_for_completion(&adap->class_dev_released); - /* free dynamically allocated bus id */ + /* free bus id */ idr_remove(&i2c_adapter_idr, adap->nr); dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name); @@ -333,24 +536,42 @@ int i2c_del_adapter(struct i2c_adapter *adap) mutex_unlock(&core_lists); return res; } +EXPORT_SYMBOL(i2c_del_adapter); + +/* ------------------------------------------------------------------------- */ -/* ----- - * What follows is the "upwards" interface: commands for talking to clients, - * which implement the functions to access the physical information of the - * chips. +/* + * An i2c_driver is used with one or more i2c_client (device) nodes to access + * i2c slave chips, on a bus instance associated with some i2c_adapter. There + * are two models for binding the driver to its device: "new style" drivers + * follow the standard Linux driver model and just respond to probe() calls + * issued if the driver core sees they match(); "legacy" drivers create device + * nodes themselves. */ int i2c_register_driver(struct module *owner, struct i2c_driver *driver) { - struct list_head *item; - struct i2c_adapter *adapter; int res; + /* new style driver methods can't mix with legacy ones */ + if (is_newstyle_driver(driver)) { + if (driver->attach_adapter || driver->detach_adapter + || driver->detach_client) { + printk(KERN_WARNING + "i2c-core: driver [%s] is confused\n", + driver->driver.name); + return -EINVAL; + } + } + /* add the driver to the list of i2c drivers in the driver core */ driver->driver.owner = owner; driver->driver.bus = &i2c_bus_type; + /* for new style drivers, when registration returns the driver core + * will have called probe() for all matching-but-unbound devices. + */ res = driver_register(&driver->driver); if (res) return res; @@ -360,10 +581,11 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver) list_add_tail(&driver->list,&drivers); pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name); - /* now look for instances of driver on our adapters */ + /* legacy drivers scan i2c busses directly */ if (driver->attach_adapter) { - list_for_each(item,&adapters) { - adapter = list_entry(item, struct i2c_adapter, list); + struct i2c_adapter *adapter; + + list_for_each_entry(adapter, &adapters, list) { driver->attach_adapter(adapter); } } @@ -373,16 +595,22 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver) } EXPORT_SYMBOL(i2c_register_driver); -int i2c_del_driver(struct i2c_driver *driver) +/** + * i2c_del_driver - unregister I2C driver + * @driver: the driver being unregistered + */ +void i2c_del_driver(struct i2c_driver *driver) { struct list_head *item1, *item2, *_n; struct i2c_client *client; struct i2c_adapter *adap; - int res = 0; - mutex_lock(&core_lists); + /* new-style driver? */ + if (is_newstyle_driver(driver)) + goto unregister; + /* Have a look at each adapter, if clients of this driver are still * attached. If so, detach them to be able to kill the driver * afterwards. @@ -390,11 +618,10 @@ int i2c_del_driver(struct i2c_driver *driver) list_for_each(item1,&adapters) { adap = list_entry(item1, struct i2c_adapter, list); if (driver->detach_adapter) { - if ((res = driver->detach_adapter(adap))) { + if (driver->detach_adapter(adap)) { dev_err(&adap->dev, "detach_adapter failed " "for driver [%s]\n", driver->driver.name); - goto out_unlock; } } else { list_for_each_safe(item2, _n, &adap->clients) { @@ -404,25 +631,26 @@ int i2c_del_driver(struct i2c_driver *driver) dev_dbg(&adap->dev, "detaching client [%s] " "at 0x%02x\n", client->name, client->addr); - if ((res = driver->detach_client(client))) { + if (driver->detach_client(client)) { dev_err(&adap->dev, "detach_client " "failed for client [%s] at " "0x%02x\n", client->name, client->addr); - goto out_unlock; } } } } + unregister: driver_unregister(&driver->driver); list_del(&driver->list); pr_debug("i2c-core: driver [%s] unregistered\n", driver->driver.name); - out_unlock: mutex_unlock(&core_lists); - return 0; } +EXPORT_SYMBOL(i2c_del_driver); + +/* ------------------------------------------------------------------------- */ static int __i2c_check_addr(struct i2c_adapter *adapter, unsigned int addr) { @@ -447,6 +675,7 @@ int i2c_check_addr(struct i2c_adapter *adapter, int addr) return rval; } +EXPORT_SYMBOL(i2c_check_addr); int i2c_attach_client(struct i2c_client *client) { @@ -463,9 +692,15 @@ int i2c_attach_client(struct i2c_client *client) client->usage_count = 0; client->dev.parent = &client->adapter->dev; - client->dev.driver = &client->driver->driver; client->dev.bus = &i2c_bus_type; - client->dev.release = &i2c_client_release; + + if (client->driver) + client->dev.driver = &client->driver->driver; + + if (client->driver && !is_newstyle_driver(client->driver)) + client->dev.release = i2c_client_release; + else + client->dev.release = i2c_client_dev_release; snprintf(&client->dev.bus_id[0], sizeof(client->dev.bus_id), "%d-%04x", i2c_adapter_id(adapter), client->addr); @@ -474,9 +709,6 @@ int i2c_attach_client(struct i2c_client *client) res = device_register(&client->dev); if (res) goto out_list; - res = device_create_file(&client->dev, &dev_attr_client_name); - if (res) - goto out_unregister; mutex_unlock(&adapter->clist_lock); if (adapter->client_register) { @@ -489,10 +721,6 @@ int i2c_attach_client(struct i2c_client *client) return 0; -out_unregister: - init_completion(&client->released); /* Needed? */ - device_unregister(&client->dev); - wait_for_completion(&client->released); out_list: list_del(&client->list); dev_err(&adapter->dev, "Failed to attach i2c client %s at 0x%02x " @@ -501,7 +729,7 @@ out_unlock: mutex_unlock(&adapter->clist_lock); return res; } - +EXPORT_SYMBOL(i2c_attach_client); int i2c_detach_client(struct i2c_client *client) { @@ -527,7 +755,6 @@ int i2c_detach_client(struct i2c_client *client) mutex_lock(&adapter->clist_lock); list_del(&client->list); init_completion(&client->released); - device_remove_file(&client->dev, &dev_attr_client_name); device_unregister(&client->dev); mutex_unlock(&adapter->clist_lock); wait_for_completion(&client->released); @@ -535,6 +762,7 @@ int i2c_detach_client(struct i2c_client *client) out: return res; } +EXPORT_SYMBOL(i2c_detach_client); static int i2c_inc_use_client(struct i2c_client *client) { @@ -567,6 +795,7 @@ int i2c_use_client(struct i2c_client *client) return 0; } +EXPORT_SYMBOL(i2c_use_client); int i2c_release_client(struct i2c_client *client) { @@ -581,6 +810,7 @@ int i2c_release_client(struct i2c_client *client) return 0; } +EXPORT_SYMBOL(i2c_release_client); void i2c_clients_command(struct i2c_adapter *adap, unsigned int cmd, void *arg) { @@ -601,6 +831,7 @@ void i2c_clients_command(struct i2c_adapter *adap, unsigned int cmd, void *arg) } mutex_unlock(&adap->clist_lock); } +EXPORT_SYMBOL(i2c_clients_command); static int __init i2c_init(void) { @@ -609,16 +840,12 @@ static int __init i2c_init(void) retval = bus_register(&i2c_bus_type); if (retval) return retval; - retval = driver_register(&i2c_adapter_driver); - if (retval) - return retval; return class_register(&i2c_adapter_class); } static void __exit i2c_exit(void) { class_unregister(&i2c_adapter_class); - driver_unregister(&i2c_adapter_driver); bus_unregister(&i2c_bus_type); } @@ -638,8 +865,9 @@ int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num) #ifdef DEBUG for (ret = 0; ret < num; ret++) { dev_dbg(&adap->dev, "master_xfer[%d] %c, addr=0x%02x, " - "len=%d\n", ret, msgs[ret].flags & I2C_M_RD ? - 'R' : 'W', msgs[ret].addr, msgs[ret].len); + "len=%d%s\n", ret, (msgs[ret].flags & I2C_M_RD) + ? 'R' : 'W', msgs[ret].addr, msgs[ret].len, + (msgs[ret].flags & I2C_M_RECV_LEN) ? "+" : ""); } #endif @@ -653,6 +881,7 @@ int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num) return -ENOSYS; } } +EXPORT_SYMBOL(i2c_transfer); int i2c_master_send(struct i2c_client *client,const char *buf ,int count) { @@ -671,6 +900,7 @@ int i2c_master_send(struct i2c_client *client,const char *buf ,int count) transmitted, else error code. */ return (ret == 1) ? count : ret; } +EXPORT_SYMBOL(i2c_master_send); int i2c_master_recv(struct i2c_client *client, char *buf ,int count) { @@ -690,7 +920,7 @@ int i2c_master_recv(struct i2c_client *client, char *buf ,int count) transmitted, else error code. */ return (ret == 1) ? count : ret; } - +EXPORT_SYMBOL(i2c_master_recv); int i2c_control(struct i2c_client *client, unsigned int cmd, unsigned long arg) @@ -712,6 +942,7 @@ int i2c_control(struct i2c_client *client, } return ret; } +EXPORT_SYMBOL(i2c_control); /* ---------------------------------------------------- * the i2c address scanning function @@ -853,6 +1084,70 @@ int i2c_probe(struct i2c_adapter *adapter, return 0; } +EXPORT_SYMBOL(i2c_probe); + +struct i2c_client * +i2c_new_probed_device(struct i2c_adapter *adap, + struct i2c_board_info *info, + unsigned short const *addr_list) +{ + int i; + + /* Stop here if the bus doesn't support probing */ + if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_READ_BYTE)) { + dev_err(&adap->dev, "Probing not supported\n"); + return NULL; + } + + mutex_lock(&adap->clist_lock); + for (i = 0; addr_list[i] != I2C_CLIENT_END; i++) { + /* Check address validity */ + if (addr_list[i] < 0x03 || addr_list[i] > 0x77) { + dev_warn(&adap->dev, "Invalid 7-bit address " + "0x%02x\n", addr_list[i]); + continue; + } + + /* Check address availability */ + if (__i2c_check_addr(adap, addr_list[i])) { + dev_dbg(&adap->dev, "Address 0x%02x already in " + "use, not probing\n", addr_list[i]); + continue; + } + + /* Test address responsiveness + The default probe method is a quick write, but it is known + to corrupt the 24RF08 EEPROMs due to a state machine bug, + and could also irreversibly write-protect some EEPROMs, so + for address ranges 0x30-0x37 and 0x50-0x5f, we use a byte + read instead. Also, some bus drivers don't implement + quick write, so we fallback to a byte read it that case + too. */ + if ((addr_list[i] & ~0x07) == 0x30 + || (addr_list[i] & ~0x0f) == 0x50 + || !i2c_check_functionality(adap, I2C_FUNC_SMBUS_QUICK)) { + if (i2c_smbus_xfer(adap, addr_list[i], 0, + I2C_SMBUS_READ, 0, + I2C_SMBUS_BYTE, NULL) >= 0) + break; + } else { + if (i2c_smbus_xfer(adap, addr_list[i], 0, + I2C_SMBUS_WRITE, 0, + I2C_SMBUS_QUICK, NULL) >= 0) + break; + } + } + mutex_unlock(&adap->clist_lock); + + if (addr_list[i] == I2C_CLIENT_END) { + dev_dbg(&adap->dev, "Probing failed, no device found\n"); + return NULL; + } + + info->addr = addr_list[i]; + return i2c_new_device(adap, info); +} +EXPORT_SYMBOL_GPL(i2c_new_probed_device); struct i2c_adapter* i2c_get_adapter(int id) { @@ -866,11 +1161,13 @@ struct i2c_adapter* i2c_get_adapter(int id) mutex_unlock(&core_lists); return adapter; } +EXPORT_SYMBOL(i2c_get_adapter); void i2c_put_adapter(struct i2c_adapter *adap) { module_put(adap->owner); } +EXPORT_SYMBOL(i2c_put_adapter); /* The SMBus parts */ @@ -939,6 +1236,7 @@ s32 i2c_smbus_write_quick(struct i2c_client *client, u8 value) return i2c_smbus_xfer(client->adapter,client->addr,client->flags, value,0,I2C_SMBUS_QUICK,NULL); } +EXPORT_SYMBOL(i2c_smbus_write_quick); s32 i2c_smbus_read_byte(struct i2c_client *client) { @@ -949,12 +1247,14 @@ s32 i2c_smbus_read_byte(struct i2c_client *client) else return data.byte; } +EXPORT_SYMBOL(i2c_smbus_read_byte); s32 i2c_smbus_write_byte(struct i2c_client *client, u8 value) { return i2c_smbus_xfer(client->adapter,client->addr,client->flags, I2C_SMBUS_WRITE, value, I2C_SMBUS_BYTE, NULL); } +EXPORT_SYMBOL(i2c_smbus_write_byte); s32 i2c_smbus_read_byte_data(struct i2c_client *client, u8 command) { @@ -965,6 +1265,7 @@ s32 i2c_smbus_read_byte_data(struct i2c_client *client, u8 command) else return data.byte; } +EXPORT_SYMBOL(i2c_smbus_read_byte_data); s32 i2c_smbus_write_byte_data(struct i2c_client *client, u8 command, u8 value) { @@ -974,6 +1275,7 @@ s32 i2c_smbus_write_byte_data(struct i2c_client *client, u8 command, u8 value) I2C_SMBUS_WRITE,command, I2C_SMBUS_BYTE_DATA,&data); } +EXPORT_SYMBOL(i2c_smbus_write_byte_data); s32 i2c_smbus_read_word_data(struct i2c_client *client, u8 command) { @@ -984,6 +1286,7 @@ s32 i2c_smbus_read_word_data(struct i2c_client *client, u8 command) else return data.word; } +EXPORT_SYMBOL(i2c_smbus_read_word_data); s32 i2c_smbus_write_word_data(struct i2c_client *client, u8 command, u16 value) { @@ -993,6 +1296,23 @@ s32 i2c_smbus_write_word_data(struct i2c_client *client, u8 command, u16 value) I2C_SMBUS_WRITE,command, I2C_SMBUS_WORD_DATA,&data); } +EXPORT_SYMBOL(i2c_smbus_write_word_data); + +/* Returns the number of read bytes */ +s32 i2c_smbus_read_block_data(struct i2c_client *client, u8 command, + u8 *values) +{ + union i2c_smbus_data data; + + if (i2c_smbus_xfer(client->adapter, client->addr, client->flags, + I2C_SMBUS_READ, command, + I2C_SMBUS_BLOCK_DATA, &data)) + return -1; + + memcpy(values, &data.block[1], data.block[0]); + return data.block[0]; +} +EXPORT_SYMBOL(i2c_smbus_read_block_data); s32 i2c_smbus_write_block_data(struct i2c_client *client, u8 command, u8 length, const u8 *values) @@ -1007,6 +1327,7 @@ s32 i2c_smbus_write_block_data(struct i2c_client *client, u8 command, I2C_SMBUS_WRITE,command, I2C_SMBUS_BLOCK_DATA,&data); } +EXPORT_SYMBOL(i2c_smbus_write_block_data); /* Returns the number of read bytes */ s32 i2c_smbus_read_i2c_block_data(struct i2c_client *client, u8 command, u8 *values) @@ -1021,6 +1342,7 @@ s32 i2c_smbus_read_i2c_block_data(struct i2c_client *client, u8 command, u8 *val memcpy(values, &data.block[1], data.block[0]); return data.block[0]; } +EXPORT_SYMBOL(i2c_smbus_read_i2c_block_data); s32 i2c_smbus_write_i2c_block_data(struct i2c_client *client, u8 command, u8 length, const u8 *values) @@ -1035,6 +1357,7 @@ s32 i2c_smbus_write_i2c_block_data(struct i2c_client *client, u8 command, I2C_SMBUS_WRITE, command, I2C_SMBUS_I2C_BLOCK_DATA, &data); } +EXPORT_SYMBOL(i2c_smbus_write_i2c_block_data); /* Simulate a SMBus command using the i2c protocol No checking of parameters is done! */ @@ -1098,9 +1421,9 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr, break; case I2C_SMBUS_BLOCK_DATA: if (read_write == I2C_SMBUS_READ) { - dev_err(&adapter->dev, "Block read not supported " - "under I2C emulation!\n"); - return -1; + msg[1].flags |= I2C_M_RECV_LEN; + msg[1].len = 1; /* block length will be added by + the underlying bus driver */ } else { msg[0].len = data->block[0] + 2; if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 2) { @@ -1114,9 +1437,21 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr, } break; case I2C_SMBUS_BLOCK_PROC_CALL: - dev_dbg(&adapter->dev, "Block process call not supported " - "under I2C emulation!\n"); - return -1; + num = 2; /* Another special case */ + read_write = I2C_SMBUS_READ; + if (data->block[0] > I2C_SMBUS_BLOCK_MAX) { + dev_err(&adapter->dev, "%s called with invalid " + "block proc call size (%d)\n", __FUNCTION__, + data->block[0]); + return -1; + } + msg[0].len = data->block[0] + 2; + for (i = 1; i < msg[0].len; i++) + msgbuf0[i] = data->block[i-1]; + msg[1].flags |= I2C_M_RECV_LEN; + msg[1].len = 1; /* block length will be added by + the underlying bus driver */ + break; case I2C_SMBUS_I2C_BLOCK_DATA: if (read_write == I2C_SMBUS_READ) { msg[1].len = I2C_SMBUS_BLOCK_MAX; @@ -1180,6 +1515,11 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr, for (i = 0; i < I2C_SMBUS_BLOCK_MAX; i++) data->block[i+1] = msgbuf1[i]; break; + case I2C_SMBUS_BLOCK_DATA: + case I2C_SMBUS_BLOCK_PROC_CALL: + for (i = 0; i < msgbuf1[0] + 1; i++) + data->block[i] = msgbuf1[i]; + break; } return 0; } @@ -1204,43 +1544,7 @@ s32 i2c_smbus_xfer(struct i2c_adapter * adapter, u16 addr, unsigned short flags, return res; } - - -/* Next four are needed by i2c-isa */ -EXPORT_SYMBOL_GPL(i2c_adapter_dev_release); -EXPORT_SYMBOL_GPL(i2c_adapter_driver); -EXPORT_SYMBOL_GPL(i2c_adapter_class); -EXPORT_SYMBOL_GPL(i2c_bus_type); - -EXPORT_SYMBOL(i2c_add_adapter); -EXPORT_SYMBOL(i2c_del_adapter); -EXPORT_SYMBOL(i2c_del_driver); -EXPORT_SYMBOL(i2c_attach_client); -EXPORT_SYMBOL(i2c_detach_client); -EXPORT_SYMBOL(i2c_use_client); -EXPORT_SYMBOL(i2c_release_client); -EXPORT_SYMBOL(i2c_clients_command); -EXPORT_SYMBOL(i2c_check_addr); - -EXPORT_SYMBOL(i2c_master_send); -EXPORT_SYMBOL(i2c_master_recv); -EXPORT_SYMBOL(i2c_control); -EXPORT_SYMBOL(i2c_transfer); -EXPORT_SYMBOL(i2c_get_adapter); -EXPORT_SYMBOL(i2c_put_adapter); -EXPORT_SYMBOL(i2c_probe); - EXPORT_SYMBOL(i2c_smbus_xfer); -EXPORT_SYMBOL(i2c_smbus_write_quick); -EXPORT_SYMBOL(i2c_smbus_read_byte); -EXPORT_SYMBOL(i2c_smbus_write_byte); -EXPORT_SYMBOL(i2c_smbus_read_byte_data); -EXPORT_SYMBOL(i2c_smbus_write_byte_data); -EXPORT_SYMBOL(i2c_smbus_read_word_data); -EXPORT_SYMBOL(i2c_smbus_write_word_data); -EXPORT_SYMBOL(i2c_smbus_write_block_data); -EXPORT_SYMBOL(i2c_smbus_read_i2c_block_data); -EXPORT_SYMBOL(i2c_smbus_write_i2c_block_data); MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>"); MODULE_DESCRIPTION("I2C-Bus main module"); diff --git a/drivers/i2c/i2c-core.h b/drivers/i2c/i2c-core.h new file mode 100644 index 00000000000..cd5bff87485 --- /dev/null +++ b/drivers/i2c/i2c-core.h @@ -0,0 +1,31 @@ +/* + * i2c-core.h - interfaces internal to the I2C framework + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +struct i2c_devinfo { + struct list_head list; + int busnum; + struct i2c_board_info board_info; +}; + +/* board_lock protects board_list and first_dynamic_bus_num. + * only i2c core components are allowed to use these symbols. + */ +extern struct mutex __i2c_board_lock; +extern struct list_head __i2c_board_list; +extern int __i2c_first_dynamic_bus_num; + diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index f17e9c7d4b3..c845d5c4cbb 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -164,6 +164,17 @@ config KEYBOARD_AMIGA To compile this driver as a module, choose M here: the module will be called amikbd. +config KEYBOARD_ATARI + tristate "Atari keyboard" + depends on ATARI + select ATARI_KBD_CORE + help + Say Y here if you are running Linux on any Atari and have a keyboard + attached. + + To compile this driver as a module, choose M here: the + module will be called atakbd. + config KEYBOARD_HIL_OLD tristate "HP HIL keyboard support (simple driver)" depends on GSC || HP300 diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index 586a0fe53be..7aa59ee5a0b 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o obj-$(CONFIG_KEYBOARD_LKKBD) += lkkbd.o obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o +obj-$(CONFIG_KEYBOARD_ATARI) += atakbd.o obj-$(CONFIG_KEYBOARD_LOCOMO) += locomokbd.o obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o diff --git a/drivers/input/keyboard/atakbd.c b/drivers/input/keyboard/atakbd.c new file mode 100644 index 00000000000..ded1d6ac6ff --- /dev/null +++ b/drivers/input/keyboard/atakbd.c @@ -0,0 +1,134 @@ +/* + * atakbd.c + * + * Copyright (c) 2005 Michael Schmitz + * + * Based on amikbd.c, which is + * + * Copyright (c) 2000-2001 Vojtech Pavlik + * + * Based on the work of: + * Hamish Macdonald + */ + +/* + * Atari keyboard driver for Linux/m68k + * + * The low level init and interrupt stuff is handled in arch/mm68k/atari/atakeyb.c + * (the keyboard ACIA also handles the mouse and joystick data, and the keyboard + * interrupt is shared with the MIDI ACIA so MIDI data also get handled there). + * This driver only deals with handing key events off to the input layer. + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/input.h> +#include <linux/delay.h> +#include <linux/interrupt.h> + +#include <asm/atariints.h> +#include <asm/atarihw.h> +#include <asm/atarikb.h> +#include <asm/irq.h> + +MODULE_AUTHOR("Michael Schmitz <schmitz@biophys.uni-duesseldorf.de>"); +MODULE_DESCRIPTION("Atari keyboard driver"); +MODULE_LICENSE("GPL"); + +static unsigned char atakbd_keycode[0x72]; + +static struct input_dev *atakbd_dev; + +static void atakbd_interrupt(unsigned char scancode, char down) +{ + + if (scancode < 0x72) { /* scancodes < 0xf2 are keys */ + + // report raw events here? + + scancode = atakbd_keycode[scancode]; + + if (scancode == KEY_CAPSLOCK) { /* CapsLock is a toggle switch key on Amiga */ + input_report_key(atakbd_dev, scancode, 1); + input_report_key(atakbd_dev, scancode, 0); + input_sync(atakbd_dev); + } else { + input_report_key(atakbd_dev, scancode, down); + input_sync(atakbd_dev); + } + } else /* scancodes >= 0xf2 are mouse data, most likely */ + printk(KERN_INFO "atakbd: unhandled scancode %x\n", scancode); + + return; +} + +static int __init atakbd_init(void) +{ + int i; + + if (!ATARIHW_PRESENT(ST_MFP)) + return -EIO; + + // TODO: request_mem_region if not done in arch code + + if (!(atakbd_dev = input_allocate_device())) + return -ENOMEM; + + // need to init core driver if not already done so + if (atari_keyb_init()) + return -ENODEV; + + atakbd_dev->name = "Atari Keyboard"; + atakbd_dev->phys = "atakbd/input0"; + atakbd_dev->id.bustype = BUS_ATARI; + atakbd_dev->id.vendor = 0x0001; + atakbd_dev->id.product = 0x0001; + atakbd_dev->id.version = 0x0100; + + atakbd_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP); + atakbd_dev->keycode = atakbd_keycode; + atakbd_dev->keycodesize = sizeof(unsigned char); + atakbd_dev->keycodemax = ARRAY_SIZE(atakbd_keycode); + + for (i = 1; i < 0x72; i++) { + atakbd_keycode[i] = i; + set_bit(atakbd_keycode[i], atakbd_dev->keybit); + } + + input_register_device(atakbd_dev); + + atari_input_keyboard_interrupt_hook = atakbd_interrupt; + + printk(KERN_INFO "input: %s at IKBD ACIA\n", atakbd_dev->name); + + return 0; +} + +static void __exit atakbd_exit(void) +{ + atari_input_keyboard_interrupt_hook = NULL; + input_unregister_device(atakbd_dev); +} + +module_init(atakbd_init); +module_exit(atakbd_exit); diff --git a/drivers/input/keyboard/hilkbd.c b/drivers/input/keyboard/hilkbd.c index 4de4dc297d5..56277fb291c 100644 --- a/drivers/input/keyboard/hilkbd.c +++ b/drivers/input/keyboard/hilkbd.c @@ -52,7 +52,7 @@ MODULE_LICENSE("GPL v2"); #elif defined(CONFIG_HP300) - #define HILBASE 0xf0428000 /* HP300 (m86k) port address */ + #define HILBASE 0xf0428000UL /* HP300 (m68k) port address */ #define HIL_DATA 0x1 #define HIL_CMD 0x3 #define HIL_IRQ 2 diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig index 35d998c3e57..b40784a60aa 100644 --- a/drivers/input/mouse/Kconfig +++ b/drivers/input/mouse/Kconfig @@ -96,6 +96,17 @@ config MOUSE_AMIGA To compile this driver as a module, choose M here: the module will be called amimouse. +config MOUSE_ATARI + tristate "Atari mouse" + depends on ATARI + select ATARI_KBD_CORE + help + Say Y here if you have an Atari and want its native mouse + supported by the kernel. + + To compile this driver as a module, choose M here: the + module will be called atarimouse. + config MOUSE_RISCPC tristate "Acorn RiscPC mouse" depends on ARCH_ACORN diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile index 21a1de61a79..700f61200df 100644 --- a/drivers/input/mouse/Makefile +++ b/drivers/input/mouse/Makefile @@ -5,6 +5,7 @@ # Each configuration option enables a list of files. obj-$(CONFIG_MOUSE_AMIGA) += amimouse.o +obj-$(CONFIG_MOUSE_ATARI) += atarimouse.o obj-$(CONFIG_MOUSE_RISCPC) += rpcmouse.o obj-$(CONFIG_MOUSE_INPORT) += inport.o obj-$(CONFIG_MOUSE_LOGIBM) += logibm.o diff --git a/drivers/input/mouse/atarimouse.c b/drivers/input/mouse/atarimouse.c new file mode 100644 index 00000000000..43ab6566fb6 --- /dev/null +++ b/drivers/input/mouse/atarimouse.c @@ -0,0 +1,160 @@ +/* + * Atari mouse driver for Linux/m68k + * + * Copyright (c) 2005 Michael Schmitz + * + * Based on: + * Amiga mouse driver for Linux/m68k + * + * Copyright (c) 2000-2002 Vojtech Pavlik + * + */ +/* + * The low level init and interrupt stuff is handled in arch/mm68k/atari/atakeyb.c + * (the keyboard ACIA also handles the mouse and joystick data, and the keyboard + * interrupt is shared with the MIDI ACIA so MIDI data also get handled there). + * This driver only deals with handing key events off to the input layer. + * + * Largely based on the old: + * + * Atari Mouse Driver for Linux + * by Robert de Vries (robert@and.nl) 19Jul93 + * + * 16 Nov 1994 Andreas Schwab + * Compatibility with busmouse + * Support for three button mouse (shamelessly stolen from MiNT) + * third button wired to one of the joystick directions on joystick 1 + * + * 1996/02/11 Andreas Schwab + * Module support + * Allow multiple open's + * + * Converted to use new generic busmouse code. 5 Apr 1998 + * Russell King <rmk@arm.uk.linux.org> + */ + + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/input.h> +#include <linux/interrupt.h> + +#include <asm/irq.h> +#include <asm/setup.h> +#include <asm/system.h> +#include <asm/uaccess.h> +#include <asm/atarihw.h> +#include <asm/atarikb.h> +#include <asm/atariints.h> + +MODULE_AUTHOR("Michael Schmitz <schmitz@biophys.uni-duesseldorf.de>"); +MODULE_DESCRIPTION("Atari mouse driver"); +MODULE_LICENSE("GPL"); + +static int mouse_threshold[2] = {2,2}; + +#ifdef __MODULE__ +MODULE_PARM(mouse_threshold, "2i"); +#endif +#ifdef FIXED_ATARI_JOYSTICK +extern int atari_mouse_buttons; +#endif +static int atamouse_used = 0; + +static struct input_dev *atamouse_dev; + +static void atamouse_interrupt(char *buf) +{ + int buttons, dx, dy; + +/* ikbd_mouse_disable(); */ + + buttons = (buf[0] & 1) | ((buf[0] & 2) << 1); +#ifdef FIXED_ATARI_JOYSTICK + buttons |= atari_mouse_buttons & 2; + atari_mouse_buttons = buttons; +#endif +/* ikbd_mouse_rel_pos(); */ + + /* only relative events get here */ + dx = buf[1]; + dy = -buf[2]; + + input_report_rel(atamouse_dev, REL_X, dx); + input_report_rel(atamouse_dev, REL_Y, dy); + + input_report_key(atamouse_dev, BTN_LEFT, buttons & 0x1); + input_report_key(atamouse_dev, BTN_MIDDLE, buttons & 0x2); + input_report_key(atamouse_dev, BTN_RIGHT, buttons & 0x4); + + input_sync(atamouse_dev); + + return; +} + +static int atamouse_open(struct input_dev *dev) +{ + if (atamouse_used++) + return 0; + +#ifdef FIXED_ATARI_JOYSTICK + atari_mouse_buttons = 0; +#endif + ikbd_mouse_y0_top(); + ikbd_mouse_thresh(mouse_threshold[0], mouse_threshold[1]); + ikbd_mouse_rel_pos(); + atari_input_mouse_interrupt_hook = atamouse_interrupt; + return 0; +} + +static void atamouse_close(struct input_dev *dev) +{ + if (!--atamouse_used) { + ikbd_mouse_disable(); + atari_mouse_interrupt_hook = NULL; + } +} + +static int __init atamouse_init(void) +{ + if (!MACH_IS_ATARI || !ATARIHW_PRESENT(ST_MFP)) + return -ENODEV; + + if (!(atamouse_dev = input_allocate_device())) + return -ENOMEM; + + if (!(atari_keyb_init())) + return -ENODEV; + + atamouse_dev->name = "Atari mouse"; + atamouse_dev->phys = "atamouse/input0"; + atamouse_dev->id.bustype = BUS_ATARI; + atamouse_dev->id.vendor = 0x0001; + atamouse_dev->id.product = 0x0002; + atamouse_dev->id.version = 0x0100; + + atamouse_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL); + atamouse_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y); + atamouse_dev->keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); + atamouse_dev->open = atamouse_open; + atamouse_dev->close = atamouse_close; + + input_register_device(atamouse_dev); + + printk(KERN_INFO "input: %s at keyboard ACIA\n", atamouse_dev->name); + return 0; +} + +static void __exit atamouse_exit(void) +{ + input_unregister_device(atamouse_dev); +} + +module_init(atamouse_init); +module_exit(atamouse_exit); diff --git a/drivers/macintosh/therm_windtunnel.c b/drivers/macintosh/therm_windtunnel.c index 35233de460a..3d0354e96a9 100644 --- a/drivers/macintosh/therm_windtunnel.c +++ b/drivers/macintosh/therm_windtunnel.c @@ -459,7 +459,8 @@ therm_of_probe( struct of_device *dev, const struct of_device_id *match ) static int therm_of_remove( struct of_device *dev ) { - return i2c_del_driver( &g4fan_driver ); + i2c_del_driver( &g4fan_driver ); + return 0; } static struct of_device_id therm_of_match[] = {{ diff --git a/drivers/macintosh/via-cuda.c b/drivers/macintosh/via-cuda.c index 76d21775fc3..741a93a3eb6 100644 --- a/drivers/macintosh/via-cuda.c +++ b/drivers/macintosh/via-cuda.c @@ -82,6 +82,7 @@ static unsigned char cuda_rbuf[16]; static unsigned char *reply_ptr; static int reading_reply; static int data_index; +static int cuda_irq; #ifdef CONFIG_PPC static struct device_node *vias; #endif @@ -160,10 +161,8 @@ int __init find_via_cuda(void) /* Clear and enable interrupts, but only on PPC. On 68K it's done */ /* for us by the main VIA driver in arch/m68k/mac/via.c */ -#ifndef CONFIG_MAC out_8(&via[IFR], 0x7f); /* clear interrupts by writing 1s */ out_8(&via[IER], IER_SET|SR_INT); /* enable interrupt from SR */ -#endif /* enable autopoll */ cuda_request(&req, NULL, 3, CUDA_PACKET, CUDA_AUTOPOLL, 1); @@ -181,24 +180,22 @@ int __init find_via_cuda(void) static int __init via_cuda_start(void) { - unsigned int irq; - if (via == NULL) return -ENODEV; #ifdef CONFIG_MAC - irq = IRQ_MAC_ADB; + cuda_irq = IRQ_MAC_ADB; #else /* CONFIG_MAC */ - irq = irq_of_parse_and_map(vias, 0); - if (irq == NO_IRQ) { + cuda_irq = irq_of_parse_and_map(vias, 0); + if (cuda_irq == NO_IRQ) { printk(KERN_ERR "via-cuda: can't map interrupts for %s\n", vias->full_name); return -ENODEV; } -#endif /* CONFIG_MAP */ +#endif /* CONFIG_MAC */ - if (request_irq(irq, cuda_interrupt, 0, "ADB", cuda_interrupt)) { - printk(KERN_ERR "via-cuda: can't request irq %d\n", irq); + if (request_irq(cuda_irq, cuda_interrupt, 0, "ADB", cuda_interrupt)) { + printk(KERN_ERR "via-cuda: can't request irq %d\n", cuda_irq); return -EAGAIN; } @@ -238,6 +235,7 @@ cuda_init(void) printk(KERN_ERR "cuda_init_via() failed\n"); return -ENODEV; } + out_8(&via[IER], IER_SET|SR_INT); /* enable interrupt from SR */ return via_cuda_start(); #endif @@ -263,15 +261,17 @@ cuda_init_via(void) out_8(&via[B], in_8(&via[B]) | TACK | TIP); /* negate them */ out_8(&via[ACR] ,(in_8(&via[ACR]) & ~SR_CTRL) | SR_EXT); /* SR data in */ (void)in_8(&via[SR]); /* clear any left-over data */ -#ifndef CONFIG_MAC +#ifdef CONFIG_PPC out_8(&via[IER], 0x7f); /* disable interrupts from VIA */ (void)in_8(&via[IER]); +#else + out_8(&via[IER], SR_INT); /* disable SR interrupt from VIA */ #endif /* delay 4ms and then clear any pending interrupt */ mdelay(4); (void)in_8(&via[SR]); - out_8(&via[IFR], in_8(&via[IFR]) & 0x7f); + out_8(&via[IFR], SR_INT); /* sync with the CUDA - assert TACK without TIP */ out_8(&via[B], in_8(&via[B]) & ~TACK); @@ -282,7 +282,7 @@ cuda_init_via(void) /* wait for the interrupt and then clear it */ WAIT_FOR(in_8(&via[IFR]) & SR_INT, "CUDA response to sync (2)"); (void)in_8(&via[SR]); - out_8(&via[IFR], in_8(&via[IFR]) & 0x7f); + out_8(&via[IFR], SR_INT); /* finish the sync by negating TACK */ out_8(&via[B], in_8(&via[B]) | TACK); @@ -291,7 +291,7 @@ cuda_init_via(void) WAIT_FOR(in_8(&via[B]) & TREQ, "CUDA response to sync (3)"); WAIT_FOR(in_8(&via[IFR]) & SR_INT, "CUDA response to sync (4)"); (void)in_8(&via[SR]); - out_8(&via[IFR], in_8(&via[IFR]) & 0x7f); + out_8(&via[IFR], SR_INT); out_8(&via[B], in_8(&via[B]) | TIP); /* should be unnecessary */ return 0; @@ -428,16 +428,12 @@ cuda_start(void) void cuda_poll(void) { - unsigned long flags; - /* cuda_interrupt only takes a normal lock, we disable * interrupts here to avoid re-entering and thus deadlocking. - * An option would be to disable only the IRQ source with - * disable_irq(), would that work on m68k ? --BenH */ - local_irq_save(flags); + disable_irq(cuda_irq); cuda_interrupt(0, NULL); - local_irq_restore(flags); + enable_irq(cuda_irq); } static irqreturn_t @@ -448,15 +444,25 @@ cuda_interrupt(int irq, void *arg) unsigned char ibuf[16]; int ibuf_len = 0; int complete = 0; - unsigned char virq; spin_lock(&cuda_lock); - virq = in_8(&via[IFR]) & 0x7f; - out_8(&via[IFR], virq); - if ((virq & SR_INT) == 0) { - spin_unlock(&cuda_lock); - return IRQ_NONE; + /* On powermacs, this handler is registered for the VIA IRQ. But it uses + * just the shift register IRQ -- other VIA interrupt sources are disabled. + * On m68k macs, the VIA IRQ sources are dispatched individually. Unless + * we are polling, the shift register IRQ flag has already been cleared. + */ + +#ifdef CONFIG_MAC + if (!arg) +#endif + { + if ((in_8(&via[IFR]) & SR_INT) == 0) { + spin_unlock(&cuda_lock); + return IRQ_NONE; + } else { + out_8(&via[IFR], SR_INT); + } } status = (~in_8(&via[B]) & (TIP|TREQ)) | (in_8(&via[ACR]) & SR_OUT); diff --git a/drivers/macintosh/via-macii.c b/drivers/macintosh/via-macii.c index 1b3bad62a1b..01b8eca7ccd 100644 --- a/drivers/macintosh/via-macii.c +++ b/drivers/macintosh/via-macii.c @@ -12,6 +12,15 @@ * 1999-08-02 (jmt) - Initial rewrite for Unified ADB. * 2000-03-29 Tony Mantler <tonym@mac.linux-m68k.org> * - Big overhaul, should actually work now. + * 2006-12-31 Finn Thain <fthain@telegraphics.com.au> - Another overhaul. + * + * Suggested reading: + * Inside Macintosh, ch. 5 ADB Manager + * Guide to the Macinstosh Family Hardware, ch. 8 Apple Desktop Bus + * Rockwell R6522 VIA datasheet + * + * Apple's "ADB Analyzer" bus sniffer is invaluable: + * ftp://ftp.apple.com/developer/Tool_Chest/Devices_-_Hardware/Apple_Desktop_Bus/ */ #include <stdarg.h> @@ -26,7 +35,6 @@ #include <asm/macints.h> #include <asm/machw.h> #include <asm/mac_via.h> -#include <asm/io.h> #include <asm/system.h> static volatile unsigned char *via; @@ -51,9 +59,7 @@ static volatile unsigned char *via; #define ANH (15*RS) /* A-side data, no handshake */ /* Bits in B data register: all active low */ -#define TREQ 0x08 /* Transfer request (input) */ -#define TACK 0x10 /* Transfer acknowledge (output) */ -#define TIP 0x20 /* Transfer in progress (output) */ +#define CTLR_IRQ 0x08 /* Controller rcv status (input) */ #define ST_MASK 0x30 /* mask for selecting ADB state bits */ /* Bits in ACR */ @@ -65,8 +71,6 @@ static volatile unsigned char *via; #define IER_SET 0x80 /* set bits in IER */ #define IER_CLR 0 /* clear bits in IER */ #define SR_INT 0x04 /* Shift register full/empty */ -#define SR_DATA 0x08 /* Shift register data */ -#define SR_CLOCK 0x10 /* Shift register clock */ /* ADB transaction states according to GMHW */ #define ST_CMD 0x00 /* ADB state: command byte */ @@ -77,7 +81,6 @@ static volatile unsigned char *via; static int macii_init_via(void); static void macii_start(void); static irqreturn_t macii_interrupt(int irq, void *arg); -static void macii_retransmit(int); static void macii_queue_poll(void); static int macii_probe(void); @@ -103,29 +106,37 @@ static enum macii_state { sending, reading, read_done, - awaiting_reply } macii_state; -static int need_poll; -static int command_byte; -static int last_reply; -static int last_active; - -static struct adb_request *current_req; -static struct adb_request *last_req; -static struct adb_request *retry_req; -static unsigned char reply_buf[16]; -static unsigned char *reply_ptr; -static int reply_len; -static int reading_reply; -static int data_index; -static int first_byte; -static int prefix_len; -static int status = ST_IDLE|TREQ; -static int last_status; -static int driver_running; - -/* debug level 10 required for ADB logging (should be && debug_adb, ideally) */ +static struct adb_request *current_req; /* first request struct in the queue */ +static struct adb_request *last_req; /* last request struct in the queue */ +static unsigned char reply_buf[16]; /* storage for autopolled replies */ +static unsigned char *reply_ptr; /* next byte in req->data or reply_buf */ +static int reading_reply; /* store reply in reply_buf else req->reply */ +static int data_index; /* index of the next byte to send from req->data */ +static int reply_len; /* number of bytes received in reply_buf or req->reply */ +static int status; /* VIA's ADB status bits captured upon interrupt */ +static int last_status; /* status bits as at previous interrupt */ +static int srq_asserted; /* have to poll for the device that asserted it */ +static int command_byte; /* the most recent command byte transmitted */ +static int autopoll_devs; /* bits set are device addresses to be polled */ + +/* Sanity check for request queue. Doesn't check for cycles. */ +static int request_is_queued(struct adb_request *req) { + struct adb_request *cur; + unsigned long flags; + local_irq_save(flags); + cur = current_req; + while (cur) { + if (cur == req) { + local_irq_restore(flags); + return 1; + } + cur = cur->next; + } + local_irq_restore(flags); + return 0; +} /* Check for MacII style ADB */ static int macii_probe(void) @@ -147,15 +158,16 @@ int macii_init(void) local_irq_save(flags); err = macii_init_via(); - if (err) return err; + if (err) goto out; err = request_irq(IRQ_MAC_ADB, macii_interrupt, IRQ_FLG_LOCK, "ADB", macii_interrupt); - if (err) return err; + if (err) goto out; macii_state = idle; +out: local_irq_restore(flags); - return 0; + return err; } /* initialize the hardware */ @@ -163,12 +175,12 @@ static int macii_init_via(void) { unsigned char x; - /* Set the lines up. We want TREQ as input TACK|TIP as output */ - via[DIRB] = (via[DIRB] | TACK | TIP) & ~TREQ; + /* We want CTLR_IRQ as input and ST_EVEN | ST_ODD as output lines. */ + via[DIRB] = (via[DIRB] | ST_EVEN | ST_ODD) & ~CTLR_IRQ; /* Set up state: idle */ via[B] |= ST_IDLE; - last_status = via[B] & (ST_MASK|TREQ); + last_status = via[B] & (ST_MASK|CTLR_IRQ); /* Shift register on input */ via[ACR] = (via[ACR] & ~SR_CTRL) | SR_EXT; @@ -179,81 +191,72 @@ static int macii_init_via(void) return 0; } -/* Send an ADB poll (Talk Register 0 command, tagged on the front of the request queue) */ +/* Send an ADB poll (Talk Register 0 command prepended to the request queue) */ static void macii_queue_poll(void) { - static int device = 0; - static int in_poll=0; + /* No point polling the active device as it will never assert SRQ, so + * poll the next device in the autopoll list. This could leave us + * stuck in a polling loop if an unprobed device is asserting SRQ. + * In theory, that could only happen if a device was plugged in after + * probing started. Unplugging it again will break the cycle. + * (Simply polling the next higher device often ends up polling almost + * every device (after wrapping around), which takes too long.) + */ + int device_mask; + int next_device; static struct adb_request req; - unsigned long flags; - - if (in_poll) printk("macii_queue_poll: double poll!\n"); - - in_poll++; - if (++device > 15) device = 1; - - adb_request(&req, NULL, ADBREQ_REPLY|ADBREQ_NOSEND, 1, - ADB_READREG(device, 0)); - - local_irq_save(flags); - - req.next = current_req; - current_req = &req; - local_irq_restore(flags); - macii_start(); - in_poll--; -} + if (!autopoll_devs) return; -/* Send an ADB retransmit (Talk, appended to the request queue) */ -static void macii_retransmit(int device) -{ - static int in_retransmit = 0; - static struct adb_request rt; - unsigned long flags; - - if (in_retransmit) printk("macii_retransmit: double retransmit!\n"); + device_mask = (1 << (((command_byte & 0xF0) >> 4) + 1)) - 1; + if (autopoll_devs & ~device_mask) + next_device = ffs(autopoll_devs & ~device_mask) - 1; + else + next_device = ffs(autopoll_devs) - 1; - in_retransmit++; + BUG_ON(request_is_queued(&req)); - adb_request(&rt, NULL, ADBREQ_REPLY|ADBREQ_NOSEND, 1, - ADB_READREG(device, 0)); + adb_request(&req, NULL, ADBREQ_NOSEND, 1, + ADB_READREG(next_device, 0)); - local_irq_save(flags); + req.sent = 0; + req.complete = 0; + req.reply_len = 0; + req.next = current_req; if (current_req != NULL) { - last_req->next = &rt; - last_req = &rt; + current_req = &req; } else { - current_req = &rt; - last_req = &rt; + current_req = &req; + last_req = &req; } - - if (macii_state == idle) macii_start(); - - local_irq_restore(flags); - in_retransmit--; } /* Send an ADB request; if sync, poll out the reply 'till it's done */ static int macii_send_request(struct adb_request *req, int sync) { - int i; + int err; + unsigned long flags; - i = macii_write(req); - if (i) return i; + BUG_ON(request_is_queued(req)); - if (sync) { - while (!req->complete) macii_poll(); + local_irq_save(flags); + err = macii_write(req); + local_irq_restore(flags); + + if (!err && sync) { + while (!req->complete) { + macii_poll(); + } + BUG_ON(request_is_queued(req)); } - return 0; + + return err; } -/* Send an ADB request */ +/* Send an ADB request (append to request queue) */ static int macii_write(struct adb_request *req) { - unsigned long flags; - if (req->nbytes < 2 || req->data[0] != ADB_PACKET || req->nbytes > 15) { req->complete = 1; return -EINVAL; @@ -264,8 +267,6 @@ static int macii_write(struct adb_request *req) req->complete = 0; req->reply_len = 0; - local_irq_save(flags); - if (current_req != NULL) { last_req->next = req; last_req = req; @@ -274,28 +275,52 @@ static int macii_write(struct adb_request *req) last_req = req; if (macii_state == idle) macii_start(); } - - local_irq_restore(flags); return 0; } /* Start auto-polling */ static int macii_autopoll(int devs) { - /* Just ping a random default address */ - if (!(current_req || retry_req)) - macii_retransmit( (last_active < 16 && last_active > 0) ? last_active : 3); - return 0; + static struct adb_request req; + unsigned long flags; + int err = 0; + + /* bit 1 == device 1, and so on. */ + autopoll_devs = devs & 0xFFFE; + + if (!autopoll_devs) return 0; + + local_irq_save(flags); + + if (current_req == NULL) { + /* Send a Talk Reg 0. The controller will repeatedly transmit + * this as long as it is idle. + */ + adb_request(&req, NULL, ADBREQ_NOSEND, 1, + ADB_READREG(ffs(autopoll_devs) - 1, 0)); + err = macii_write(&req); + } + + local_irq_restore(flags); + return err; +} + +static inline int need_autopoll(void) { + /* Was the last command Talk Reg 0 + * and is the target on the autopoll list? + */ + if ((command_byte & 0x0F) == 0x0C && + ((1 << ((command_byte & 0xF0) >> 4)) & autopoll_devs)) + return 0; + return 1; } /* Prod the chip without interrupts */ static void macii_poll(void) { - unsigned long flags; - - local_irq_save(flags); - if (via[IFR] & SR_INT) macii_interrupt(0, NULL); - local_irq_restore(flags); + disable_irq(IRQ_MAC_ADB); + macii_interrupt(0, NULL); + enable_irq(IRQ_MAC_ADB); } /* Reset the bus */ @@ -303,73 +328,34 @@ static int macii_reset_bus(void) { static struct adb_request req; + if (request_is_queued(&req)) + return 0; + /* Command = 0, Address = ignored */ adb_request(&req, NULL, 0, 1, ADB_BUSRESET); + /* Don't want any more requests during the Global Reset low time. */ + udelay(3000); + return 0; } /* Start sending ADB packet */ static void macii_start(void) { - unsigned long flags; struct adb_request *req; req = current_req; - if (!req) return; - - /* assert macii_state == idle */ - if (macii_state != idle) { - printk("macii_start: called while driver busy (%p %x %x)!\n", - req, macii_state, (uint) via1[B] & (ST_MASK|TREQ)); - return; - } - local_irq_save(flags); - - /* - * IRQ signaled ?? (means ADB controller wants to send, or might - * be end of packet if we were reading) - */ -#if 0 /* FIXME: This is broke broke broke, for some reason */ - if ((via[B] & TREQ) == 0) { - printk("macii_start: weird poll stuff. huh?\n"); - /* - * FIXME - we need to restart this on a timer - * or a collision at boot hangs us. - * Never set macii_state to idle here, or macii_start - * won't be called again from send_request! - * (need to re-check other cases ...) - */ - /* - * if the interrupt handler set the need_poll - * flag, it's hopefully a SRQ poll or re-Talk - * so we try to send here anyway - */ - if (!need_poll) { - if (console_loglevel == 10) - printk("macii_start: device busy - retry %p state %d status %x!\n", - req, macii_state, - (uint) via[B] & (ST_MASK|TREQ)); - retry_req = req; - /* set ADB status here ? */ - local_irq_restore(flags); - return; - } else { - need_poll = 0; - } - } -#endif - /* - * Another retry pending? (sanity check) + BUG_ON(req == NULL); + + BUG_ON(macii_state != idle); + + /* Now send it. Be careful though, that first byte of the request + * is actually ADB_PACKET; the real data begins at index 1! + * And req->nbytes is the number of bytes of real data plus one. */ - if (retry_req) { - retry_req = NULL; - } - /* Now send it. Be careful though, that first byte of the request */ - /* is actually ADB_PACKET; the real data begins at index 1! */ - /* store command byte */ command_byte = req->data[1]; /* Output mode */ @@ -381,115 +367,97 @@ static void macii_start(void) macii_state = sending; data_index = 2; - - local_irq_restore(flags); } /* - * The notorious ADB interrupt handler - does all of the protocol handling, - * except for starting new send operations. Relies heavily on the ADB - * controller sending and receiving data, thereby generating SR interrupts - * for us. This means there has to be always activity on the ADB bus, otherwise - * the whole process dies and has to be re-kicked by sending TALK requests ... - * CUDA-based Macs seem to solve this with the autopoll option, for MacII-type - * ADB the problem isn't solved yet (retransmit of the latest active TALK seems - * a good choice; either on timeout or on a timer interrupt). + * The notorious ADB interrupt handler - does all of the protocol handling. + * Relies on the ADB controller sending and receiving data, thereby + * generating shift register interrupts (SR_INT) for us. This means there has + * to be activity on the ADB bus. The chip will poll to achieve this. * * The basic ADB state machine was left unchanged from the original MacII code * by Alan Cox, which was based on the CUDA driver for PowerMac. - * The syntax of the ADB status lines seems to be totally different on MacII, - * though. MacII uses the states Command -> Even -> Odd -> Even ->...-> Idle for - * sending, and Idle -> Even -> Odd -> Even ->...-> Idle for receiving. Start - * and end of a receive packet are signaled by asserting /IRQ on the interrupt - * line. Timeouts are signaled by a sequence of 4 0xFF, with /IRQ asserted on - * every other byte. SRQ is probably signaled by 3 or more 0xFF tacked on the - * end of a packet. (Thanks to Guido Koerber for eavesdropping on the ADB - * protocol with a logic analyzer!!) - * - * Note: As of 21/10/97, the MacII ADB part works including timeout detection - * and retransmit (Talk to the last active device). + * The syntax of the ADB status lines is totally different on MacII, + * though. MacII uses the states Command -> Even -> Odd -> Even ->...-> Idle + * for sending and Idle -> Even -> Odd -> Even ->...-> Idle for receiving. + * Start and end of a receive packet are signalled by asserting /IRQ on the + * interrupt line (/IRQ means the CTLR_IRQ bit in port B; not to be confused + * with the VIA shift register interrupt. /IRQ never actually interrupts the + * processor, it's just an ordinary input.) */ static irqreturn_t macii_interrupt(int irq, void *arg) { - int x, adbdir; - unsigned long flags; + int x; + static int entered; struct adb_request *req; - last_status = status; - - /* prevent races due to SCSI enabling ints */ - local_irq_save(flags); - - if (driver_running) { - local_irq_restore(flags); - return IRQ_NONE; + if (!arg) { + /* Clear the SR IRQ flag when polling. */ + if (via[IFR] & SR_INT) + via[IFR] = SR_INT; + else + return IRQ_NONE; } - driver_running = 1; - - status = via[B] & (ST_MASK|TREQ); - adbdir = via[ACR] & SR_OUT; + BUG_ON(entered++); + + last_status = status; + status = via[B] & (ST_MASK|CTLR_IRQ); switch (macii_state) { case idle: + if (reading_reply) { + reply_ptr = current_req->reply; + } else { + BUG_ON(current_req != NULL); + reply_ptr = reply_buf; + } + x = via[SR]; - first_byte = x; - /* set ADB state = even for first data byte */ - via[B] = (via[B] & ~ST_MASK) | ST_EVEN; - reply_buf[0] = first_byte; /* was command_byte?? */ - reply_ptr = reply_buf + 1; - reply_len = 1; - prefix_len = 1; - reading_reply = 0; - - macii_state = reading; - break; + if ((status & CTLR_IRQ) && (x == 0xFF)) { + /* Bus timeout without SRQ sequence: + * data is "FF" while CTLR_IRQ is "H" + */ + reply_len = 0; + srq_asserted = 0; + macii_state = read_done; + } else { + macii_state = reading; + *reply_ptr = x; + reply_len = 1; + } - case awaiting_reply: - /* handshake etc. for II ?? */ - x = via[SR]; - first_byte = x; /* set ADB state = even for first data byte */ via[B] = (via[B] & ~ST_MASK) | ST_EVEN; - - current_req->reply[0] = first_byte; - reply_ptr = current_req->reply + 1; - reply_len = 1; - prefix_len = 1; - reading_reply = 1; - - macii_state = reading; break; case sending: req = current_req; if (data_index >= req->nbytes) { - /* print an error message if a listen command has no data */ - if (((command_byte & 0x0C) == 0x08) - /* && (console_loglevel == 10) */ - && (data_index == 2)) - printk("MacII ADB: listen command with no data: %x!\n", - command_byte); - /* reset to shift in */ - via[ACR] &= ~SR_OUT; - x = via[SR]; - /* set ADB state idle - might get SRQ */ - via[B] = (via[B] & ~ST_MASK) | ST_IDLE; - req->sent = 1; + macii_state = idle; if (req->reply_expected) { - macii_state = awaiting_reply; + reading_reply = 1; } else { req->complete = 1; current_req = req->next; if (req->done) (*req->done)(req); - macii_state = idle; - if (current_req || retry_req) + + if (current_req) macii_start(); else - macii_retransmit((command_byte & 0xF0) >> 4); + if (need_autopoll()) + macii_autopoll(autopoll_devs); + } + + if (macii_state == idle) { + /* reset to shift in */ + via[ACR] &= ~SR_OUT; + x = via[SR]; + /* set ADB state idle - might get SRQ */ + via[B] = (via[B] & ~ST_MASK) | ST_IDLE; } } else { via[SR] = req->data[data_index++]; @@ -505,147 +473,79 @@ static irqreturn_t macii_interrupt(int irq, void *arg) break; case reading: + x = via[SR]; + BUG_ON((status & ST_MASK) == ST_CMD || + (status & ST_MASK) == ST_IDLE); + + /* Bus timeout with SRQ sequence: + * data is "XX FF" while CTLR_IRQ is "L L" + * End of packet without SRQ sequence: + * data is "XX...YY 00" while CTLR_IRQ is "L...H L" + * End of packet SRQ sequence: + * data is "XX...YY 00" while CTLR_IRQ is "L...L L" + * (where XX is the first response byte and + * YY is the last byte of valid response data.) + */ - /* timeout / SRQ handling for II hw */ - if( (first_byte == 0xFF && (reply_len-prefix_len)==2 - && memcmp(reply_ptr-2,"\xFF\xFF",2)==0) || - ((reply_len-prefix_len)==3 - && memcmp(reply_ptr-3,"\xFF\xFF\xFF",3)==0)) - { - /* - * possible timeout (in fact, most probably a - * timeout, since SRQ can't be signaled without - * transfer on the bus). - * The last three bytes seen were FF, together - * with the starting byte (in case we started - * on 'idle' or 'awaiting_reply') this probably - * makes four. So this is mostl likely #5! - * The timeout signal is a pattern 1 0 1 0 0.. - * on /INT, meaning we missed it :-( - */ - x = via[SR]; - if (x != 0xFF) printk("MacII ADB: mistaken timeout/SRQ!\n"); - - if ((status & TREQ) == (last_status & TREQ)) { - /* Not a timeout. Unsolicited SRQ? weird. */ - /* Terminate the SRQ packet and poll */ - need_poll = 1; + srq_asserted = 0; + if (!(status & CTLR_IRQ)) { + if (x == 0xFF) { + if (!(last_status & CTLR_IRQ)) { + macii_state = read_done; + reply_len = 0; + srq_asserted = 1; + } + } else if (x == 0x00) { + macii_state = read_done; + if (!(last_status & CTLR_IRQ)) + srq_asserted = 1; } - /* There's no packet to get, so reply is blank */ - via[B] ^= ST_MASK; - reply_ptr -= (reply_len-prefix_len); - reply_len = prefix_len; - macii_state = read_done; - break; - } /* end timeout / SRQ handling for II hw. */ - - if((reply_len-prefix_len)>3 - && memcmp(reply_ptr-3,"\xFF\xFF\xFF",3)==0) - { - /* SRQ tacked on data packet */ - /* Terminate the packet (SRQ never ends) */ - x = via[SR]; - macii_state = read_done; - reply_len -= 3; - reply_ptr -= 3; - need_poll = 1; - /* need to continue; next byte not seen else */ - } else { - /* Sanity check */ - if (reply_len > 15) reply_len = 0; - /* read byte */ - x = via[SR]; - *reply_ptr = x; + } + + if (macii_state == reading) { + BUG_ON(reply_len > 15); reply_ptr++; + *reply_ptr = x; reply_len++; } - /* The usual handshake ... */ - - /* - * NetBSD hints that the next to last byte - * is sent with IRQ !! - * Guido found out it's the last one (0x0), - * but IRQ should be asserted already. - * Problem with timeout detection: First - * transition to /IRQ might be second - * byte of timeout packet! - * Timeouts are signaled by 4x FF. - */ - if (((status & TREQ) == 0) && (x == 0x00)) { /* != 0xFF */ - /* invert state bits, toggle ODD/EVEN */ - via[B] ^= ST_MASK; - /* adjust packet length */ - reply_len--; - reply_ptr--; - macii_state = read_done; - } else { - /* not caught: ST_CMD */ - /* required for re-entry 'reading'! */ - if ((status & ST_MASK) == ST_IDLE) { - /* (in)sanity check - set even */ - via[B] = (via[B] & ~ST_MASK) | ST_EVEN; - } else { - /* invert state bits */ - via[B] ^= ST_MASK; - } - } + /* invert state bits, toggle ODD/EVEN */ + via[B] ^= ST_MASK; break; case read_done: x = via[SR]; + if (reading_reply) { + reading_reply = 0; req = current_req; - req->reply_len = reply_ptr - req->reply; + req->reply_len = reply_len; req->complete = 1; current_req = req->next; if (req->done) (*req->done)(req); - } else { - adb_input(reply_buf, reply_ptr - reply_buf, 0); - } + } else if (reply_len && autopoll_devs) + adb_input(reply_buf, reply_len, 0); - /* - * remember this device ID; it's the latest we got a - * reply from! - */ - last_reply = command_byte; - last_active = (command_byte & 0xF0) >> 4; + macii_state = idle; /* SRQ seen before, initiate poll now */ - if (need_poll) { - macii_state = idle; + if (srq_asserted) macii_queue_poll(); - need_poll = 0; - break; - } - - /* set ADB state to idle */ - via[B] = (via[B] & ~ST_MASK) | ST_IDLE; - - /* /IRQ seen, so the ADB controller has data for us */ - if ((via[B] & TREQ) != 0) { - macii_state = reading; - reply_buf[0] = command_byte; - reply_ptr = reply_buf + 1; - reply_len = 1; - prefix_len = 1; - reading_reply = 0; - } else { - /* no IRQ, send next packet or wait */ - macii_state = idle; - if (current_req) - macii_start(); - else - macii_retransmit(last_active); - } + if (current_req) + macii_start(); + else + if (need_autopoll()) + macii_autopoll(autopoll_devs); + + if (macii_state == idle) + via[B] = (via[B] & ~ST_MASK) | ST_IDLE; break; default: break; } - /* reset mutex and interrupts */ - driver_running = 0; - local_irq_restore(flags); + + entered--; return IRQ_HANDLED; } diff --git a/drivers/macintosh/via-pmu68k.c b/drivers/macintosh/via-pmu68k.c index 356c7216a17..dfdf11c1eec 100644 --- a/drivers/macintosh/via-pmu68k.c +++ b/drivers/macintosh/via-pmu68k.c @@ -111,7 +111,6 @@ static int pmu_send_request(struct adb_request *req, int sync); static int pmu_autopoll(int devs); void pmu_poll(void); static int pmu_reset_bus(void); -static int pmu_queue_request(struct adb_request *req); static void pmu_start(void); static void send_byte(int x); @@ -475,7 +474,7 @@ pmu_request(struct adb_request *req, void (*done)(struct adb_request *), return pmu_queue_request(req); } -static int +int pmu_queue_request(struct adb_request *req) { unsigned long flags; diff --git a/drivers/media/dvb/b2c2/flexcop-i2c.c b/drivers/media/dvb/b2c2/flexcop-i2c.c index 5347a406fff..02a0ea6e1c1 100644 --- a/drivers/media/dvb/b2c2/flexcop-i2c.c +++ b/drivers/media/dvb/b2c2/flexcop-i2c.c @@ -183,7 +183,8 @@ int flexcop_i2c_init(struct flexcop_device *fc) mutex_init(&fc->i2c_mutex); memset(&fc->i2c_adap, 0, sizeof(struct i2c_adapter)); - strncpy(fc->i2c_adap.name, "B2C2 FlexCop device",I2C_NAME_SIZE); + strncpy(fc->i2c_adap.name, "B2C2 FlexCop device", + sizeof(fc->i2c_adap.name)); i2c_set_adapdata(&fc->i2c_adap,fc); diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c index 70df31b0a8a..088b6dee3a7 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c @@ -19,7 +19,7 @@ int dvb_usb_i2c_init(struct dvb_usb_device *d) return -EINVAL; } - strncpy(d->i2c_adap.name,d->desc->name,I2C_NAME_SIZE); + strncpy(d->i2c_adap.name, d->desc->name, sizeof(d->i2c_adap.name)); #ifdef I2C_ADAP_CLASS_TV_DIGITAL d->i2c_adap.class = I2C_ADAP_CLASS_TV_DIGITAL, #else diff --git a/drivers/media/dvb/frontends/dibx000_common.c b/drivers/media/dvb/frontends/dibx000_common.c index a18c8f45a2e..315e09e95b0 100644 --- a/drivers/media/dvb/frontends/dibx000_common.c +++ b/drivers/media/dvb/frontends/dibx000_common.c @@ -105,9 +105,9 @@ struct i2c_adapter * dibx000_get_i2c_adapter(struct dibx000_i2c_master *mst, enu } EXPORT_SYMBOL(dibx000_get_i2c_adapter); -static int i2c_adapter_init(struct i2c_adapter *i2c_adap, struct i2c_algorithm *algo, const char name[I2C_NAME_SIZE], struct dibx000_i2c_master *mst) +static int i2c_adapter_init(struct i2c_adapter *i2c_adap, struct i2c_algorithm *algo, const char *name, struct dibx000_i2c_master *mst) { - strncpy(i2c_adap->name, name, I2C_NAME_SIZE); + strncpy(i2c_adap->name, name, sizeof(i2c_adap->name)); i2c_adap->class = I2C_CLASS_TV_DIGITAL, i2c_adap->algo = algo; i2c_adap->algo_data = NULL; diff --git a/drivers/media/video/cx2341x.c b/drivers/media/video/cx2341x.c index 88dbdddeec4..d73c86aeeaa 100644 --- a/drivers/media/video/cx2341x.c +++ b/drivers/media/video/cx2341x.c @@ -26,7 +26,6 @@ #include <linux/init.h> #include <linux/types.h> #include <linux/videodev2.h> -#include <linux/i2c.h> #include <media/tuner.h> #include <media/cx2341x.h> diff --git a/drivers/media/video/ovcamchip/ovcamchip_priv.h b/drivers/media/video/ovcamchip/ovcamchip_priv.h index 1231335a9f4..50c7763d44b 100644 --- a/drivers/media/video/ovcamchip/ovcamchip_priv.h +++ b/drivers/media/video/ovcamchip/ovcamchip_priv.h @@ -15,6 +15,7 @@ #ifndef __LINUX_OVCAMCHIP_PRIV_H #define __LINUX_OVCAMCHIP_PRIV_H +#include <linux/i2c.h> #include <media/ovcamchip.h> #ifdef DEBUG diff --git a/drivers/media/video/usbvision/usbvision-cards.c b/drivers/media/video/usbvision/usbvision-cards.c index 13f69fe6360..51ab265d566 100644 --- a/drivers/media/video/usbvision/usbvision-cards.c +++ b/drivers/media/video/usbvision/usbvision-cards.c @@ -24,7 +24,6 @@ #include <linux/list.h> -#include <linux/i2c.h> #include <media/v4l2-dev.h> #include <media/tuner.h> #include "usbvision.h" diff --git a/drivers/net/7990.c b/drivers/net/7990.c index d396f996af5..0877fc372f4 100644 --- a/drivers/net/7990.c +++ b/drivers/net/7990.c @@ -565,9 +565,9 @@ int lance_start_xmit (struct sk_buff *skb, struct net_device *dev) ib->btx_ring [entry].length = (-len) | 0xf000; ib->btx_ring [entry].misc = 0; - if (skb->len < ETH_ZLEN) - memset((char *)&ib->tx_buf[entry][0], 0, ETH_ZLEN); - skb_copy_from_linear_data(skb, &ib->tx_buf[entry][0], skblen); + if (skb->len < ETH_ZLEN) + memset((void *)&ib->tx_buf[entry][0], 0, ETH_ZLEN); + skb_copy_from_linear_data(skb, (void *)&ib->tx_buf[entry][0], skblen); /* Now, give the packet to the lance */ ib->btx_ring [entry].tmd1_bits = (LE_T1_POK|LE_T1_OWN); diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index dcdad217df5..69dba62e0ba 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -311,7 +311,7 @@ config MAC8390 config MAC89x0 tristate "Macintosh CS89x0 based ethernet cards" - depends on NET_ETHERNET && MAC && BROKEN + depends on NET_ETHERNET && MAC ---help--- Support for CS89x0 chipset based Ethernet cards. If you have a Nubus or LC-PDS network (Ethernet) card of this type, say Y and @@ -337,8 +337,8 @@ config MACSONIC be called macsonic. config MACMACE - bool "Macintosh (AV) onboard MACE ethernet (EXPERIMENTAL)" - depends on NET_ETHERNET && MAC && EXPERIMENTAL + bool "Macintosh (AV) onboard MACE ethernet" + depends on NET_ETHERNET && MAC select CRC32 help Support for the onboard AMD 79C940 MACE Ethernet controller used in diff --git a/drivers/net/Space.c b/drivers/net/Space.c index dd8ed456c8b..1c3e293fbaf 100644 --- a/drivers/net/Space.c +++ b/drivers/net/Space.c @@ -83,7 +83,6 @@ extern struct net_device *bagetlance_probe(int unit); extern struct net_device *mvme147lance_probe(int unit); extern struct net_device *tc515_probe(int unit); extern struct net_device *lance_probe(int unit); -extern struct net_device *mace_probe(int unit); extern struct net_device *mac8390_probe(int unit); extern struct net_device *mac89x0_probe(int unit); extern struct net_device *mc32_probe(int unit); @@ -274,9 +273,6 @@ static struct devprobe2 m68k_probes[] __initdata = { #ifdef CONFIG_MVME147_NET /* MVME147 internal Ethernet */ {mvme147lance_probe, 0}, #endif -#ifdef CONFIG_MACMACE /* Mac 68k Quadra AV builtin Ethernet */ - {mace_probe, 0}, -#endif #ifdef CONFIG_MAC8390 /* NuBus NS8390-based cards */ {mac8390_probe, 0}, #endif diff --git a/drivers/net/a2065.c b/drivers/net/a2065.c index 1226cbba045..81d5a374042 100644 --- a/drivers/net/a2065.c +++ b/drivers/net/a2065.c @@ -562,7 +562,6 @@ static int lance_start_xmit (struct sk_buff *skb, struct net_device *dev) volatile struct lance_init_block *ib = lp->init_block; int entry, skblen, len; int status = 0; - static int outs; unsigned long flags; skblen = skb->len; @@ -598,17 +597,16 @@ static int lance_start_xmit (struct sk_buff *skb, struct net_device *dev) ib->btx_ring [entry].length = (-len) | 0xf000; ib->btx_ring [entry].misc = 0; - skb_copy_from_linear_data(skb, &ib->tx_buf [entry][0], skblen); + skb_copy_from_linear_data(skb, (void *)&ib->tx_buf [entry][0], skblen); /* Clear the slack of the packet, do I need this? */ if (len != skblen) - memset ((char *) &ib->tx_buf [entry][skblen], 0, len - skblen); + memset ((void *) &ib->tx_buf [entry][skblen], 0, len - skblen); /* Now, give the packet to the lance */ ib->btx_ring [entry].tmd1_bits = (LE_T1_POK|LE_T1_OWN); lp->tx_new = (lp->tx_new+1) & lp->tx_ring_mod_mask; - - outs++; + lp->stats.tx_bytes += skblen; if (TX_BUFFS_AVAIL <= 0) netif_stop_queue(dev); diff --git a/drivers/net/ariadne.c b/drivers/net/ariadne.c index a0e68e71853..a241ae7855a 100644 --- a/drivers/net/ariadne.c +++ b/drivers/net/ariadne.c @@ -677,6 +677,7 @@ static int ariadne_start_xmit(struct sk_buff *skb, struct net_device *dev) priv->cur_tx -= TX_RING_SIZE; priv->dirty_tx -= TX_RING_SIZE; } + priv->stats.tx_bytes += len; /* Trigger an immediate send poll. */ lance->RAP = CSR0; /* PCnet-ISA Controller Status */ diff --git a/drivers/net/jazzsonic.c b/drivers/net/jazzsonic.c index d34afb52ea7..75f6f441e87 100644 --- a/drivers/net/jazzsonic.c +++ b/drivers/net/jazzsonic.c @@ -88,6 +88,23 @@ static unsigned short known_revisions[] = 0xffff /* end of list */ }; +static int jazzsonic_open(struct net_device* dev) +{ + if (request_irq(dev->irq, &sonic_interrupt, IRQF_DISABLED, "sonic", dev)) { + printk(KERN_ERR "%s: unable to get IRQ %d.\n", dev->name, dev->irq); + return -EAGAIN; + } + return sonic_open(dev); +} + +static int jazzsonic_close(struct net_device* dev) +{ + int err; + err = sonic_close(dev); + free_irq(dev->irq, dev); + return err; +} + static int __init sonic_probe1(struct net_device *dev) { static unsigned version_printed; @@ -169,8 +186,8 @@ static int __init sonic_probe1(struct net_device *dev) lp->rra_laddr = lp->rda_laddr + (SIZEOF_SONIC_RD * SONIC_NUM_RDS * SONIC_BUS_SCALE(lp->dma_bitmode)); - dev->open = sonic_open; - dev->stop = sonic_close; + dev->open = jazzsonic_open; + dev->stop = jazzsonic_close; dev->hard_start_xmit = sonic_send_packet; dev->get_stats = sonic_get_stats; dev->set_multicast_list = &sonic_multicast_list; @@ -260,8 +277,6 @@ MODULE_DESCRIPTION("Jazz SONIC ethernet driver"); module_param(sonic_debug, int, 0); MODULE_PARM_DESC(sonic_debug, "jazzsonic debug level (1-4)"); -#define SONIC_IRQ_FLAG IRQF_DISABLED - #include "sonic.c" static int __devexit jazz_sonic_device_remove (struct platform_device *pdev) @@ -269,11 +284,11 @@ static int __devexit jazz_sonic_device_remove (struct platform_device *pdev) struct net_device *dev = platform_get_drvdata(pdev); struct sonic_local* lp = netdev_priv(dev); - unregister_netdev (dev); + unregister_netdev(dev); dma_free_coherent(lp->device, SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode), lp->descriptors, lp->descriptors_laddr); release_region (dev->base_addr, SONIC_MEM_SIZE); - free_netdev (dev); + free_netdev(dev); return 0; } diff --git a/drivers/net/mac8390.c b/drivers/net/mac8390.c index a12bb64e369..90b0c3ed4bb 100644 --- a/drivers/net/mac8390.c +++ b/drivers/net/mac8390.c @@ -14,6 +14,8 @@ /* 2001-05-15: support for Cabletron ported from old daynaport driver * and fixed access to Sonic Sys card which masquerades as a Farallon * by rayk@knightsmanor.org */ +/* 2002-12-30: Try to support more cards, some clues from NetBSD driver */ +/* 2003-12-26: Make sure Asante cards always work. */ #include <linux/module.h> #include <linux/kernel.h> @@ -61,25 +63,21 @@ static char version[] = #define DAYNA_8390_BASE 0x80000 #define DAYNA_8390_MEM 0x00000 -#define KINETICS_8390_BASE 0x80000 -#define KINETICS_8390_MEM 0x00000 - #define CABLETRON_8390_BASE 0x90000 #define CABLETRON_8390_MEM 0x00000 +#define INTERLAN_8390_BASE 0xE0000 +#define INTERLAN_8390_MEM 0xD0000 + enum mac8390_type { MAC8390_NONE = -1, MAC8390_APPLE, MAC8390_ASANTE, - MAC8390_FARALLON, /* Apple, Asante, and Farallon are all compatible */ + MAC8390_FARALLON, MAC8390_CABLETRON, MAC8390_DAYNA, MAC8390_INTERLAN, MAC8390_KINETICS, - MAC8390_FOCUS, - MAC8390_SONICSYS, - MAC8390_DAYNA2, - MAC8390_DAYNA3, }; static const char * cardname[] = { @@ -90,10 +88,6 @@ static const char * cardname[] = { "dayna", "interlan", "kinetics", - "focus", - "sonic systems", - "dayna2", - "dayna_lc", }; static int word16[] = { @@ -104,10 +98,6 @@ static int word16[] = { 0, /* dayna */ 1, /* interlan */ 0, /* kinetics */ - 1, /* focus (??) */ - 1, /* sonic systems */ - 1, /* dayna2 */ - 1, /* dayna-lc */ }; /* on which cards do we use NuBus resources? */ @@ -119,10 +109,12 @@ static int useresources[] = { 0, /* dayna */ 0, /* interlan */ 0, /* kinetics */ - 0, /* focus (??) */ - 1, /* sonic systems */ - 1, /* dayna2 */ - 1, /* dayna-lc */ +}; + +enum mac8390_access { + ACCESS_UNKNOWN = 0, + ACCESS_32, + ACCESS_16, }; extern enum mac8390_type mac8390_ident(struct nubus_dev * dev); @@ -134,8 +126,9 @@ static int mac8390_initdev(struct net_device * dev, struct nubus_dev * ndev, static int mac8390_open(struct net_device * dev); static int mac8390_close(struct net_device * dev); static void mac8390_no_reset(struct net_device *dev); +static void interlan_reset(struct net_device *dev); -/* Sane (32-bit chunk memory read/write) - Apple/Asante/Farallon do this*/ +/* Sane (32-bit chunk memory read/write) - Some Farallon and Apple do this*/ static void sane_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page); static void sane_block_input(struct net_device * dev, int count, @@ -172,23 +165,93 @@ static void word_memcpy_fromcard(void *tp, const void *fp, int count); enum mac8390_type __init mac8390_ident(struct nubus_dev * dev) { - if (dev->dr_sw == NUBUS_DRSW_ASANTE) - return MAC8390_ASANTE; - if (dev->dr_sw == NUBUS_DRSW_FARALLON) - return MAC8390_FARALLON; - if (dev->dr_sw == NUBUS_DRSW_KINETICS) - return MAC8390_KINETICS; - if (dev->dr_sw == NUBUS_DRSW_DAYNA) - return MAC8390_DAYNA; - if (dev->dr_sw == NUBUS_DRSW_DAYNA2) - return MAC8390_DAYNA2; - if (dev->dr_sw == NUBUS_DRSW_DAYNA_LC) - return MAC8390_DAYNA3; - if (dev->dr_hw == NUBUS_DRHW_CABLETRON) - return MAC8390_CABLETRON; + switch (dev->dr_sw) { + case NUBUS_DRSW_3COM: + switch (dev->dr_hw) { + case NUBUS_DRHW_APPLE_SONIC_NB: + case NUBUS_DRHW_APPLE_SONIC_LC: + case NUBUS_DRHW_SONNET: + return MAC8390_NONE; + break; + default: + return MAC8390_APPLE; + break; + } + break; + + case NUBUS_DRSW_APPLE: + switch (dev->dr_hw) { + case NUBUS_DRHW_ASANTE_LC: + return MAC8390_NONE; + break; + case NUBUS_DRHW_CABLETRON: + return MAC8390_CABLETRON; + break; + default: + return MAC8390_APPLE; + break; + } + break; + + case NUBUS_DRSW_ASANTE: + return MAC8390_ASANTE; + break; + + case NUBUS_DRSW_TECHWORKS: + case NUBUS_DRSW_DAYNA2: + case NUBUS_DRSW_DAYNA_LC: + if (dev->dr_hw == NUBUS_DRHW_CABLETRON) + return MAC8390_CABLETRON; + else + return MAC8390_APPLE; + break; + + case NUBUS_DRSW_FARALLON: + return MAC8390_FARALLON; + break; + + case NUBUS_DRSW_KINETICS: + switch (dev->dr_hw) { + case NUBUS_DRHW_INTERLAN: + return MAC8390_INTERLAN; + break; + default: + return MAC8390_KINETICS; + break; + } + break; + + case NUBUS_DRSW_DAYNA: + // These correspond to Dayna Sonic cards + // which use the macsonic driver + if (dev->dr_hw == NUBUS_DRHW_SMC9194 || + dev->dr_hw == NUBUS_DRHW_INTERLAN ) + return MAC8390_NONE; + else + return MAC8390_DAYNA; + break; + } return MAC8390_NONE; } +enum mac8390_access __init mac8390_testio(volatile unsigned long membase) +{ + unsigned long outdata = 0xA5A0B5B0; + unsigned long indata = 0x00000000; + /* Try writing 32 bits */ + memcpy((char *)membase, (char *)&outdata, 4); + /* Now compare them */ + if (memcmp((char *)&outdata, (char *)membase, 4) == 0) + return ACCESS_32; + /* Write 16 bit output */ + word_memcpy_tocard((char *)membase, (char *)&outdata, 4); + /* Now read it back */ + word_memcpy_fromcard((char *)&indata, (char *)membase, 4); + if (outdata == indata) + return ACCESS_16; + return ACCESS_UNKNOWN; +} + int __init mac8390_memsize(unsigned long membase) { unsigned long flags; @@ -287,14 +350,6 @@ struct net_device * __init mac8390_probe(int unit) continue; } else { nubus_get_rsrc_mem(dev->dev_addr, &ent, 6); - /* Some Sonic Sys cards masquerade as Farallon */ - if (cardtype == MAC8390_FARALLON && - dev->dev_addr[0] == 0x0 && - dev->dev_addr[1] == 0x40 && - dev->dev_addr[2] == 0x10) { - /* This is really Sonic Sys card */ - cardtype = MAC8390_SONICSYS; - } } if (useresources[cardtype] == 1) { @@ -334,6 +389,17 @@ struct net_device * __init mac8390_probe(int unit) dev->mem_start + mac8390_memsize(dev->mem_start); break; + case MAC8390_INTERLAN: + dev->base_addr = + (int)(ndev->board->slot_addr + + INTERLAN_8390_BASE); + dev->mem_start = + (int)(ndev->board->slot_addr + + INTERLAN_8390_MEM); + dev->mem_end = + dev->mem_start + + mac8390_memsize(dev->mem_start); + break; case MAC8390_CABLETRON: dev->base_addr = (int)(ndev->board->slot_addr + @@ -356,8 +422,8 @@ struct net_device * __init mac8390_probe(int unit) default: printk(KERN_ERR "Card type %s is" - " unsupported, sorry\n", - cardname[cardtype]); + " unsupported, sorry\n", + ndev->board->name); continue; } } @@ -438,7 +504,7 @@ static int __init mac8390_initdev(struct net_device * dev, struct nubus_dev * nd 24, 26, 28, 30 }; - int access_bitmode; + int access_bitmode = 0; /* Now fill in our stuff */ dev->open = &mac8390_open; @@ -468,29 +534,47 @@ static int __init mac8390_initdev(struct net_device * dev, struct nubus_dev * nd /* Fill in model-specific information and functions */ switch(type) { - case MAC8390_SONICSYS: - /* 16 bit card, register map is reversed */ - ei_status.reset_8390 = &mac8390_no_reset; - ei_status.block_input = &slow_sane_block_input; - ei_status.block_output = &slow_sane_block_output; - ei_status.get_8390_hdr = &slow_sane_get_8390_hdr; - ei_status.reg_offset = back4_offsets; - access_bitmode = 0; - break; case MAC8390_FARALLON: case MAC8390_APPLE: + switch(mac8390_testio(dev->mem_start)) { + case ACCESS_UNKNOWN: + printk("Don't know how to access card memory!\n"); + return -ENODEV; + break; + + case ACCESS_16: + /* 16 bit card, register map is reversed */ + ei_status.reset_8390 = &mac8390_no_reset; + ei_status.block_input = &slow_sane_block_input; + ei_status.block_output = &slow_sane_block_output; + ei_status.get_8390_hdr = &slow_sane_get_8390_hdr; + ei_status.reg_offset = back4_offsets; + break; + + case ACCESS_32: + /* 32 bit card, register map is reversed */ + ei_status.reset_8390 = &mac8390_no_reset; + ei_status.block_input = &sane_block_input; + ei_status.block_output = &sane_block_output; + ei_status.get_8390_hdr = &sane_get_8390_hdr; + ei_status.reg_offset = back4_offsets; + access_bitmode = 1; + break; + } + break; + case MAC8390_ASANTE: - case MAC8390_DAYNA2: - case MAC8390_DAYNA3: - /* 32 bit card, register map is reversed */ - /* sane */ + /* Some Asante cards pass the 32 bit test + * but overwrite system memory when run at 32 bit. + * so we run them all at 16 bit. + */ ei_status.reset_8390 = &mac8390_no_reset; - ei_status.block_input = &sane_block_input; - ei_status.block_output = &sane_block_output; - ei_status.get_8390_hdr = &sane_get_8390_hdr; + ei_status.block_input = &slow_sane_block_input; + ei_status.block_output = &slow_sane_block_output; + ei_status.get_8390_hdr = &slow_sane_get_8390_hdr; ei_status.reg_offset = back4_offsets; - access_bitmode = 1; break; + case MAC8390_CABLETRON: /* 16 bit card, register map is short forward */ ei_status.reset_8390 = &mac8390_no_reset; @@ -498,21 +582,30 @@ static int __init mac8390_initdev(struct net_device * dev, struct nubus_dev * nd ei_status.block_output = &slow_sane_block_output; ei_status.get_8390_hdr = &slow_sane_get_8390_hdr; ei_status.reg_offset = fwrd2_offsets; - access_bitmode = 0; break; + case MAC8390_DAYNA: case MAC8390_KINETICS: - /* 16 bit memory */ + /* 16 bit memory, register map is forward */ /* dayna and similar */ ei_status.reset_8390 = &mac8390_no_reset; ei_status.block_input = &dayna_block_input; ei_status.block_output = &dayna_block_output; ei_status.get_8390_hdr = &dayna_get_8390_hdr; ei_status.reg_offset = fwrd4_offsets; - access_bitmode = 0; break; + + case MAC8390_INTERLAN: + /* 16 bit memory, register map is forward */ + ei_status.reset_8390 = &interlan_reset; + ei_status.block_input = &slow_sane_block_input; + ei_status.block_output = &slow_sane_block_output; + ei_status.get_8390_hdr = &slow_sane_get_8390_hdr; + ei_status.reg_offset = fwrd4_offsets; + break; + default: - printk(KERN_ERR "Card type %s is unsupported, sorry\n", cardname[type]); + printk(KERN_ERR "Card type %s is unsupported, sorry\n", ndev->board->name); return -ENODEV; } @@ -530,9 +623,9 @@ static int __init mac8390_initdev(struct net_device * dev, struct nubus_dev * nd printk(":"); } } - printk(" IRQ %d, shared memory at %#lx-%#lx, %d-bit access.\n", - dev->irq, dev->mem_start, dev->mem_end-1, - access_bitmode?32:16); + printk(" IRQ %d, %d KB shared memory at %#lx, %d-bit access.\n", + dev->irq, (int)((dev->mem_end - dev->mem_start)/0x1000) * 4, + dev->mem_start, access_bitmode?32:16); return 0; } @@ -561,6 +654,18 @@ static void mac8390_no_reset(struct net_device *dev) return; } +static void interlan_reset(struct net_device *dev) +{ + unsigned char *target=nubus_slot_addr(IRQ2SLOT(dev->irq)); + if (ei_debug > 1) + printk("Need to reset the NS8390 t=%lu...", jiffies); + ei_status.txing = 0; + target[0xC0000] = 0; + if (ei_debug > 1) + printk("reset complete\n"); + return; +} + /* dayna_memcpy_fromio/dayna_memcpy_toio */ /* directly from daynaport.c by Alan Cox */ static void dayna_memcpy_fromcard(struct net_device *dev, void *to, int from, int count) diff --git a/drivers/net/mac89x0.c b/drivers/net/mac89x0.c index 90e695d5326..26a3b45a4a3 100644 --- a/drivers/net/mac89x0.c +++ b/drivers/net/mac89x0.c @@ -128,7 +128,7 @@ struct net_local { extern void reset_chip(struct net_device *dev); #endif static int net_open(struct net_device *dev); -static int net_send_packet(struct sk_buff *skb, struct net_device *dev); +static int net_send_packet(struct sk_buff *skb, struct net_device *dev); static irqreturn_t net_interrupt(int irq, void *dev_id); static void set_multicast_list(struct net_device *dev); static void net_rx(struct net_device *dev); @@ -374,56 +374,39 @@ net_open(struct net_device *dev) static int net_send_packet(struct sk_buff *skb, struct net_device *dev) { - if (dev->tbusy) { - /* If we get here, some higher level has decided we are broken. - There should really be a "kick me" function call instead. */ - int tickssofar = jiffies - dev->trans_start; - if (tickssofar < 5) - return 1; - if (net_debug > 0) printk("%s: transmit timed out, %s?\n", dev->name, - tx_done(dev) ? "IRQ conflict" : "network cable problem"); - /* Try to restart the adaptor. */ - dev->tbusy=0; - dev->trans_start = jiffies; - } - - /* Block a timer-based transmit from overlapping. This could better be - done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ - if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) - printk("%s: Transmitter access conflict.\n", dev->name); - else { - struct net_local *lp = netdev_priv(dev); - unsigned long flags; - - if (net_debug > 3) - printk("%s: sent %d byte packet of type %x\n", - dev->name, skb->len, - (skb->data[ETH_ALEN+ETH_ALEN] << 8) - | skb->data[ETH_ALEN+ETH_ALEN+1]); - - /* keep the upload from being interrupted, since we - ask the chip to start transmitting before the - whole packet has been completely uploaded. */ - local_irq_save(flags); + struct net_local *lp = netdev_priv(dev); + unsigned long flags; - /* initiate a transmit sequence */ - writereg(dev, PP_TxCMD, lp->send_cmd); - writereg(dev, PP_TxLength, skb->len); + if (net_debug > 3) + printk("%s: sent %d byte packet of type %x\n", + dev->name, skb->len, + (skb->data[ETH_ALEN+ETH_ALEN] << 8) + | skb->data[ETH_ALEN+ETH_ALEN+1]); - /* Test to see if the chip has allocated memory for the packet */ - if ((readreg(dev, PP_BusST) & READY_FOR_TX_NOW) == 0) { - /* Gasp! It hasn't. But that shouldn't happen since - we're waiting for TxOk, so return 1 and requeue this packet. */ - local_irq_restore(flags); - return 1; - } + /* keep the upload from being interrupted, since we + ask the chip to start transmitting before the + whole packet has been completely uploaded. */ + local_irq_save(flags); + netif_stop_queue(dev); - /* Write the contents of the packet */ - memcpy_toio(dev->mem_start + PP_TxFrame, skb->data, skb->len+1); + /* initiate a transmit sequence */ + writereg(dev, PP_TxCMD, lp->send_cmd); + writereg(dev, PP_TxLength, skb->len); + /* Test to see if the chip has allocated memory for the packet */ + if ((readreg(dev, PP_BusST) & READY_FOR_TX_NOW) == 0) { + /* Gasp! It hasn't. But that shouldn't happen since + we're waiting for TxOk, so return 1 and requeue this packet. */ local_irq_restore(flags); - dev->trans_start = jiffies; + return 1; } + + /* Write the contents of the packet */ + skb_copy_from_linear_data(skb, (void *)(dev->mem_start + PP_TxFrame), + skb->len+1); + + local_irq_restore(flags); + dev->trans_start = jiffies; dev_kfree_skb (skb); return 0; @@ -441,9 +424,6 @@ static irqreturn_t net_interrupt(int irq, void *dev_id) printk ("net_interrupt(): irq %d for unknown device.\n", irq); return IRQ_NONE; } - if (dev->interrupt) - printk("%s: Re-entering the interrupt handler.\n", dev->name); - dev->interrupt = 1; ioaddr = dev->base_addr; lp = netdev_priv(dev); @@ -464,8 +444,7 @@ static irqreturn_t net_interrupt(int irq, void *dev_id) break; case ISQ_TRANSMITTER_EVENT: lp->stats.tx_packets++; - dev->tbusy = 0; - mark_bh(NET_BH); /* Inform upper layers. */ + netif_wake_queue(dev); if ((status & TX_OK) == 0) lp->stats.tx_errors++; if (status & TX_LOST_CRS) lp->stats.tx_carrier_errors++; if (status & TX_SQE_ERROR) lp->stats.tx_heartbeat_errors++; @@ -479,8 +458,7 @@ static irqreturn_t net_interrupt(int irq, void *dev_id) That shouldn't happen since we only ever load one packet. Shrug. Do the right thing anyway. */ - dev->tbusy = 0; - mark_bh(NET_BH); /* Inform upper layers. */ + netif_wake_queue(dev); } if (status & TX_UNDERRUN) { if (net_debug > 0) printk("%s: transmit underrun\n", dev->name); @@ -497,7 +475,6 @@ static irqreturn_t net_interrupt(int irq, void *dev_id) break; } } - dev->interrupt = 0; return IRQ_HANDLED; } @@ -531,7 +508,8 @@ net_rx(struct net_device *dev) } skb_put(skb, length); - memcpy_fromio(skb->data, dev->mem_start + PP_RxFrame, length); + skb_copy_to_linear_data(skb, (void *)(dev->mem_start + PP_RxFrame), + length); if (net_debug > 3)printk("%s: received %d byte packet of type %x\n", dev->name, length, @@ -610,8 +588,6 @@ static void set_multicast_list(struct net_device *dev) static int set_mac_address(struct net_device *dev, void *addr) { int i; - if (dev->start) - return -EBUSY; printk("%s: Setting MAC address to ", dev->name); for (i = 0; i < 6; i++) printk(" %2.2x", dev->dev_addr[i] = ((unsigned char *)addr)[i]); diff --git a/drivers/net/macmace.c b/drivers/net/macmace.c index 27911c07558..fef3193121f 100644 --- a/drivers/net/macmace.c +++ b/drivers/net/macmace.c @@ -12,6 +12,11 @@ * Copyright (C) 1998 Alan Cox <alan@redhat.com> * * Modified heavily by Joshua M. Thompson based on Dave Huang's NetBSD driver + * + * Copyright (C) 2007 Finn Thain + * + * Converted to DMA API, converted to unified driver model, + * sync'd some routines with mace.c and fixed various bugs. */ @@ -23,8 +28,9 @@ #include <linux/string.h> #include <linux/crc32.h> #include <linux/bitrev.h> +#include <linux/dma-mapping.h> +#include <linux/platform_device.h> #include <asm/io.h> -#include <asm/pgtable.h> #include <asm/irq.h> #include <asm/macintosh.h> #include <asm/macints.h> @@ -32,13 +38,20 @@ #include <asm/page.h> #include "mace.h" -#define N_TX_RING 1 -#define N_RX_RING 8 -#define N_RX_PAGES ((N_RX_RING * 0x0800 + PAGE_SIZE - 1) / PAGE_SIZE) +static char mac_mace_string[] = "macmace"; +static struct platform_device *mac_mace_device; + +#define N_TX_BUFF_ORDER 0 +#define N_TX_RING (1 << N_TX_BUFF_ORDER) +#define N_RX_BUFF_ORDER 3 +#define N_RX_RING (1 << N_RX_BUFF_ORDER) + #define TX_TIMEOUT HZ -/* Bits in transmit DMA status */ -#define TX_DMA_ERR 0x80 +#define MACE_BUFF_SIZE 0x800 + +/* Chip rev needs workaround on HW & multicast addr change */ +#define BROKEN_ADDRCHG_REV 0x0941 /* The MACE is simply wired down on a Mac68K box */ @@ -47,40 +60,46 @@ struct mace_data { volatile struct mace *mace; - volatile unsigned char *tx_ring; - volatile unsigned char *tx_ring_phys; - volatile unsigned char *rx_ring; - volatile unsigned char *rx_ring_phys; + unsigned char *tx_ring; + dma_addr_t tx_ring_phys; + unsigned char *rx_ring; + dma_addr_t rx_ring_phys; int dma_intr; struct net_device_stats stats; int rx_slot, rx_tail; int tx_slot, tx_sloti, tx_count; + int chipid; + struct device *device; }; struct mace_frame { - u16 len; - u16 status; - u16 rntpc; - u16 rcvcc; - u32 pad1; - u32 pad2; + u8 rcvcnt; + u8 pad1; + u8 rcvsts; + u8 pad2; + u8 rntpc; + u8 pad3; + u8 rcvcc; + u8 pad4; + u32 pad5; + u32 pad6; u8 data[1]; /* And frame continues.. */ }; #define PRIV_BYTES sizeof(struct mace_data) -extern void psc_debug_dump(void); - static int mace_open(struct net_device *dev); static int mace_close(struct net_device *dev); static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev); static struct net_device_stats *mace_stats(struct net_device *dev); static void mace_set_multicast(struct net_device *dev); static int mace_set_address(struct net_device *dev, void *addr); +static void mace_reset(struct net_device *dev); static irqreturn_t mace_interrupt(int irq, void *dev_id); static irqreturn_t mace_dma_intr(int irq, void *dev_id); static void mace_tx_timeout(struct net_device *dev); +static void __mace_set_address(struct net_device *dev, void *addr); /* * Load a receive DMA channel with a base address and ring length @@ -88,7 +107,7 @@ static void mace_tx_timeout(struct net_device *dev); static void mace_load_rxdma_base(struct net_device *dev, int set) { - struct mace_data *mp = (struct mace_data *) dev->priv; + struct mace_data *mp = netdev_priv(dev); psc_write_word(PSC_ENETRD_CMD + set, 0x0100); psc_write_long(PSC_ENETRD_ADDR + set, (u32) mp->rx_ring_phys); @@ -103,7 +122,7 @@ static void mace_load_rxdma_base(struct net_device *dev, int set) static void mace_rxdma_reset(struct net_device *dev) { - struct mace_data *mp = (struct mace_data *) dev->priv; + struct mace_data *mp = netdev_priv(dev); volatile struct mace *mace = mp->mace; u8 maccc = mace->maccc; @@ -130,7 +149,7 @@ static void mace_rxdma_reset(struct net_device *dev) static void mace_txdma_reset(struct net_device *dev) { - struct mace_data *mp = (struct mace_data *) dev->priv; + struct mace_data *mp = netdev_priv(dev); volatile struct mace *mace = mp->mace; u8 maccc; @@ -168,7 +187,7 @@ static void mace_dma_off(struct net_device *dev) * model of Macintrash has a MACE (AV macintoshes) */ -struct net_device *mace_probe(int unit) +static int __devinit mace_probe(struct platform_device *pdev) { int j; struct mace_data *mp; @@ -179,24 +198,28 @@ struct net_device *mace_probe(int unit) int err; if (found || macintosh_config->ether_type != MAC_ETHER_MACE) - return ERR_PTR(-ENODEV); + return -ENODEV; found = 1; /* prevent 'finding' one on every device probe */ dev = alloc_etherdev(PRIV_BYTES); if (!dev) - return ERR_PTR(-ENOMEM); + return -ENOMEM; - if (unit >= 0) - sprintf(dev->name, "eth%d", unit); + mp = netdev_priv(dev); + + mp->device = &pdev->dev; + SET_NETDEV_DEV(dev, &pdev->dev); + SET_MODULE_OWNER(dev); - mp = (struct mace_data *) dev->priv; dev->base_addr = (u32)MACE_BASE; mp->mace = (volatile struct mace *) MACE_BASE; dev->irq = IRQ_MAC_MACE; mp->dma_intr = IRQ_MAC_MACE_DMA; + mp->chipid = mp->mace->chipid_hi << 8 | mp->mace->chipid_lo; + /* * The PROM contains 8 bytes which total 0xFF when XOR'd * together. Due to the usual peculiar apple brain damage @@ -217,7 +240,7 @@ struct net_device *mace_probe(int unit) if (checksum != 0xFF) { free_netdev(dev); - return ERR_PTR(-ENODEV); + return -ENODEV; } memset(&mp->stats, 0, sizeof(mp->stats)); @@ -237,22 +260,98 @@ struct net_device *mace_probe(int unit) err = register_netdev(dev); if (!err) - return dev; + return 0; free_netdev(dev); - return ERR_PTR(err); + return err; +} + +/* + * Reset the chip. + */ + +static void mace_reset(struct net_device *dev) +{ + struct mace_data *mp = netdev_priv(dev); + volatile struct mace *mb = mp->mace; + int i; + + /* soft-reset the chip */ + i = 200; + while (--i) { + mb->biucc = SWRST; + if (mb->biucc & SWRST) { + udelay(10); + continue; + } + break; + } + if (!i) { + printk(KERN_ERR "macmace: cannot reset chip!\n"); + return; + } + + mb->maccc = 0; /* turn off tx, rx */ + mb->imr = 0xFF; /* disable all intrs for now */ + i = mb->ir; + + mb->biucc = XMTSP_64; + mb->utr = RTRD; + mb->fifocc = XMTFW_8 | RCVFW_64 | XMTFWU | RCVFWU; + + mb->xmtfc = AUTO_PAD_XMIT; /* auto-pad short frames */ + mb->rcvfc = 0; + + /* load up the hardware address */ + __mace_set_address(dev, dev->dev_addr); + + /* clear the multicast filter */ + if (mp->chipid == BROKEN_ADDRCHG_REV) + mb->iac = LOGADDR; + else { + mb->iac = ADDRCHG | LOGADDR; + while ((mb->iac & ADDRCHG) != 0) + ; + } + for (i = 0; i < 8; ++i) + mb->ladrf = 0; + + /* done changing address */ + if (mp->chipid != BROKEN_ADDRCHG_REV) + mb->iac = 0; + + mb->plscc = PORTSEL_AUI; } /* * Load the address on a mace controller. */ -static int mace_set_address(struct net_device *dev, void *addr) +static void __mace_set_address(struct net_device *dev, void *addr) { - unsigned char *p = addr; - struct mace_data *mp = (struct mace_data *) dev->priv; + struct mace_data *mp = netdev_priv(dev); volatile struct mace *mb = mp->mace; + unsigned char *p = addr; int i; + + /* load up the hardware address */ + if (mp->chipid == BROKEN_ADDRCHG_REV) + mb->iac = PHYADDR; + else { + mb->iac = ADDRCHG | PHYADDR; + while ((mb->iac & ADDRCHG) != 0) + ; + } + for (i = 0; i < 6; ++i) + mb->padr = dev->dev_addr[i] = p[i]; + if (mp->chipid != BROKEN_ADDRCHG_REV) + mb->iac = 0; +} + +static int mace_set_address(struct net_device *dev, void *addr) +{ + struct mace_data *mp = netdev_priv(dev); + volatile struct mace *mb = mp->mace; unsigned long flags; u8 maccc; @@ -260,15 +359,10 @@ static int mace_set_address(struct net_device *dev, void *addr) maccc = mb->maccc; - /* load up the hardware address */ - mb->iac = ADDRCHG | PHYADDR; - while ((mb->iac & ADDRCHG) != 0); - - for (i = 0; i < 6; ++i) { - mb->padr = dev->dev_addr[i] = p[i]; - } + __mace_set_address(dev, addr); mb->maccc = maccc; + local_irq_restore(flags); return 0; @@ -281,31 +375,11 @@ static int mace_set_address(struct net_device *dev, void *addr) static int mace_open(struct net_device *dev) { - struct mace_data *mp = (struct mace_data *) dev->priv; + struct mace_data *mp = netdev_priv(dev); volatile struct mace *mb = mp->mace; -#if 0 - int i; - i = 200; - while (--i) { - mb->biucc = SWRST; - if (mb->biucc & SWRST) { - udelay(10); - continue; - } - break; - } - if (!i) { - printk(KERN_ERR "%s: software reset failed!!\n", dev->name); - return -EAGAIN; - } -#endif - - mb->biucc = XMTSP_64; - mb->fifocc = XMTFW_16 | RCVFW_64 | XMTFWU | RCVFWU | XMTBRST | RCVBRST; - mb->xmtfc = AUTO_PAD_XMIT; - mb->plscc = PORTSEL_AUI; - /* mb->utr = RTRD; */ + /* reset the chip */ + mace_reset(dev); if (request_irq(dev->irq, mace_interrupt, 0, dev->name, dev)) { printk(KERN_ERR "%s: can't get irq %d\n", dev->name, dev->irq); @@ -319,25 +393,21 @@ static int mace_open(struct net_device *dev) /* Allocate the DMA ring buffers */ - mp->rx_ring = (void *) __get_free_pages(GFP_KERNEL | GFP_DMA, N_RX_PAGES); - mp->tx_ring = (void *) __get_free_pages(GFP_KERNEL | GFP_DMA, 0); - - if (mp->tx_ring==NULL || mp->rx_ring==NULL) { - if (mp->rx_ring) free_pages((u32) mp->rx_ring, N_RX_PAGES); - if (mp->tx_ring) free_pages((u32) mp->tx_ring, 0); - free_irq(dev->irq, dev); - free_irq(mp->dma_intr, dev); - printk(KERN_ERR "%s: unable to allocate DMA buffers\n", dev->name); - return -ENOMEM; + mp->tx_ring = dma_alloc_coherent(mp->device, + N_TX_RING * MACE_BUFF_SIZE, + &mp->tx_ring_phys, GFP_KERNEL); + if (mp->tx_ring == NULL) { + printk(KERN_ERR "%s: unable to allocate DMA tx buffers\n", dev->name); + goto out1; } - mp->rx_ring_phys = (unsigned char *) virt_to_bus((void *)mp->rx_ring); - mp->tx_ring_phys = (unsigned char *) virt_to_bus((void *)mp->tx_ring); - - /* We want the Rx buffer to be uncached and the Tx buffer to be writethrough */ - - kernel_set_cachemode((void *)mp->rx_ring, N_RX_PAGES * PAGE_SIZE, IOMAP_NOCACHE_NONSER); - kernel_set_cachemode((void *)mp->tx_ring, PAGE_SIZE, IOMAP_WRITETHROUGH); + mp->rx_ring = dma_alloc_coherent(mp->device, + N_RX_RING * MACE_BUFF_SIZE, + &mp->rx_ring_phys, GFP_KERNEL); + if (mp->rx_ring == NULL) { + printk(KERN_ERR "%s: unable to allocate DMA rx buffers\n", dev->name); + goto out2; + } mace_dma_off(dev); @@ -348,34 +418,22 @@ static int mace_open(struct net_device *dev) psc_write_word(PSC_ENETWR_CTL, 0x0400); psc_write_word(PSC_ENETRD_CTL, 0x0400); -#if 0 - /* load up the hardware address */ - - mb->iac = ADDRCHG | PHYADDR; - - while ((mb->iac & ADDRCHG) != 0); - - for (i = 0; i < 6; ++i) - mb->padr = dev->dev_addr[i]; - - /* clear the multicast filter */ - mb->iac = ADDRCHG | LOGADDR; - - while ((mb->iac & ADDRCHG) != 0); - - for (i = 0; i < 8; ++i) - mb->ladrf = 0; - - mb->plscc = PORTSEL_GPSI + ENPLSIO; - - mb->maccc = ENXMT | ENRCV; - mb->imr = RCVINT; -#endif - mace_rxdma_reset(dev); mace_txdma_reset(dev); + /* turn it on! */ + mb->maccc = ENXMT | ENRCV; + /* enable all interrupts except receive interrupts */ + mb->imr = RCVINT; return 0; + +out2: + dma_free_coherent(mp->device, N_TX_RING * MACE_BUFF_SIZE, + mp->tx_ring, mp->tx_ring_phys); +out1: + free_irq(dev->irq, dev); + free_irq(mp->dma_intr, dev); + return -ENOMEM; } /* @@ -384,19 +442,13 @@ static int mace_open(struct net_device *dev) static int mace_close(struct net_device *dev) { - struct mace_data *mp = (struct mace_data *) dev->priv; + struct mace_data *mp = netdev_priv(dev); volatile struct mace *mb = mp->mace; mb->maccc = 0; /* disable rx and tx */ mb->imr = 0xFF; /* disable all irqs */ mace_dma_off(dev); /* disable rx and tx dma */ - free_irq(dev->irq, dev); - free_irq(IRQ_MAC_MACE_DMA, dev); - - free_pages((u32) mp->rx_ring, N_RX_PAGES); - free_pages((u32) mp->tx_ring, 0); - return 0; } @@ -406,15 +458,20 @@ static int mace_close(struct net_device *dev) static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev) { - struct mace_data *mp = (struct mace_data *) dev->priv; + struct mace_data *mp = netdev_priv(dev); + unsigned long flags; - /* Stop the queue if the buffer is full */ + /* Stop the queue since there's only the one buffer */ + local_irq_save(flags); + netif_stop_queue(dev); if (!mp->tx_count) { - netif_stop_queue(dev); - return 1; + printk(KERN_ERR "macmace: tx queue running but no free buffers.\n"); + local_irq_restore(flags); + return NETDEV_TX_BUSY; } mp->tx_count--; + local_irq_restore(flags); mp->stats.tx_packets++; mp->stats.tx_bytes += skb->len; @@ -432,23 +489,26 @@ static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev) dev_kfree_skb(skb); - return 0; + dev->trans_start = jiffies; + return NETDEV_TX_OK; } static struct net_device_stats *mace_stats(struct net_device *dev) { - struct mace_data *p = (struct mace_data *) dev->priv; - return &p->stats; + struct mace_data *mp = netdev_priv(dev); + return &mp->stats; } static void mace_set_multicast(struct net_device *dev) { - struct mace_data *mp = (struct mace_data *) dev->priv; + struct mace_data *mp = netdev_priv(dev); volatile struct mace *mb = mp->mace; int i, j; u32 crc; u8 maccc; + unsigned long flags; + local_irq_save(flags); maccc = mb->maccc; mb->maccc &= ~PROM; @@ -473,116 +533,122 @@ static void mace_set_multicast(struct net_device *dev) } } - mb->iac = ADDRCHG | LOGADDR; - while (mb->iac & ADDRCHG); - - for (i = 0; i < 8; ++i) { - mb->ladrf = multicast_filter[i]; + if (mp->chipid == BROKEN_ADDRCHG_REV) + mb->iac = LOGADDR; + else { + mb->iac = ADDRCHG | LOGADDR; + while ((mb->iac & ADDRCHG) != 0) + ; } + for (i = 0; i < 8; ++i) + mb->ladrf = multicast_filter[i]; + if (mp->chipid != BROKEN_ADDRCHG_REV) + mb->iac = 0; } mb->maccc = maccc; + local_irq_restore(flags); } -/* - * Miscellaneous interrupts are handled here. We may end up - * having to bash the chip on the head for bad errors - */ - static void mace_handle_misc_intrs(struct mace_data *mp, int intr) { volatile struct mace *mb = mp->mace; static int mace_babbles, mace_jabbers; - if (intr & MPCO) { + if (intr & MPCO) mp->stats.rx_missed_errors += 256; - } - mp->stats.rx_missed_errors += mb->mpc; /* reading clears it */ - - if (intr & RNTPCO) { + mp->stats.rx_missed_errors += mb->mpc; /* reading clears it */ + if (intr & RNTPCO) mp->stats.rx_length_errors += 256; - } - mp->stats.rx_length_errors += mb->rntpc; /* reading clears it */ - - if (intr & CERR) { + mp->stats.rx_length_errors += mb->rntpc; /* reading clears it */ + if (intr & CERR) ++mp->stats.tx_heartbeat_errors; - } - if (intr & BABBLE) { - if (mace_babbles++ < 4) { - printk(KERN_DEBUG "mace: babbling transmitter\n"); - } - } - if (intr & JABBER) { - if (mace_jabbers++ < 4) { - printk(KERN_DEBUG "mace: jabbering transceiver\n"); - } - } + if (intr & BABBLE) + if (mace_babbles++ < 4) + printk(KERN_DEBUG "macmace: babbling transmitter\n"); + if (intr & JABBER) + if (mace_jabbers++ < 4) + printk(KERN_DEBUG "macmace: jabbering transceiver\n"); } -/* - * A transmit error has occurred. (We kick the transmit side from - * the DMA completion) - */ - -static void mace_xmit_error(struct net_device *dev) +static irqreturn_t mace_interrupt(int irq, void *dev_id) { - struct mace_data *mp = (struct mace_data *) dev->priv; + struct net_device *dev = (struct net_device *) dev_id; + struct mace_data *mp = netdev_priv(dev); volatile struct mace *mb = mp->mace; - u8 xmtfs, xmtrc; + int intr, fs; + unsigned int flags; - xmtfs = mb->xmtfs; - xmtrc = mb->xmtrc; + /* don't want the dma interrupt handler to fire */ + local_irq_save(flags); - if (xmtfs & XMTSV) { - if (xmtfs & UFLO) { - printk("%s: DMA underrun.\n", dev->name); - mp->stats.tx_errors++; - mp->stats.tx_fifo_errors++; - mace_txdma_reset(dev); + intr = mb->ir; /* read interrupt register */ + mace_handle_misc_intrs(mp, intr); + + if (intr & XMTINT) { + fs = mb->xmtfs; + if ((fs & XMTSV) == 0) { + printk(KERN_ERR "macmace: xmtfs not valid! (fs=%x)\n", fs); + mace_reset(dev); + /* + * XXX mace likes to hang the machine after a xmtfs error. + * This is hard to reproduce, reseting *may* help + */ } - if (xmtfs & RTRY) { - mp->stats.collisions++; + /* dma should have finished */ + if (!mp->tx_count) { + printk(KERN_DEBUG "macmace: tx ring ran out? (fs=%x)\n", fs); + } + /* Update stats */ + if (fs & (UFLO|LCOL|LCAR|RTRY)) { + ++mp->stats.tx_errors; + if (fs & LCAR) + ++mp->stats.tx_carrier_errors; + else if (fs & (UFLO|LCOL|RTRY)) { + ++mp->stats.tx_aborted_errors; + if (mb->xmtfs & UFLO) { + printk(KERN_ERR "%s: DMA underrun.\n", dev->name); + mp->stats.tx_fifo_errors++; + mace_txdma_reset(dev); + } + } } } -} -/* - * A receive interrupt occurred. - */ + if (mp->tx_count) + netif_wake_queue(dev); -static void mace_recv_interrupt(struct net_device *dev) -{ -/* struct mace_data *mp = (struct mace_data *) dev->priv; */ -// volatile struct mace *mb = mp->mace; -} + local_irq_restore(flags); -/* - * Process the chip interrupt - */ + return IRQ_HANDLED; +} -static irqreturn_t mace_interrupt(int irq, void *dev_id) +static void mace_tx_timeout(struct net_device *dev) { - struct net_device *dev = (struct net_device *) dev_id; - struct mace_data *mp = (struct mace_data *) dev->priv; + struct mace_data *mp = netdev_priv(dev); volatile struct mace *mb = mp->mace; - u8 ir; + unsigned long flags; - ir = mb->ir; - mace_handle_misc_intrs(mp, ir); + local_irq_save(flags); - if (ir & XMTINT) { - mace_xmit_error(dev); - } - if (ir & RCVINT) { - mace_recv_interrupt(dev); - } - return IRQ_HANDLED; -} + /* turn off both tx and rx and reset the chip */ + mb->maccc = 0; + printk(KERN_ERR "macmace: transmit timeout - resetting\n"); + mace_txdma_reset(dev); + mace_reset(dev); -static void mace_tx_timeout(struct net_device *dev) -{ -/* struct mace_data *mp = (struct mace_data *) dev->priv; */ -// volatile struct mace *mb = mp->mace; + /* restart rx dma */ + mace_rxdma_reset(dev); + + mp->tx_count = N_TX_RING; + netif_wake_queue(dev); + + /* turn it on! */ + mb->maccc = ENXMT | ENRCV; + /* enable all interrupts except receive interrupts */ + mb->imr = RCVINT; + + local_irq_restore(flags); } /* @@ -591,40 +657,39 @@ static void mace_tx_timeout(struct net_device *dev) static void mace_dma_rx_frame(struct net_device *dev, struct mace_frame *mf) { - struct mace_data *mp = (struct mace_data *) dev->priv; + struct mace_data *mp = netdev_priv(dev); struct sk_buff *skb; + unsigned int frame_status = mf->rcvsts; - if (mf->status & RS_OFLO) { - printk("%s: fifo overflow.\n", dev->name); - mp->stats.rx_errors++; - mp->stats.rx_fifo_errors++; - } - if (mf->status&(RS_CLSN|RS_FRAMERR|RS_FCSERR)) + if (frame_status & (RS_OFLO | RS_CLSN | RS_FRAMERR | RS_FCSERR)) { mp->stats.rx_errors++; + if (frame_status & RS_OFLO) { + printk(KERN_DEBUG "%s: fifo overflow.\n", dev->name); + mp->stats.rx_fifo_errors++; + } + if (frame_status & RS_CLSN) + mp->stats.collisions++; + if (frame_status & RS_FRAMERR) + mp->stats.rx_frame_errors++; + if (frame_status & RS_FCSERR) + mp->stats.rx_crc_errors++; + } else { + unsigned int frame_length = mf->rcvcnt + ((frame_status & 0x0F) << 8 ); - if (mf->status&RS_CLSN) { - mp->stats.collisions++; - } - if (mf->status&RS_FRAMERR) { - mp->stats.rx_frame_errors++; - } - if (mf->status&RS_FCSERR) { - mp->stats.rx_crc_errors++; - } - - skb = dev_alloc_skb(mf->len+2); - if (!skb) { - mp->stats.rx_dropped++; - return; + skb = dev_alloc_skb(frame_length + 2); + if (!skb) { + mp->stats.rx_dropped++; + return; + } + skb_reserve(skb, 2); + memcpy(skb_put(skb, frame_length), mf->data, frame_length); + + skb->protocol = eth_type_trans(skb, dev); + netif_rx(skb); + dev->last_rx = jiffies; + mp->stats.rx_packets++; + mp->stats.rx_bytes += frame_length; } - skb_reserve(skb,2); - memcpy(skb_put(skb, mf->len), mf->data, mf->len); - - skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); - dev->last_rx = jiffies; - mp->stats.rx_packets++; - mp->stats.rx_bytes += mf->len; } /* @@ -634,7 +699,7 @@ static void mace_dma_rx_frame(struct net_device *dev, struct mace_frame *mf) static irqreturn_t mace_dma_intr(int irq, void *dev_id) { struct net_device *dev = (struct net_device *) dev_id; - struct mace_data *mp = (struct mace_data *) dev->priv; + struct mace_data *mp = netdev_priv(dev); int left, head; u16 status; u32 baka; @@ -661,7 +726,8 @@ static irqreturn_t mace_dma_intr(int irq, void *dev_id) /* Loop through the ring buffer and process new packages */ while (mp->rx_tail < head) { - mace_dma_rx_frame(dev, (struct mace_frame *) (mp->rx_ring + (mp->rx_tail * 0x0800))); + mace_dma_rx_frame(dev, (struct mace_frame*) (mp->rx_ring + + (mp->rx_tail * MACE_BUFF_SIZE))); mp->rx_tail++; } @@ -688,9 +754,76 @@ static irqreturn_t mace_dma_intr(int irq, void *dev_id) psc_write_word(PSC_ENETWR_CMD + mp->tx_sloti, 0x0100); mp->tx_sloti ^= 0x10; mp->tx_count++; - netif_wake_queue(dev); } return IRQ_HANDLED; } MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Macintosh MACE ethernet driver"); + +static int __devexit mac_mace_device_remove (struct platform_device *pdev) +{ + struct net_device *dev = platform_get_drvdata(pdev); + struct mace_data *mp = netdev_priv(dev); + + unregister_netdev(dev); + + free_irq(dev->irq, dev); + free_irq(IRQ_MAC_MACE_DMA, dev); + + dma_free_coherent(mp->device, N_RX_RING * MACE_BUFF_SIZE, + mp->rx_ring, mp->rx_ring_phys); + dma_free_coherent(mp->device, N_TX_RING * MACE_BUFF_SIZE, + mp->tx_ring, mp->tx_ring_phys); + + free_netdev(dev); + + return 0; +} + +static struct platform_driver mac_mace_driver = { + .probe = mace_probe, + .remove = __devexit_p(mac_mace_device_remove), + .driver = { + .name = mac_mace_string, + }, +}; + +static int __init mac_mace_init_module(void) +{ + int err; + + if ((err = platform_driver_register(&mac_mace_driver))) { + printk(KERN_ERR "Driver registration failed\n"); + return err; + } + + mac_mace_device = platform_device_alloc(mac_mace_string, 0); + if (!mac_mace_device) + goto out_unregister; + + if (platform_device_add(mac_mace_device)) { + platform_device_put(mac_mace_device); + mac_mace_device = NULL; + } + + return 0; + +out_unregister: + platform_driver_unregister(&mac_mace_driver); + + return -ENOMEM; +} + +static void __exit mac_mace_cleanup_module(void) +{ + platform_driver_unregister(&mac_mace_driver); + + if (mac_mace_device) { + platform_device_unregister(mac_mace_device); + mac_mace_device = NULL; + } +} + +module_init(mac_mace_init_module); +module_exit(mac_mace_cleanup_module); diff --git a/drivers/net/macsonic.c b/drivers/net/macsonic.c index 8ca57a0a4c1..e9ecdbf352a 100644 --- a/drivers/net/macsonic.c +++ b/drivers/net/macsonic.c @@ -130,6 +130,46 @@ static inline void bit_reverse_addr(unsigned char addr[6]) addr[i] = bitrev8(addr[i]); } +static irqreturn_t macsonic_interrupt(int irq, void *dev_id) +{ + irqreturn_t result; + unsigned long flags; + + local_irq_save(flags); + result = sonic_interrupt(irq, dev_id); + local_irq_restore(flags); + return result; +} + +static int macsonic_open(struct net_device* dev) +{ + if (request_irq(dev->irq, &sonic_interrupt, IRQ_FLG_FAST, "sonic", dev)) { + printk(KERN_ERR "%s: unable to get IRQ %d.\n", dev->name, dev->irq); + return -EAGAIN; + } + /* Under the A/UX interrupt scheme, the onboard SONIC interrupt comes + * in at priority level 3. However, we sometimes get the level 2 inter- + * rupt as well, which must prevent re-entrance of the sonic handler. + */ + if (dev->irq == IRQ_AUTO_3) + if (request_irq(IRQ_NUBUS_9, &macsonic_interrupt, IRQ_FLG_FAST, "sonic", dev)) { + printk(KERN_ERR "%s: unable to get IRQ %d.\n", dev->name, IRQ_NUBUS_9); + free_irq(dev->irq, dev); + return -EAGAIN; + } + return sonic_open(dev); +} + +static int macsonic_close(struct net_device* dev) +{ + int err; + err = sonic_close(dev); + free_irq(dev->irq, dev); + if (dev->irq == IRQ_AUTO_3) + free_irq(IRQ_NUBUS_9, dev); + return err; +} + int __init macsonic_init(struct net_device* dev) { struct sonic_local* lp = netdev_priv(dev); @@ -160,8 +200,8 @@ int __init macsonic_init(struct net_device* dev) lp->rra_laddr = lp->rda_laddr + (SIZEOF_SONIC_RD * SONIC_NUM_RDS * SONIC_BUS_SCALE(lp->dma_bitmode)); - dev->open = sonic_open; - dev->stop = sonic_close; + dev->open = macsonic_open; + dev->stop = macsonic_close; dev->hard_start_xmit = sonic_send_packet; dev->get_stats = sonic_get_stats; dev->set_multicast_list = &sonic_multicast_list; @@ -402,7 +442,7 @@ int __init macsonic_ident(struct nubus_dev* ndev) ndev->dr_sw == NUBUS_DRSW_DAYNA) return MACSONIC_DAYNA; - if (ndev->dr_hw == NUBUS_DRHW_SONIC_LC && + if (ndev->dr_hw == NUBUS_DRHW_APPLE_SONIC_LC && ndev->dr_sw == 0) { /* huh? */ return MACSONIC_APPLE16; } @@ -522,7 +562,7 @@ int __init mac_nubus_sonic_probe(struct net_device* dev) return macsonic_init(dev); } -static int __init mac_sonic_probe(struct platform_device *device) +static int __init mac_sonic_probe(struct platform_device *pdev) { struct net_device *dev; struct sonic_local *lp; @@ -534,8 +574,8 @@ static int __init mac_sonic_probe(struct platform_device *device) return -ENOMEM; lp = netdev_priv(dev); - lp->device = &device->dev; - SET_NETDEV_DEV(dev, &device->dev); + lp->device = &pdev->dev; + SET_NETDEV_DEV(dev, &pdev->dev); SET_MODULE_OWNER(dev); /* This will catch fatal stuff like -ENOMEM as well as success */ @@ -572,19 +612,17 @@ MODULE_DESCRIPTION("Macintosh SONIC ethernet driver"); module_param(sonic_debug, int, 0); MODULE_PARM_DESC(sonic_debug, "macsonic debug level (1-4)"); -#define SONIC_IRQ_FLAG IRQ_FLG_FAST - #include "sonic.c" -static int __devexit mac_sonic_device_remove (struct platform_device *device) +static int __devexit mac_sonic_device_remove (struct platform_device *pdev) { - struct net_device *dev = platform_get_drvdata(device); + struct net_device *dev = platform_get_drvdata(pdev); struct sonic_local* lp = netdev_priv(dev); - unregister_netdev (dev); + unregister_netdev(dev); dma_free_coherent(lp->device, SIZEOF_SONIC_DESC * SONIC_BUS_SCALE(lp->dma_bitmode), lp->descriptors, lp->descriptors_laddr); - free_netdev (dev); + free_netdev(dev); return 0; } @@ -607,9 +645,8 @@ static int __init mac_sonic_init_module(void) } mac_sonic_device = platform_device_alloc(mac_sonic_string, 0); - if (!mac_sonic_device) { + if (!mac_sonic_device) goto out_unregister; - } if (platform_device_add(mac_sonic_device)) { platform_device_put(mac_sonic_device); diff --git a/drivers/net/sonic.c b/drivers/net/sonic.c index c6320c71993..8069f3e32d8 100644 --- a/drivers/net/sonic.c +++ b/drivers/net/sonic.c @@ -50,29 +50,6 @@ static int sonic_open(struct net_device *dev) if (sonic_debug > 2) printk("sonic_open: initializing sonic driver.\n"); - /* - * We don't need to deal with auto-irq stuff since we - * hardwire the sonic interrupt. - */ -/* - * XXX Horrible work around: We install sonic_interrupt as fast interrupt. - * This means that during execution of the handler interrupt are disabled - * covering another bug otherwise corrupting data. This doesn't mean - * this glue works ok under all situations. - * - * Note (dhd): this also appears to prevent lockups on the Macintrash - * when more than one Ethernet card is installed (knock on wood) - * - * Note (fthain): whether the above is still true is anyones guess. Certainly - * the buffer handling algorithms will not tolerate re-entrance without some - * mutual exclusion added. Anyway, the memcpy has now been eliminated from the - * rx code to make this a faster "fast interrupt". - */ - if (request_irq(dev->irq, &sonic_interrupt, SONIC_IRQ_FLAG, "sonic", dev)) { - printk(KERN_ERR "\n%s: unable to get IRQ %d .\n", dev->name, dev->irq); - return -EAGAIN; - } - for (i = 0; i < SONIC_NUM_RRS; i++) { struct sk_buff *skb = dev_alloc_skb(SONIC_RBSIZE + 2); if (skb == NULL) { @@ -169,8 +146,6 @@ static int sonic_close(struct net_device *dev) } } - free_irq(dev->irq, dev); /* release the IRQ */ - return 0; } @@ -178,8 +153,13 @@ static void sonic_tx_timeout(struct net_device *dev) { struct sonic_local *lp = netdev_priv(dev); int i; - /* Stop the interrupts for this */ + /* + * put the Sonic into software-reset mode and + * disable all interrupts before releasing DMA buffers + */ SONIC_WRITE(SONIC_IMR, 0); + SONIC_WRITE(SONIC_ISR, 0x7fff); + SONIC_WRITE(SONIC_CMD, SONIC_CR_RST); /* We could resend the original skbs. Easier to re-initialise. */ for (i = 0; i < SONIC_NUM_TDS; i++) { if(lp->tx_laddr[i]) { diff --git a/drivers/net/sun3_82586.c b/drivers/net/sun3_82586.c index 396c3d961f8..a123ea87893 100644 --- a/drivers/net/sun3_82586.c +++ b/drivers/net/sun3_82586.c @@ -1023,10 +1023,11 @@ static int sun3_82586_send_packet(struct sk_buff *skb, struct net_device *dev) { len = skb->len; if (len < ETH_ZLEN) { - memset((char *)p->xmit_cbuffs[p->xmit_count], 0, ETH_ZLEN); + memset((void *)p->xmit_cbuffs[p->xmit_count], 0, + ETH_ZLEN); len = ETH_ZLEN; } - skb_copy_from_linear_data(skb, p->xmit_cbuffs[p->xmit_count], skb->len); + skb_copy_from_linear_data(skb, (void *)p->xmit_cbuffs[p->xmit_count], skb->len); #if (NUM_XMIT_BUFFS == 1) # ifdef NO_NOPCOMMANDS diff --git a/drivers/ps3/ps3av.c b/drivers/ps3/ps3av.c index d21e04ccb02..1393e64335f 100644 --- a/drivers/ps3/ps3av.c +++ b/drivers/ps3/ps3av.c @@ -38,7 +38,24 @@ static int timeout = 5000; /* in msec ( 5 sec ) */ module_param(timeout, int, 0644); -static struct ps3av ps3av; +static struct ps3av { + int available; + struct mutex mutex; + struct work_struct work; + struct completion done; + struct workqueue_struct *wq; + int open_count; + struct ps3_vuart_port_device *dev; + + int region; + struct ps3av_pkt_av_get_hw_conf av_hw_conf; + u32 av_port[PS3AV_AV_PORT_MAX + PS3AV_OPT_PORT_MAX]; + u32 opt_port[PS3AV_OPT_PORT_MAX]; + u32 head[PS3AV_HEAD_MAX]; + u32 audio_port; + int ps3av_mode; + int ps3av_mode_old; +} ps3av; static struct ps3_vuart_port_device ps3av_dev = { .match_id = PS3_MATCH_ID_AV_SETTINGS @@ -159,7 +176,7 @@ static int ps3av_parse_event_packet(const struct ps3av_reply_hdr *hdr) else printk(KERN_ERR "%s: failed event packet, cid:%08x size:%d\n", - __FUNCTION__, hdr->cid, hdr->size); + __func__, hdr->cid, hdr->size); return 1; /* receive event packet */ } return 0; @@ -181,7 +198,7 @@ static int ps3av_send_cmd_pkt(const struct ps3av_send_hdr *send_buf, if (res < 0) { dev_dbg(&ps3av_dev.core, "%s: ps3av_vuart_write() failed (result=%d)\n", - __FUNCTION__, res); + __func__, res); return res; } @@ -194,7 +211,7 @@ static int ps3av_send_cmd_pkt(const struct ps3av_send_hdr *send_buf, if (res != PS3AV_HDR_SIZE) { dev_dbg(&ps3av_dev.core, "%s: ps3av_vuart_read() failed (result=%d)\n", - __FUNCTION__, res); + __func__, res); return res; } @@ -204,7 +221,7 @@ static int ps3av_send_cmd_pkt(const struct ps3av_send_hdr *send_buf, if (res < 0) { dev_dbg(&ps3av_dev.core, "%s: ps3av_vuart_read() failed (result=%d)\n", - __FUNCTION__, res); + __func__, res); return res; } res += PS3AV_HDR_SIZE; /* total len */ @@ -214,7 +231,7 @@ static int ps3av_send_cmd_pkt(const struct ps3av_send_hdr *send_buf, if ((cmd | PS3AV_REPLY_BIT) != recv_buf->cid) { dev_dbg(&ps3av_dev.core, "%s: reply err (result=%x)\n", - __FUNCTION__, recv_buf->cid); + __func__, recv_buf->cid); return -EINVAL; } @@ -250,7 +267,7 @@ int ps3av_do_pkt(u32 cid, u16 send_len, size_t usr_buf_size, struct ps3av_send_hdr *buf) { int res = 0; - union { + static union { struct ps3av_reply_hdr reply_hdr; u8 raw[PS3AV_BUF_SIZE]; } recv_buf; @@ -259,8 +276,7 @@ int ps3av_do_pkt(u32 cid, u16 send_len, size_t usr_buf_size, BUG_ON(!ps3av.available); - if (down_interruptible(&ps3av.sem)) - return -ERESTARTSYS; + mutex_lock(&ps3av.mutex); table = ps3av_search_cmd_table(cid, PS3AV_CID_MASK); BUG_ON(!table); @@ -277,7 +293,7 @@ int ps3av_do_pkt(u32 cid, u16 send_len, size_t usr_buf_size, if (res < 0) { printk(KERN_ERR "%s: ps3av_send_cmd_pkt() failed (result=%d)\n", - __FUNCTION__, res); + __func__, res); goto err; } @@ -286,16 +302,16 @@ int ps3av_do_pkt(u32 cid, u16 send_len, size_t usr_buf_size, usr_buf_size); if (res < 0) { printk(KERN_ERR "%s: put_return_status() failed (result=%d)\n", - __FUNCTION__, res); + __func__, res); goto err; } - up(&ps3av.sem); + mutex_unlock(&ps3av.mutex); return 0; err: - up(&ps3av.sem); - printk(KERN_ERR "%s: failed cid:%x res:%d\n", __FUNCTION__, cid, res); + mutex_unlock(&ps3av.mutex); + printk(KERN_ERR "%s: failed cid:%x res:%d\n", __func__, cid, res); return res; } @@ -440,7 +456,7 @@ static int ps3av_set_videomode(void) ps3av_set_av_video_mute(PS3AV_CMD_MUTE_ON); /* wake up ps3avd to do the actual video mode setting */ - up(&ps3av.ping); + queue_work(ps3av.wq, &ps3av.work); return 0; } @@ -506,7 +522,7 @@ static void ps3av_set_videomode_cont(u32 id, u32 old_id) if (res == PS3AV_STATUS_NO_SYNC_HEAD) printk(KERN_WARNING "%s: Command failed. Please try your request again. \n", - __FUNCTION__); + __func__); else if (res) dev_dbg(&ps3av_dev.core, "ps3av_cmd_avb_param failed\n"); @@ -515,18 +531,10 @@ static void ps3av_set_videomode_cont(u32 id, u32 old_id) ps3av_set_av_video_mute(PS3AV_CMD_MUTE_OFF); } -static int ps3avd(void *p) +static void ps3avd(struct work_struct *work) { - struct ps3av *info = p; - - daemonize("ps3avd"); - while (1) { - down(&info->ping); - ps3av_set_videomode_cont(info->ps3av_mode, - info->ps3av_mode_old); - up(&info->pong); - } - return 0; + ps3av_set_videomode_cont(ps3av.ps3av_mode, ps3av.ps3av_mode_old); + complete(&ps3av.done); } static int ps3av_vid2table_id(int vid) @@ -707,8 +715,7 @@ int ps3av_set_video_mode(u32 id, int boot) size = ARRAY_SIZE(video_mode_table); if ((id & PS3AV_MODE_MASK) > size - 1 || id < 0) { - dev_dbg(&ps3av_dev.core, "%s: error id :%d\n", __FUNCTION__, - id); + dev_dbg(&ps3av_dev.core, "%s: error id :%d\n", __func__, id); return -EINVAL; } @@ -717,15 +724,14 @@ int ps3av_set_video_mode(u32 id, int boot) if ((id & PS3AV_MODE_MASK) == 0) { id = ps3av_auto_videomode(&ps3av.av_hw_conf, boot); if (id < 1) { - printk(KERN_ERR "%s: invalid id :%d\n", __FUNCTION__, - id); + printk(KERN_ERR "%s: invalid id :%d\n", __func__, id); return -EINVAL; } id |= option; } /* set videomode */ - down(&ps3av.pong); + wait_for_completion(&ps3av.done); ps3av.ps3av_mode_old = ps3av.ps3av_mode; ps3av.ps3av_mode = id; if (ps3av_set_videomode()) @@ -736,6 +742,13 @@ int ps3av_set_video_mode(u32 id, int boot) EXPORT_SYMBOL_GPL(ps3av_set_video_mode); +int ps3av_get_auto_mode(int boot) +{ + return ps3av_auto_videomode(&ps3av.av_hw_conf, boot); +} + +EXPORT_SYMBOL_GPL(ps3av_get_auto_mode); + int ps3av_set_mode(u32 id, int boot) { int res; @@ -771,7 +784,7 @@ int ps3av_get_scanmode(int id) id = id & PS3AV_MODE_MASK; size = ARRAY_SIZE(video_mode_table); if (id > size - 1 || id < 0) { - printk(KERN_ERR "%s: invalid mode %d\n", __FUNCTION__, id); + printk(KERN_ERR "%s: invalid mode %d\n", __func__, id); return -EINVAL; } return video_mode_table[id].interlace; @@ -786,7 +799,7 @@ int ps3av_get_refresh_rate(int id) id = id & PS3AV_MODE_MASK; size = ARRAY_SIZE(video_mode_table); if (id > size - 1 || id < 0) { - printk(KERN_ERR "%s: invalid mode %d\n", __FUNCTION__, id); + printk(KERN_ERR "%s: invalid mode %d\n", __func__, id); return -EINVAL; } return video_mode_table[id].freq; @@ -802,7 +815,7 @@ int ps3av_video_mode2res(u32 id, u32 *xres, u32 *yres) id = id & PS3AV_MODE_MASK; size = ARRAY_SIZE(video_mode_table); if (id > size - 1 || id < 0) { - printk(KERN_ERR "%s: invalid mode %d\n", __FUNCTION__, id); + printk(KERN_ERR "%s: invalid mode %d\n", __func__, id); return -EINVAL; } *xres = video_mode_table[id].x; @@ -838,7 +851,7 @@ int ps3av_dev_open(void) status = lv1_gpu_open(0); if (status) { printk(KERN_ERR "%s: lv1_gpu_open failed %d\n", - __FUNCTION__, status); + __func__, status); ps3av.open_count--; } } @@ -855,13 +868,13 @@ int ps3av_dev_close(void) mutex_lock(&ps3av.mutex); if (ps3av.open_count <= 0) { - printk(KERN_ERR "%s: GPU already closed\n", __FUNCTION__); + printk(KERN_ERR "%s: GPU already closed\n", __func__); status = -1; } else if (!--ps3av.open_count) { status = lv1_gpu_close(); if (status) printk(KERN_WARNING "%s: lv1_gpu_close failed %d\n", - __FUNCTION__, status); + __func__, status); } mutex_unlock(&ps3av.mutex); @@ -880,13 +893,16 @@ static int ps3av_probe(struct ps3_vuart_port_device *dev) memset(&ps3av, 0, sizeof(ps3av)); - init_MUTEX(&ps3av.sem); - init_MUTEX_LOCKED(&ps3av.ping); - init_MUTEX(&ps3av.pong); mutex_init(&ps3av.mutex); ps3av.ps3av_mode = 0; ps3av.dev = dev; - kernel_thread(ps3avd, &ps3av, CLONE_KERNEL); + + INIT_WORK(&ps3av.work, ps3avd); + init_completion(&ps3av.done); + complete(&ps3av.done); + ps3av.wq = create_singlethread_workqueue("ps3avd"); + if (!ps3av.wq) + return -ENOMEM; ps3av.available = 1; switch (ps3_os_area_get_av_multi_out()) { @@ -908,7 +924,7 @@ static int ps3av_probe(struct ps3_vuart_port_device *dev) /* init avsetting modules */ res = ps3av_cmd_init(); if (res < 0) - printk(KERN_ERR "%s: ps3av_cmd_init failed %d\n", __FUNCTION__, + printk(KERN_ERR "%s: ps3av_cmd_init failed %d\n", __func__, res); ps3av_get_hw_conf(&ps3av); @@ -926,6 +942,8 @@ static int ps3av_remove(struct ps3_vuart_port_device *dev) { if (ps3av.available) { ps3av_cmd_fin(); + if (ps3av.wq) + destroy_workqueue(ps3av.wq); ps3av.available = 0; } @@ -958,7 +976,7 @@ static int ps3av_module_init(void) if (error) { printk(KERN_ERR "%s: ps3_vuart_port_driver_register failed %d\n", - __FUNCTION__, error); + __func__, error); return error; } @@ -966,7 +984,7 @@ static int ps3av_module_init(void) if (error) printk(KERN_ERR "%s: ps3_vuart_port_device_register failed %d\n", - __FUNCTION__, error); + __func__, error); return error; } diff --git a/drivers/ps3/ps3av_cmd.c b/drivers/ps3/ps3av_cmd.c index bc70e81f8cb..0145ea173c4 100644 --- a/drivers/ps3/ps3av_cmd.c +++ b/drivers/ps3/ps3av_cmd.c @@ -395,7 +395,7 @@ u32 ps3av_cmd_set_video_mode(void *p, u32 head, int video_vid, int video_fmt, video_mode->video_order = ps3av_video_fmt_table[video_fmt].order; pr_debug("%s: video_mode:vid:%x width:%d height:%d pitch:%d out_format:%d format:%x order:%x\n", - __FUNCTION__, video_vid, video_mode->width, video_mode->height, + __func__, video_vid, video_mode->width, video_mode->height, video_mode->pitch, video_mode->video_out_format, video_mode->video_format, video_mode->video_order); return sizeof(*video_mode); @@ -477,7 +477,7 @@ static u8 ps3av_cnv_mclk(u32 fs) if (ps3av_cnv_mclk_table[i].fs == fs) return ps3av_cnv_mclk_table[i].mclk; - printk(KERN_ERR "%s failed, fs:%x\n", __FUNCTION__, fs); + printk(KERN_ERR "%s failed, fs:%x\n", __func__, fs); return 0; } @@ -526,13 +526,12 @@ static void ps3av_cnv_ns(u8 *ns, u32 fs, u32 video_vid) d = 4; break; default: - printk(KERN_ERR "%s failed, vid:%x\n", __FUNCTION__, - video_vid); + printk(KERN_ERR "%s failed, vid:%x\n", __func__, video_vid); break; } if (fs < PS3AV_CMD_AUDIO_FS_44K || fs > PS3AV_CMD_AUDIO_FS_192K) - printk(KERN_ERR "%s failed, fs:%x\n", __FUNCTION__, fs); + printk(KERN_ERR "%s failed, fs:%x\n", __func__, fs); else ns_val = ps3av_ns_table[PS3AV_CMD_AUDIO_FS_44K-BASE][d]; @@ -555,8 +554,7 @@ static u8 ps3av_cnv_enable(u32 source, const u8 *enable) ret = ((p[0] << 4) + (p[1] << 5) + (p[2] << 6) + (p[3] << 7)) | 0x01; } else - printk(KERN_ERR "%s failed, source:%x\n", __FUNCTION__, - source); + printk(KERN_ERR "%s failed, source:%x\n", __func__, source); return ret; } @@ -585,7 +583,7 @@ static u8 ps3av_cnv_inputlen(u32 word_bits) ret = PS3AV_CMD_AV_INPUTLEN_24; break; default: - printk(KERN_ERR "%s failed, word_bits:%x\n", __FUNCTION__, + printk(KERN_ERR "%s failed, word_bits:%x\n", __func__, word_bits); break; } @@ -595,7 +593,7 @@ static u8 ps3av_cnv_inputlen(u32 word_bits) static u8 ps3av_cnv_layout(u32 num_of_ch) { if (num_of_ch > PS3AV_CMD_AUDIO_NUM_OF_CH_8) { - printk(KERN_ERR "%s failed, num_of_ch:%x\n", __FUNCTION__, + printk(KERN_ERR "%s failed, num_of_ch:%x\n", __func__, num_of_ch); return 0; } @@ -864,7 +862,7 @@ int ps3av_cmd_avb_param(struct ps3av_pkt_avb_param *avb, u32 send_len) res = get_status(avb); if (res) - pr_debug("%s: PS3AV_CID_AVB_PARAM: failed %x\n", __FUNCTION__, + pr_debug("%s: PS3AV_CID_AVB_PARAM: failed %x\n", __func__, res); out: @@ -1013,7 +1011,7 @@ int ps3av_vuart_read(struct ps3_vuart_port_device *dev, void *buf, return size; if (error != -EAGAIN) { printk(KERN_ERR "%s: ps3_vuart_read failed %d\n", - __FUNCTION__, error); + __func__, error); return error; } msleep(POLLING_INTERVAL); diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index e71929db8b0..977521013fe 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -2174,6 +2174,51 @@ dasd_generic_notify(struct ccw_device *cdev, int event) return ret; } +struct dasd_ccw_req * dasd_generic_build_rdc(struct dasd_device *device, + void *rdc_buffer, + int rdc_buffer_size, char *magic) +{ + struct dasd_ccw_req *cqr; + struct ccw1 *ccw; + + cqr = dasd_smalloc_request(magic, 1 /* RDC */, rdc_buffer_size, device); + + if (IS_ERR(cqr)) { + DEV_MESSAGE(KERN_WARNING, device, "%s", + "Could not allocate RDC request"); + return cqr; + } + + ccw = cqr->cpaddr; + ccw->cmd_code = CCW_CMD_RDC; + ccw->cda = (__u32)(addr_t)rdc_buffer; + ccw->count = rdc_buffer_size; + + cqr->device = device; + cqr->expires = 10*HZ; + clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); + cqr->retries = 2; + cqr->buildclk = get_clock(); + cqr->status = DASD_CQR_FILLED; + return cqr; +} + + +int dasd_generic_read_dev_chars(struct dasd_device *device, char *magic, + void **rdc_buffer, int rdc_buffer_size) +{ + int ret; + struct dasd_ccw_req *cqr; + + cqr = dasd_generic_build_rdc(device, *rdc_buffer, rdc_buffer_size, + magic); + if (IS_ERR(cqr)) + return PTR_ERR(cqr); + + ret = dasd_sleep_on(cqr); + dasd_sfree_request(cqr, cqr->device); + return ret; +} static int __init dasd_init(void) diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index cecab2274a6..c9583fbc2a7 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -450,6 +450,81 @@ dasd_eckd_generate_uid(struct dasd_device *device, struct dasd_uid *uid) return 0; } +struct dasd_ccw_req * dasd_eckd_build_rcd_lpm(struct dasd_device *device, + void *rcd_buffer, + struct ciw *ciw, __u8 lpm) +{ + struct dasd_ccw_req *cqr; + struct ccw1 *ccw; + + cqr = dasd_smalloc_request("ECKD", 1 /* RCD */, ciw->count, device); + + if (IS_ERR(cqr)) { + DEV_MESSAGE(KERN_WARNING, device, "%s", + "Could not allocate RCD request"); + return cqr; + } + + ccw = cqr->cpaddr; + ccw->cmd_code = ciw->cmd; + ccw->cda = (__u32)(addr_t)rcd_buffer; + ccw->count = ciw->count; + + cqr->device = device; + cqr->expires = 10*HZ; + cqr->lpm = lpm; + clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); + cqr->retries = 2; + cqr->buildclk = get_clock(); + cqr->status = DASD_CQR_FILLED; + return cqr; +} + +static int dasd_eckd_read_conf_lpm(struct dasd_device *device, + void **rcd_buffer, + int *rcd_buffer_size, __u8 lpm) +{ + struct ciw *ciw; + char *rcd_buf = NULL; + int ret; + struct dasd_ccw_req *cqr; + + /* + * scan for RCD command in extended SenseID data + */ + ciw = ccw_device_get_ciw(device->cdev, CIW_TYPE_RCD); + if (!ciw || ciw->cmd == 0) { + ret = -EOPNOTSUPP; + goto out_error; + } + rcd_buf = kzalloc(ciw->count, GFP_KERNEL | GFP_DMA); + if (!rcd_buf) { + ret = -ENOMEM; + goto out_error; + } + cqr = dasd_eckd_build_rcd_lpm(device, rcd_buf, ciw, lpm); + if (IS_ERR(cqr)) { + ret = PTR_ERR(cqr); + goto out_error; + } + ret = dasd_sleep_on(cqr); + /* + * on success we update the user input parms + */ + dasd_sfree_request(cqr, cqr->device); + if (ret) + goto out_error; + + *rcd_buffer_size = ciw->count; + *rcd_buffer = rcd_buf; + return 0; +out_error: + kfree(rcd_buf); + *rcd_buffer = NULL; + *rcd_buffer_size = 0; + return ret; +} + static int dasd_eckd_read_conf(struct dasd_device *device) { @@ -469,8 +544,8 @@ dasd_eckd_read_conf(struct dasd_device *device) /* get configuration data per operational path */ for (lpm = 0x80; lpm; lpm>>= 1) { if (lpm & path_data->opm){ - rc = read_conf_data_lpm(device->cdev, &conf_data, - &conf_len, lpm); + rc = dasd_eckd_read_conf_lpm(device, &conf_data, + &conf_len, lpm); if (rc && rc != -EOPNOTSUPP) { /* -EOPNOTSUPP is ok */ MESSAGE(KERN_WARNING, "Read configuration data returned " @@ -639,7 +714,7 @@ dasd_eckd_check_characteristics(struct dasd_device *device) /* Read Device Characteristics */ rdc_data = (void *) &(private->rdc_data); memset(rdc_data, 0, sizeof(rdc_data)); - rc = read_dev_chars(device->cdev, &rdc_data, 64); + rc = dasd_generic_read_dev_chars(device, "ECKD", &rdc_data, 64); if (rc) DEV_MESSAGE(KERN_WARNING, device, "Read device characteristics returned " diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c index be0909e3922..da16ead8aff 100644 --- a/drivers/s390/block/dasd_fba.c +++ b/drivers/s390/block/dasd_fba.c @@ -135,7 +135,7 @@ dasd_fba_check_characteristics(struct dasd_device *device) } /* Read Device Characteristics */ rdc_data = (void *) &(private->rdc_data); - rc = read_dev_chars(device->cdev, &rdc_data, 32); + rc = dasd_generic_read_dev_chars(device, "FBA ", &rdc_data, 32); if (rc) { DEV_MESSAGE(KERN_WARNING, device, "Read device characteristics returned error %d", diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index a2cc69e1141..241294cba41 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h @@ -509,6 +509,8 @@ int dasd_generic_set_online(struct ccw_device *, struct dasd_discipline *); int dasd_generic_set_offline (struct ccw_device *cdev); int dasd_generic_notify(struct ccw_device *, int); +int dasd_generic_read_dev_chars(struct dasd_device *, char *, void **, int); + /* externals in dasd_devmap.c */ extern int dasd_max_devindex; extern int dasd_probeonly; diff --git a/drivers/s390/char/tape.h b/drivers/s390/char/tape.h index bb4ff537729..3b52f5c1dbe 100644 --- a/drivers/s390/char/tape.h +++ b/drivers/s390/char/tape.h @@ -103,6 +103,7 @@ enum tape_op { TO_CRYPT_OFF, /* Disable encrpytion */ TO_KEKL_SET, /* Set KEK label */ TO_KEKL_QUERY, /* Query KEK label */ + TO_RDC, /* Read device characteristics */ TO_SIZE, /* #entries in tape_op_t */ }; diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c index 50f5edab83d..7e2b2ab4926 100644 --- a/drivers/s390/char/tape_3590.c +++ b/drivers/s390/char/tape_3590.c @@ -788,6 +788,7 @@ tape_3590_done(struct tape_device *device, struct tape_request *request) case TO_SIZE: case TO_KEKL_SET: case TO_KEKL_QUERY: + case TO_RDC: break; } return TAPE_IO_SUCCESS; @@ -1549,6 +1550,26 @@ tape_3590_irq(struct tape_device *device, struct tape_request *request, return TAPE_IO_STOP; } + +static int tape_3590_read_dev_chars(struct tape_device *device, + struct tape_3590_rdc_data *rdc_data) +{ + int rc; + struct tape_request *request; + + request = tape_alloc_request(1, sizeof(*rdc_data)); + if (IS_ERR(request)) + return PTR_ERR(request); + request->op = TO_RDC; + tape_ccw_end(request->cpaddr, CCW_CMD_RDC, sizeof(*rdc_data), + request->cpdata); + rc = tape_do_io(device, request); + if (rc == 0) + memcpy(rdc_data, request->cpdata, sizeof(*rdc_data)); + tape_free_request(request); + return rc; +} + /* * Setup device function */ @@ -1557,7 +1578,7 @@ tape_3590_setup_device(struct tape_device *device) { int rc; struct tape_3590_disc_data *data; - char *rdc_data; + struct tape_3590_rdc_data *rdc_data; DBF_EVENT(6, "3590 device setup\n"); data = kzalloc(sizeof(struct tape_3590_disc_data), GFP_KERNEL | GFP_DMA); @@ -1566,12 +1587,12 @@ tape_3590_setup_device(struct tape_device *device) data->read_back_op = READ_PREVIOUS; device->discdata = data; - rdc_data = kmalloc(64, GFP_KERNEL | GFP_DMA); + rdc_data = kmalloc(sizeof(*rdc_data), GFP_KERNEL | GFP_DMA); if (!rdc_data) { rc = -ENOMEM; goto fail_kmalloc; } - rc = read_dev_chars(device->cdev, (void**)&rdc_data, 64); + rc = tape_3590_read_dev_chars(device, rdc_data); if (rc) { DBF_LH(3, "Read device characteristics failed!\n"); goto fail_kmalloc; @@ -1579,7 +1600,7 @@ tape_3590_setup_device(struct tape_device *device) rc = tape_std_assign(device); if (rc) goto fail_rdc_data; - if (rdc_data[31] == 0x13) { + if (rdc_data->data[31] == 0x13) { PRINT_INFO("Device has crypto support\n"); data->crypt_info.capability |= TAPE390_CRYPT_SUPPORTED_MASK; tape_3592_disable_crypt(device); diff --git a/drivers/s390/char/tape_3590.h b/drivers/s390/char/tape_3590.h index aa5138807af..4534055f137 100644 --- a/drivers/s390/char/tape_3590.h +++ b/drivers/s390/char/tape_3590.h @@ -129,6 +129,10 @@ struct tape_3590_med_sense { char pad2[116]; } __attribute__ ((packed)); +struct tape_3590_rdc_data { + char data[64]; +} __attribute__ ((packed)); + /* Datastructures for 3592 encryption support */ struct tape3592_kekl { diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c index e2a8a1a04ba..2fae6338ee1 100644 --- a/drivers/s390/char/tape_core.c +++ b/drivers/s390/char/tape_core.c @@ -73,7 +73,7 @@ const char *tape_op_verbose[TO_SIZE] = [TO_DIS] = "DIS", [TO_ASSIGN] = "ASS", [TO_UNASSIGN] = "UAS", [TO_CRYPT_ON] = "CON", [TO_CRYPT_OFF] = "COF", [TO_KEKL_SET] = "KLS", - [TO_KEKL_QUERY] = "KLQ", + [TO_KEKL_QUERY] = "KLQ",[TO_RDC] = "RDC", }; static int @@ -911,6 +911,7 @@ __tape_start_request(struct tape_device *device, struct tape_request *request) case TO_ASSIGN: case TO_UNASSIGN: case TO_READ_ATTMSG: + case TO_RDC: if (device->tape_state == TS_INIT) break; if (device->tape_state == TS_UNUSED) diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c index 05fac0733f3..cba64e4cfcd 100644 --- a/drivers/s390/cio/qdio.c +++ b/drivers/s390/cio/qdio.c @@ -69,7 +69,6 @@ static const char version[] = "QDIO base support version 2"; static int qdio_performance_stats = 0; static int proc_perf_file_registration; -static unsigned long i_p_c, i_p_nc, o_p_c, o_p_nc, ii_p_c, ii_p_nc; static struct qdio_perf_stats perf_stats; static int hydra_thinints; @@ -111,6 +110,31 @@ qdio_min(int a,int b) } /***************** SCRUBBER HELPER ROUTINES **********************/ +#ifdef CONFIG_64BIT +static inline void qdio_perf_stat_inc(atomic64_t *count) +{ + if (qdio_performance_stats) + atomic64_inc(count); +} + +static inline void qdio_perf_stat_dec(atomic64_t *count) +{ + if (qdio_performance_stats) + atomic64_dec(count); +} +#else /* CONFIG_64BIT */ +static inline void qdio_perf_stat_inc(atomic_t *count) +{ + if (qdio_performance_stats) + atomic_inc(count); +} + +static inline void qdio_perf_stat_dec(atomic_t *count) +{ + if (qdio_performance_stats) + atomic_dec(count); +} +#endif /* CONFIG_64BIT */ static inline __u64 qdio_get_micros(void) @@ -277,8 +301,7 @@ qdio_siga_sync(struct qdio_q *q, unsigned int gpr2, QDIO_DBF_TEXT4(0,trace,"sigasync"); QDIO_DBF_HEX4(0,trace,&q,sizeof(void*)); - if (qdio_performance_stats) - perf_stats.siga_syncs++; + qdio_perf_stat_inc(&perf_stats.siga_syncs); cc = do_siga_sync(q->schid, gpr2, gpr3); if (cc) @@ -323,8 +346,7 @@ qdio_siga_output(struct qdio_q *q) __u32 busy_bit; __u64 start_time=0; - if (qdio_performance_stats) - perf_stats.siga_outs++; + qdio_perf_stat_inc(&perf_stats.siga_outs); QDIO_DBF_TEXT4(0,trace,"sigaout"); QDIO_DBF_HEX4(0,trace,&q,sizeof(void*)); @@ -358,8 +380,7 @@ qdio_siga_input(struct qdio_q *q) QDIO_DBF_TEXT4(0,trace,"sigain"); QDIO_DBF_HEX4(0,trace,&q,sizeof(void*)); - if (qdio_performance_stats) - perf_stats.siga_ins++; + qdio_perf_stat_inc(&perf_stats.siga_ins); cc = do_siga_input(q->schid, q->mask); @@ -953,8 +974,7 @@ __qdio_outbound_processing(struct qdio_q *q) if (unlikely(qdio_reserve_q(q))) { qdio_release_q(q); - if (qdio_performance_stats) - o_p_c++; + qdio_perf_stat_inc(&perf_stats.outbound_tl_runs_resched); /* as we're sissies, we'll check next time */ if (likely(!atomic_read(&q->is_in_shutdown))) { qdio_mark_q(q); @@ -962,10 +982,8 @@ __qdio_outbound_processing(struct qdio_q *q) } return; } - if (qdio_performance_stats) { - o_p_nc++; - perf_stats.tl_runs++; - } + qdio_perf_stat_inc(&perf_stats.outbound_tl_runs); + qdio_perf_stat_inc(&perf_stats.tl_runs); /* see comment in qdio_kick_outbound_q */ siga_attempts=atomic_read(&q->busy_siga_counter); @@ -1139,17 +1157,6 @@ qdio_has_inbound_q_moved(struct qdio_q *q) { int i; - static int old_pcis=0; - static int old_thinints=0; - - if (qdio_performance_stats) { - if ((old_pcis==perf_stats.pcis)&& - (old_thinints==perf_stats.thinints)) - perf_stats.start_time_inbound=NOW; - else - old_pcis=perf_stats.pcis; - } - i=qdio_get_inbound_buffer_frontier(q); if ( (i!=GET_SAVED_FRONTIER(q)) || (q->error_status_flags&QDIO_STATUS_LOOK_FOR_ERROR) ) { @@ -1337,10 +1344,7 @@ qdio_kick_inbound_handler(struct qdio_q *q) q->siga_error=0; q->error_status_flags=0; - if (qdio_performance_stats) { - perf_stats.inbound_time+=NOW-perf_stats.start_time_inbound; - perf_stats.inbound_cnt++; - } + qdio_perf_stat_inc(&perf_stats.inbound_cnt); } static void @@ -1360,8 +1364,7 @@ __tiqdio_inbound_processing(struct qdio_q *q, int spare_ind_was_set) */ if (unlikely(qdio_reserve_q(q))) { qdio_release_q(q); - if (qdio_performance_stats) - ii_p_c++; + qdio_perf_stat_inc(&perf_stats.inbound_thin_tl_runs_resched); /* * as we might just be about to stop polling, we make * sure that we check again at least once more @@ -1369,8 +1372,7 @@ __tiqdio_inbound_processing(struct qdio_q *q, int spare_ind_was_set) tiqdio_sched_tl(); return; } - if (qdio_performance_stats) - ii_p_nc++; + qdio_perf_stat_inc(&perf_stats.inbound_thin_tl_runs); if (unlikely(atomic_read(&q->is_in_shutdown))) { qdio_unmark_q(q); goto out; @@ -1412,8 +1414,7 @@ __tiqdio_inbound_processing(struct qdio_q *q, int spare_ind_was_set) for (i=0;i<irq_ptr->no_output_qs;i++) { oq = irq_ptr->output_qs[i]; if (!qdio_is_outbound_q_done(oq)) { - if (qdio_performance_stats) - perf_stats.tl_runs--; + qdio_perf_stat_dec(&perf_stats.tl_runs); __qdio_outbound_processing(oq); } } @@ -1452,8 +1453,7 @@ __qdio_inbound_processing(struct qdio_q *q) if (unlikely(qdio_reserve_q(q))) { qdio_release_q(q); - if (qdio_performance_stats) - i_p_c++; + qdio_perf_stat_inc(&perf_stats.inbound_tl_runs_resched); /* as we're sissies, we'll check next time */ if (likely(!atomic_read(&q->is_in_shutdown))) { qdio_mark_q(q); @@ -1461,10 +1461,8 @@ __qdio_inbound_processing(struct qdio_q *q) } return; } - if (qdio_performance_stats) { - i_p_nc++; - perf_stats.tl_runs++; - } + qdio_perf_stat_inc(&perf_stats.inbound_tl_runs); + qdio_perf_stat_inc(&perf_stats.tl_runs); again: if (qdio_has_inbound_q_moved(q)) { @@ -1510,8 +1508,7 @@ tiqdio_reset_processing_state(struct qdio_q *q, int q_laps) if (unlikely(qdio_reserve_q(q))) { qdio_release_q(q); - if (qdio_performance_stats) - ii_p_c++; + qdio_perf_stat_inc(&perf_stats.inbound_thin_tl_runs_resched); /* * as we might just be about to stop polling, we make * sure that we check again at least once more @@ -1602,8 +1599,7 @@ tiqdio_tl(unsigned long data) { QDIO_DBF_TEXT4(0,trace,"iqdio_tl"); - if (qdio_performance_stats) - perf_stats.tl_runs++; + qdio_perf_stat_inc(&perf_stats.tl_runs); tiqdio_inbound_checks(); } @@ -1914,10 +1910,7 @@ tiqdio_thinint_handler(void) { QDIO_DBF_TEXT4(0,trace,"thin_int"); - if (qdio_performance_stats) { - perf_stats.thinints++; - perf_stats.start_time_inbound=NOW; - } + qdio_perf_stat_inc(&perf_stats.thinints); /* SVS only when needed: * issue SVS to benefit from iqdio interrupt avoidance @@ -1972,17 +1965,12 @@ qdio_handle_pci(struct qdio_irq *irq_ptr) int i; struct qdio_q *q; - if (qdio_performance_stats) { - perf_stats.pcis++; - perf_stats.start_time_inbound=NOW; - } + qdio_perf_stat_inc(&perf_stats.pcis); for (i=0;i<irq_ptr->no_input_qs;i++) { q=irq_ptr->input_qs[i]; if (q->is_input_q&QDIO_FLAG_NO_INPUT_INTERRUPT_CONTEXT) qdio_mark_q(q); else { - if (qdio_performance_stats) - perf_stats.tl_runs--; __qdio_inbound_processing(q); } } @@ -1992,8 +1980,7 @@ qdio_handle_pci(struct qdio_irq *irq_ptr) q=irq_ptr->output_qs[i]; if (qdio_is_outbound_q_done(q)) continue; - if (qdio_performance_stats) - perf_stats.tl_runs--; + qdio_perf_stat_dec(&perf_stats.tl_runs); if (!irq_ptr->sync_done_on_outb_pcis) SYNC_MEMORY; __qdio_outbound_processing(q); @@ -3463,18 +3450,12 @@ do_qdio_handle_outbound(struct qdio_q *q, unsigned int callflags, struct qdio_irq *irq = (struct qdio_irq *) q->irq_ptr; /* This is the outbound handling of queues */ - if (qdio_performance_stats) - perf_stats.start_time_outbound=NOW; - qdio_do_qdio_fill_output(q,qidx,count,buffers); used_elements=atomic_add_return(count, &q->number_of_buffers_used) - count; if (callflags&QDIO_FLAG_DONT_SIGA) { - if (qdio_performance_stats) { - perf_stats.outbound_time+=NOW-perf_stats.start_time_outbound; - perf_stats.outbound_cnt++; - } + qdio_perf_stat_inc(&perf_stats.outbound_cnt); return; } if (q->is_iqdio_q) { @@ -3504,8 +3485,7 @@ do_qdio_handle_outbound(struct qdio_q *q, unsigned int callflags, qdio_kick_outbound_q(q); } else { QDIO_DBF_TEXT3(0,trace, "fast-req"); - if (qdio_performance_stats) - perf_stats.fast_reqs++; + qdio_perf_stat_inc(&perf_stats.fast_reqs); } } /* @@ -3516,10 +3496,7 @@ do_qdio_handle_outbound(struct qdio_q *q, unsigned int callflags, __qdio_outbound_processing(q); } - if (qdio_performance_stats) { - perf_stats.outbound_time+=NOW-perf_stats.start_time_outbound; - perf_stats.outbound_cnt++; - } + qdio_perf_stat_inc(&perf_stats.outbound_cnt); } /* count must be 1 in iqdio */ @@ -3589,33 +3566,67 @@ qdio_perf_procfile_read(char *buffer, char **buffer_location, off_t offset, return 0; #define _OUTP_IT(x...) c+=sprintf(buffer+c,x) - _OUTP_IT("i_p_nc/c=%lu/%lu\n",i_p_nc,i_p_c); - _OUTP_IT("ii_p_nc/c=%lu/%lu\n",ii_p_nc,ii_p_c); - _OUTP_IT("o_p_nc/c=%lu/%lu\n",o_p_nc,o_p_c); - _OUTP_IT("Number of tasklet runs (total) : %lu\n", - perf_stats.tl_runs); +#ifdef CONFIG_64BIT + _OUTP_IT("Number of tasklet runs (total) : %li\n", + (long)atomic64_read(&perf_stats.tl_runs)); + _OUTP_IT("Inbound tasklet runs tried/retried : %li/%li\n", + (long)atomic64_read(&perf_stats.inbound_tl_runs), + (long)atomic64_read(&perf_stats.inbound_tl_runs_resched)); + _OUTP_IT("Inbound-thin tasklet runs tried/retried : %li/%li\n", + (long)atomic64_read(&perf_stats.inbound_thin_tl_runs), + (long)atomic64_read(&perf_stats.inbound_thin_tl_runs_resched)); + _OUTP_IT("Outbound tasklet runs tried/retried : %li/%li\n", + (long)atomic64_read(&perf_stats.outbound_tl_runs), + (long)atomic64_read(&perf_stats.outbound_tl_runs_resched)); _OUTP_IT("\n"); - _OUTP_IT("Number of SIGA sync's issued : %lu\n", - perf_stats.siga_syncs); - _OUTP_IT("Number of SIGA in's issued : %lu\n", - perf_stats.siga_ins); - _OUTP_IT("Number of SIGA out's issued : %lu\n", - perf_stats.siga_outs); - _OUTP_IT("Number of PCIs caught : %lu\n", - perf_stats.pcis); - _OUTP_IT("Number of adapter interrupts caught : %lu\n", - perf_stats.thinints); - _OUTP_IT("Number of fast requeues (outg. SBALs w/o SIGA) : %lu\n", - perf_stats.fast_reqs); + _OUTP_IT("Number of SIGA sync's issued : %li\n", + (long)atomic64_read(&perf_stats.siga_syncs)); + _OUTP_IT("Number of SIGA in's issued : %li\n", + (long)atomic64_read(&perf_stats.siga_ins)); + _OUTP_IT("Number of SIGA out's issued : %li\n", + (long)atomic64_read(&perf_stats.siga_outs)); + _OUTP_IT("Number of PCIs caught : %li\n", + (long)atomic64_read(&perf_stats.pcis)); + _OUTP_IT("Number of adapter interrupts caught : %li\n", + (long)atomic64_read(&perf_stats.thinints)); + _OUTP_IT("Number of fast requeues (outg. SBALs w/o SIGA) : %li\n", + (long)atomic64_read(&perf_stats.fast_reqs)); _OUTP_IT("\n"); - _OUTP_IT("Total time of all inbound actions (us) incl. UL : %lu\n", - perf_stats.inbound_time); - _OUTP_IT("Number of inbound transfers : %lu\n", - perf_stats.inbound_cnt); - _OUTP_IT("Total time of all outbound do_QDIOs (us) : %lu\n", - perf_stats.outbound_time); - _OUTP_IT("Number of do_QDIOs outbound : %lu\n", - perf_stats.outbound_cnt); + _OUTP_IT("Number of inbound transfers : %li\n", + (long)atomic64_read(&perf_stats.inbound_cnt)); + _OUTP_IT("Number of do_QDIOs outbound : %li\n", + (long)atomic64_read(&perf_stats.outbound_cnt)); +#else /* CONFIG_64BIT */ + _OUTP_IT("Number of tasklet runs (total) : %i\n", + atomic_read(&perf_stats.tl_runs)); + _OUTP_IT("Inbound tasklet runs tried/retried : %i/%i\n", + atomic_read(&perf_stats.inbound_tl_runs), + atomic_read(&perf_stats.inbound_tl_runs_resched)); + _OUTP_IT("Inbound-thin tasklet runs tried/retried : %i/%i\n", + atomic_read(&perf_stats.inbound_thin_tl_runs), + atomic_read(&perf_stats.inbound_thin_tl_runs_resched)); + _OUTP_IT("Outbound tasklet runs tried/retried : %i/%i\n", + atomic_read(&perf_stats.outbound_tl_runs), + atomic_read(&perf_stats.outbound_tl_runs_resched)); + _OUTP_IT("\n"); + _OUTP_IT("Number of SIGA sync's issued : %i\n", + atomic_read(&perf_stats.siga_syncs)); + _OUTP_IT("Number of SIGA in's issued : %i\n", + atomic_read(&perf_stats.siga_ins)); + _OUTP_IT("Number of SIGA out's issued : %i\n", + atomic_read(&perf_stats.siga_outs)); + _OUTP_IT("Number of PCIs caught : %i\n", + atomic_read(&perf_stats.pcis)); + _OUTP_IT("Number of adapter interrupts caught : %i\n", + atomic_read(&perf_stats.thinints)); + _OUTP_IT("Number of fast requeues (outg. SBALs w/o SIGA) : %i\n", + atomic_read(&perf_stats.fast_reqs)); + _OUTP_IT("\n"); + _OUTP_IT("Number of inbound transfers : %i\n", + atomic_read(&perf_stats.inbound_cnt)); + _OUTP_IT("Number of do_QDIOs outbound : %i\n", + atomic_read(&perf_stats.outbound_cnt)); +#endif /* CONFIG_64BIT */ _OUTP_IT("\n"); return c; @@ -3642,8 +3653,6 @@ qdio_add_procfs_entry(void) static void qdio_remove_procfs_entry(void) { - perf_stats.tl_runs=0; - if (!proc_perf_file_registration) /* means if it went ok earlier */ remove_proc_entry(QDIO_PERF,&proc_root); } @@ -3671,13 +3680,38 @@ qdio_performance_stats_store(struct bus_type *bus, const char *buf, size_t count qdio_performance_stats = i; if (i==0) { /* reset perf. stat. info */ - i_p_nc = 0; - i_p_c = 0; - ii_p_nc = 0; - ii_p_c = 0; - o_p_nc = 0; - o_p_c = 0; - memset(&perf_stats, 0, sizeof(struct qdio_perf_stats)); +#ifdef CONFIG_64BIT + atomic64_set(&perf_stats.tl_runs, 0); + atomic64_set(&perf_stats.outbound_tl_runs, 0); + atomic64_set(&perf_stats.inbound_tl_runs, 0); + atomic64_set(&perf_stats.inbound_tl_runs_resched, 0); + atomic64_set(&perf_stats.inbound_thin_tl_runs, 0); + atomic64_set(&perf_stats.inbound_thin_tl_runs_resched, + 0); + atomic64_set(&perf_stats.siga_outs, 0); + atomic64_set(&perf_stats.siga_ins, 0); + atomic64_set(&perf_stats.siga_syncs, 0); + atomic64_set(&perf_stats.pcis, 0); + atomic64_set(&perf_stats.thinints, 0); + atomic64_set(&perf_stats.fast_reqs, 0); + atomic64_set(&perf_stats.outbound_cnt, 0); + atomic64_set(&perf_stats.inbound_cnt, 0); +#else /* CONFIG_64BIT */ + atomic_set(&perf_stats.tl_runs, 0); + atomic_set(&perf_stats.outbound_tl_runs, 0); + atomic_set(&perf_stats.inbound_tl_runs, 0); + atomic_set(&perf_stats.inbound_tl_runs_resched, 0); + atomic_set(&perf_stats.inbound_thin_tl_runs, 0); + atomic_set(&perf_stats.inbound_thin_tl_runs_resched, 0); + atomic_set(&perf_stats.siga_outs, 0); + atomic_set(&perf_stats.siga_ins, 0); + atomic_set(&perf_stats.siga_syncs, 0); + atomic_set(&perf_stats.pcis, 0); + atomic_set(&perf_stats.thinints, 0); + atomic_set(&perf_stats.fast_reqs, 0); + atomic_set(&perf_stats.outbound_cnt, 0); + atomic_set(&perf_stats.inbound_cnt, 0); +#endif /* CONFIG_64BIT */ } } else { QDIO_PRINT_WARN("QDIO performance_stats: write 0 or 1 to this file!\n"); diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h index ec9af72b2af..2895392eaae 100644 --- a/drivers/s390/cio/qdio.h +++ b/drivers/s390/cio/qdio.h @@ -406,21 +406,43 @@ do_clear_global_summary(void) #define CHSC_FLAG_SIGA_SYNC_DONE_ON_OUTB_PCIS 0x04 struct qdio_perf_stats { - unsigned long tl_runs; - - unsigned long siga_outs; - unsigned long siga_ins; - unsigned long siga_syncs; - unsigned long pcis; - unsigned long thinints; - unsigned long fast_reqs; - - __u64 start_time_outbound; - unsigned long outbound_cnt; - unsigned long outbound_time; - __u64 start_time_inbound; - unsigned long inbound_cnt; - unsigned long inbound_time; +#ifdef CONFIG_64BIT + atomic64_t tl_runs; + atomic64_t outbound_tl_runs; + atomic64_t outbound_tl_runs_resched; + atomic64_t inbound_tl_runs; + atomic64_t inbound_tl_runs_resched; + atomic64_t inbound_thin_tl_runs; + atomic64_t inbound_thin_tl_runs_resched; + + atomic64_t siga_outs; + atomic64_t siga_ins; + atomic64_t siga_syncs; + atomic64_t pcis; + atomic64_t thinints; + atomic64_t fast_reqs; + + atomic64_t outbound_cnt; + atomic64_t inbound_cnt; +#else /* CONFIG_64BIT */ + atomic_t tl_runs; + atomic_t outbound_tl_runs; + atomic_t outbound_tl_runs_resched; + atomic_t inbound_tl_runs; + atomic_t inbound_tl_runs_resched; + atomic_t inbound_thin_tl_runs; + atomic_t inbound_thin_tl_runs_resched; + + atomic_t siga_outs; + atomic_t siga_ins; + atomic_t siga_syncs; + atomic_t pcis; + atomic_t thinints; + atomic_t fast_reqs; + + atomic_t outbound_cnt; + atomic_t inbound_cnt; +#endif /* CONFIG_64BIT */ }; /* unlikely as the later the better */ diff --git a/drivers/s390/net/qeth.h b/drivers/s390/net/qeth.h index 84b108d7c7f..b34eb82edd9 100644 --- a/drivers/s390/net/qeth.h +++ b/drivers/s390/net/qeth.h @@ -288,6 +288,7 @@ qeth_is_ipa_enabled(struct qeth_ipa_info *ipa, enum qeth_ipa_funcs func) */ #define IF_NAME_LEN 16 #define QETH_TX_TIMEOUT 100 * HZ +#define QETH_RCD_TIMEOUT 60 * HZ #define QETH_HEADER_SIZE 32 #define MAX_PORTNO 15 #define QETH_FAKE_LL_LEN_ETH ETH_HLEN @@ -582,6 +583,8 @@ enum qeth_channel_states { CH_STATE_ACTIVATING, CH_STATE_HALTED, CH_STATE_STOPPED, + CH_STATE_RCD, + CH_STATE_RCD_DONE, }; /** * card state machine diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c index ad7792dc1a0..6fd8870551d 100644 --- a/drivers/s390/net/qeth_main.c +++ b/drivers/s390/net/qeth_main.c @@ -315,7 +315,8 @@ qeth_alloc_card(void) } static long -__qeth_check_irb_error(struct ccw_device *cdev, struct irb *irb) +__qeth_check_irb_error(struct ccw_device *cdev, unsigned long intparm, + struct irb *irb) { if (!IS_ERR(irb)) return 0; @@ -330,6 +331,14 @@ __qeth_check_irb_error(struct ccw_device *cdev, struct irb *irb) PRINT_WARN("timeout on device %s\n", cdev->dev.bus_id); QETH_DBF_TEXT(trace, 2, "ckirberr"); QETH_DBF_TEXT_(trace, 2, " rc%d", -ETIMEDOUT); + if (intparm == QETH_RCD_PARM) { + struct qeth_card *card = CARD_FROM_CDEV(cdev); + + if (card && (card->data.ccwdev == cdev)) { + card->data.state = CH_STATE_DOWN; + wake_up(&card->wait_q); + } + } break; default: PRINT_WARN("unknown error %ld on device %s\n", PTR_ERR(irb), @@ -401,7 +410,7 @@ qeth_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) QETH_DBF_TEXT(trace,5,"irq"); - if (__qeth_check_irb_error(cdev, irb)) + if (__qeth_check_irb_error(cdev, intparm, irb)) return; cstat = irb->scsw.cstat; dstat = irb->scsw.dstat; @@ -429,7 +438,8 @@ qeth_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) channel->state = CH_STATE_HALTED; /*let's wake up immediately on data channel*/ - if ((channel == &card->data) && (intparm != 0)) + if ((channel == &card->data) && (intparm != 0) && + (intparm != QETH_RCD_PARM)) goto out; if (intparm == QETH_CLEAR_CHANNEL_PARM) { @@ -453,6 +463,10 @@ qeth_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) HEXDUMP16(WARN,"irb: ",irb); HEXDUMP16(WARN,"sense data: ",irb->ecw); } + if (intparm == QETH_RCD_PARM) { + channel->state = CH_STATE_DOWN; + goto out; + } rc = qeth_get_problem(cdev,irb); if (rc) { qeth_schedule_recovery(card); @@ -460,6 +474,10 @@ qeth_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) } } + if (intparm == QETH_RCD_PARM) { + channel->state = CH_STATE_RCD_DONE; + goto out; + } if (intparm) { buffer = (struct qeth_cmd_buffer *) __va((addr_t)intparm); buffer->state = BUF_STATE_PROCESSED; @@ -1204,6 +1222,54 @@ qeth_probe_device(struct ccwgroup_device *gdev) } +static int qeth_read_conf_data(struct qeth_card *card, void **buffer, + int *length) +{ + struct ciw *ciw; + char *rcd_buf; + int ret; + struct qeth_channel *channel = &card->data; + unsigned long flags; + + /* + * scan for RCD command in extended SenseID data + */ + ciw = ccw_device_get_ciw(channel->ccwdev, CIW_TYPE_RCD); + if (!ciw || ciw->cmd == 0) + return -EOPNOTSUPP; + rcd_buf = kzalloc(ciw->count, GFP_KERNEL | GFP_DMA); + if (!rcd_buf) + return -ENOMEM; + + channel->ccw.cmd_code = ciw->cmd; + channel->ccw.cda = (__u32) __pa (rcd_buf); + channel->ccw.count = ciw->count; + channel->ccw.flags = CCW_FLAG_SLI; + channel->state = CH_STATE_RCD; + spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags); + ret = ccw_device_start_timeout(channel->ccwdev, &channel->ccw, + QETH_RCD_PARM, LPM_ANYPATH, 0, + QETH_RCD_TIMEOUT); + spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags); + if (!ret) + wait_event(card->wait_q, + (channel->state == CH_STATE_RCD_DONE || + channel->state == CH_STATE_DOWN)); + if (channel->state == CH_STATE_DOWN) + ret = -EIO; + else + channel->state = CH_STATE_DOWN; + if (ret) { + kfree(rcd_buf); + *buffer = NULL; + *length = 0; + } else { + *length = ciw->count; + *buffer = rcd_buf; + } + return ret; +} + static int qeth_get_unitaddr(struct qeth_card *card) { @@ -1212,9 +1278,9 @@ qeth_get_unitaddr(struct qeth_card *card) int rc; QETH_DBF_TEXT(setup, 2, "getunit"); - rc = read_conf_data(CARD_DDEV(card), (void **) &prcd, &length); + rc = qeth_read_conf_data(card, (void **) &prcd, &length); if (rc) { - PRINT_ERR("read_conf_data for device %s returned %i\n", + PRINT_ERR("qeth_read_conf_data for device %s returned %i\n", CARD_DDEV_ID(card), rc); return rc; } @@ -1223,6 +1289,7 @@ qeth_get_unitaddr(struct qeth_card *card) card->info.cula = prcd[63]; card->info.guestlan = ((prcd[0x10] == _ascebc['V']) && (prcd[0x11] == _ascebc['M'])); + kfree(prcd); return 0; } diff --git a/drivers/s390/net/qeth_mpc.h b/drivers/s390/net/qeth_mpc.h index 0477c47471c..d74bc43da72 100644 --- a/drivers/s390/net/qeth_mpc.h +++ b/drivers/s390/net/qeth_mpc.h @@ -37,6 +37,7 @@ extern unsigned char IPA_PDU_HEADER[]; #define QETH_CLEAR_CHANNEL_PARM -10 #define QETH_HALT_CHANNEL_PARM -11 +#define QETH_RCD_PARM -12 /*****************************************************************************/ /* IP Assist related definitions */ diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index fcc4cb6c7f4..e1ebed0f075 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -1649,7 +1649,7 @@ config OKTAGON_SCSI config ATARI_SCSI tristate "Atari native SCSI support" - depends on ATARI && SCSI && BROKEN + depends on ATARI && SCSI select SCSI_SPI_ATTRS ---help--- If you have an Atari with built-in NCR5380 SCSI controller (TT, diff --git a/drivers/scsi/atari_NCR5380.c b/drivers/scsi/atari_NCR5380.c index 0f920c84ac0..eff846ae0af 100644 --- a/drivers/scsi/atari_NCR5380.c +++ b/drivers/scsi/atari_NCR5380.c @@ -1,19 +1,19 @@ -/* +/* * NCR 5380 generic driver routines. These should make it *trivial* - * to implement 5380 SCSI drivers under Linux with a non-trantor + * to implement 5380 SCSI drivers under Linux with a non-trantor * architecture. * * Note that these routines also work with NR53c400 family chips. * * Copyright 1993, Drew Eckhardt - * Visionary Computing + * Visionary Computing * (Unix and Linux consulting and custom programming) - * drew@colorado.edu + * drew@colorado.edu * +1 (303) 666-5836 * - * DISTRIBUTION RELEASE 6. + * DISTRIBUTION RELEASE 6. * - * For more information, please consult + * For more information, please consult * * NCR 5380 Family * SCSI Protocol Controller @@ -57,7 +57,7 @@ * - I've deleted all the stuff for AUTOPROBE_IRQ, REAL_DMA_POLL, PSEUDO_DMA * and USLEEP, because these were messing up readability and will never be * needed for Atari SCSI. - * + * * - I've revised the NCR5380_main() calling scheme (relax the 'main_running' * stuff), and 'main' is executed in a bottom half if awoken by an * interrupt. @@ -69,21 +69,29 @@ */ /* - * Further development / testing that should be done : - * 1. Test linked command handling code after Eric is ready with + * Further development / testing that should be done : + * 1. Test linked command handling code after Eric is ready with * the high level code. */ #include <scsi/scsi_dbg.h> #include <scsi/scsi_transport_spi.h> #if (NDEBUG & NDEBUG_LISTS) -#define LIST(x,y) \ - { printk("LINE:%d Adding %p to %p\n", __LINE__, (void*)(x), (void*)(y)); \ - if ((x)==(y)) udelay(5); } -#define REMOVE(w,x,y,z) \ - { printk("LINE:%d Removing: %p->%p %p->%p \n", __LINE__, \ - (void*)(w), (void*)(x), (void*)(y), (void*)(z)); \ - if ((x)==(y)) udelay(5); } +#define LIST(x, y) \ + do { \ + printk("LINE:%d Adding %p to %p\n", \ + __LINE__, (void*)(x), (void*)(y)); \ + if ((x) == (y)) \ + udelay(5); \ + } while (0) +#define REMOVE(w, x, y, z) \ + do { \ + printk("LINE:%d Removing: %p->%p %p->%p \n", \ + __LINE__, (void*)(w), (void*)(x), \ + (void*)(y), (void*)(z)); \ + if ((x) == (y)) \ + udelay(5); \ + } while (0) #else #define LIST(x,y) #define REMOVE(w,x,y,z) @@ -103,62 +111,62 @@ * more difficult than it has to be. * * Also, many of the SCSI drivers were written before the command queuing - * routines were implemented, meaning their implementations of queued + * routines were implemented, meaning their implementations of queued * commands were hacked on rather than designed in from the start. * - * When I designed the Linux SCSI drivers I figured that + * When I designed the Linux SCSI drivers I figured that * while having two different SCSI boards in a system might be useful * for debugging things, two of the same type wouldn't be used. * Well, I was wrong and a number of users have mailed me about running * multiple high-performance SCSI boards in a server. * - * Finally, when I get questions from users, I have no idea what + * Finally, when I get questions from users, I have no idea what * revision of my driver they are running. * * This driver attempts to address these problems : - * This is a generic 5380 driver. To use it on a different platform, + * This is a generic 5380 driver. To use it on a different platform, * one simply writes appropriate system specific macros (ie, data - * transfer - some PC's will use the I/O bus, 68K's must use + * transfer - some PC's will use the I/O bus, 68K's must use * memory mapped) and drops this file in their 'C' wrapper. * - * As far as command queueing, two queues are maintained for + * As far as command queueing, two queues are maintained for * each 5380 in the system - commands that haven't been issued yet, - * and commands that are currently executing. This means that an - * unlimited number of commands may be queued, letting - * more commands propagate from the higher driver levels giving higher - * throughput. Note that both I_T_L and I_T_L_Q nexuses are supported, - * allowing multiple commands to propagate all the way to a SCSI-II device + * and commands that are currently executing. This means that an + * unlimited number of commands may be queued, letting + * more commands propagate from the higher driver levels giving higher + * throughput. Note that both I_T_L and I_T_L_Q nexuses are supported, + * allowing multiple commands to propagate all the way to a SCSI-II device * while a command is already executing. * - * To solve the multiple-boards-in-the-same-system problem, + * To solve the multiple-boards-in-the-same-system problem, * there is a separate instance structure for each instance * of a 5380 in the system. So, multiple NCR5380 drivers will * be able to coexist with appropriate changes to the high level - * SCSI code. + * SCSI code. * * A NCR5380_PUBLIC_REVISION macro is provided, with the release - * number (updated for each public release) printed by the - * NCR5380_print_options command, which should be called from the + * number (updated for each public release) printed by the + * NCR5380_print_options command, which should be called from the * wrapper detect function, so that I know what release of the driver * users are using. * - * Issues specific to the NCR5380 : + * Issues specific to the NCR5380 : * - * When used in a PIO or pseudo-dma mode, the NCR5380 is a braindead - * piece of hardware that requires you to sit in a loop polling for - * the REQ signal as long as you are connected. Some devices are - * brain dead (ie, many TEXEL CD ROM drives) and won't disconnect + * When used in a PIO or pseudo-dma mode, the NCR5380 is a braindead + * piece of hardware that requires you to sit in a loop polling for + * the REQ signal as long as you are connected. Some devices are + * brain dead (ie, many TEXEL CD ROM drives) and won't disconnect * while doing long seek operations. - * + * * The workaround for this is to keep track of devices that have * disconnected. If the device hasn't disconnected, for commands that - * should disconnect, we do something like + * should disconnect, we do something like * * while (!REQ is asserted) { sleep for N usecs; poll for M usecs } - * - * Some tweaking of N and M needs to be done. An algorithm based + * + * Some tweaking of N and M needs to be done. An algorithm based * on "time to data" would give the best results as long as short time - * to datas (ie, on the same track) were considered, however these + * to datas (ie, on the same track) were considered, however these * broken devices are the exception rather than the rule and I'd rather * spend my time optimizing for the normal case. * @@ -167,9 +175,9 @@ * At the heart of the design is a coroutine, NCR5380_main, * which is started when not running by the interrupt handler, * timer, and queue command function. It attempts to establish - * I_T_L or I_T_L_Q nexuses by removing the commands from the - * issue queue and calling NCR5380_select() if a nexus - * is not established. + * I_T_L or I_T_L_Q nexuses by removing the commands from the + * issue queue and calling NCR5380_select() if a nexus + * is not established. * * Once a nexus is established, the NCR5380_information_transfer() * phase goes through the various phases as instructed by the target. @@ -183,10 +191,10 @@ * calling NCR5380_intr() which will in turn call NCR5380_reselect * to reestablish a nexus. This will run main if necessary. * - * On command termination, the done function will be called as + * On command termination, the done function will be called as * appropriate. * - * SCSI pointers are maintained in the SCp field of SCSI command + * SCSI pointers are maintained in the SCp field of SCSI command * structures, being initialized after the command is connected * in NCR5380_select, and set as appropriate in NCR5380_information_transfer. * Note that in violation of the standard, an implicit SAVE POINTERS operation @@ -196,12 +204,12 @@ /* * Using this file : * This file a skeleton Linux SCSI driver for the NCR 5380 series - * of chips. To use it, you write an architecture specific functions + * of chips. To use it, you write an architecture specific functions * and macros and include this file in your driver. * - * These macros control options : + * These macros control options : * AUTOSENSE - if defined, REQUEST SENSE will be performed automatically - * for commands that return with a CHECK CONDITION status. + * for commands that return with a CHECK CONDITION status. * * LINKED - if defined, linked commands are supported. * @@ -210,18 +218,18 @@ * SUPPORT_TAGS - if defined, SCSI-2 tagged queuing is used where possible * * These macros MUST be defined : - * + * * NCR5380_read(register) - read from the specified register * - * NCR5380_write(register, value) - write to the specific register + * NCR5380_write(register, value) - write to the specific register * * Either real DMA *or* pseudo DMA may be implemented - * REAL functions : + * REAL functions : * NCR5380_REAL_DMA should be defined if real DMA is to be used. - * Note that the DMA setup functions should return the number of bytes + * Note that the DMA setup functions should return the number of bytes * that they were able to program the controller for. * - * Also note that generic i386/PC versions of these macros are + * Also note that generic i386/PC versions of these macros are * available as NCR5380_i386_dma_write_setup, * NCR5380_i386_dma_read_setup, and NCR5380_i386_dma_residual. * @@ -234,14 +242,14 @@ * NCR5380_pread(instance, dst, count); * * If nothing specific to this implementation needs doing (ie, with external - * hardware), you must also define - * + * hardware), you must also define + * * NCR5380_queue_command * NCR5380_reset * NCR5380_abort * NCR5380_proc_info * - * to be the global entry points into the specific driver, ie + * to be the global entry points into the specific driver, ie * #define NCR5380_queue_command t128_queue_command. * * If this is not done, the routines will be defined as static functions @@ -249,7 +257,7 @@ * accessible wrapper function. * * The generic driver is initialized by calling NCR5380_init(instance), - * after setting the appropriate host specific fields and ID. If the + * after setting the appropriate host specific fields and ID. If the * driver wishes to autoprobe for an IRQ line, the NCR5380_probe_irq(instance, * possible) function may be used. Before the specific driver initialization * code finishes, NCR5380_print_options should be called. @@ -264,8 +272,9 @@ static struct scsi_host_template *the_template = NULL; (struct NCR5380_hostdata *)(in)->hostdata #define HOSTDATA(in) ((struct NCR5380_hostdata *)(in)->hostdata) -#define NEXT(cmd) ((Scsi_Cmnd *)((cmd)->host_scribble)) -#define NEXTADDR(cmd) ((Scsi_Cmnd **)&((cmd)->host_scribble)) +#define NEXT(cmd) ((Scsi_Cmnd *)(cmd)->host_scribble) +#define SET_NEXT(cmd,next) ((cmd)->host_scribble = (void *)(next)) +#define NEXTADDR(cmd) ((Scsi_Cmnd **)&(cmd)->host_scribble) #define HOSTNO instance->host_no #define H_NO(cmd) (cmd)->device->host->host_no @@ -312,34 +321,34 @@ static struct scsi_host_template *the_template = NULL; #define TAG_NONE 0xff typedef struct { - DECLARE_BITMAP(allocated, MAX_TAGS); - int nr_allocated; - int queue_size; + DECLARE_BITMAP(allocated, MAX_TAGS); + int nr_allocated; + int queue_size; } TAG_ALLOC; -static TAG_ALLOC TagAlloc[8][8]; /* 8 targets and 8 LUNs */ +static TAG_ALLOC TagAlloc[8][8]; /* 8 targets and 8 LUNs */ -static void __init init_tags( void ) +static void __init init_tags(void) { - int target, lun; - TAG_ALLOC *ta; - - if (!setup_use_tagged_queuing) - return; - - for( target = 0; target < 8; ++target ) { - for( lun = 0; lun < 8; ++lun ) { - ta = &TagAlloc[target][lun]; - bitmap_zero(ta->allocated, MAX_TAGS); - ta->nr_allocated = 0; - /* At the beginning, assume the maximum queue size we could - * support (MAX_TAGS). This value will be decreased if the target - * returns QUEUE_FULL status. - */ - ta->queue_size = MAX_TAGS; + int target, lun; + TAG_ALLOC *ta; + + if (!setup_use_tagged_queuing) + return; + + for (target = 0; target < 8; ++target) { + for (lun = 0; lun < 8; ++lun) { + ta = &TagAlloc[target][lun]; + bitmap_zero(ta->allocated, MAX_TAGS); + ta->nr_allocated = 0; + /* At the beginning, assume the maximum queue size we could + * support (MAX_TAGS). This value will be decreased if the target + * returns QUEUE_FULL status. + */ + ta->queue_size = MAX_TAGS; + } } - } } @@ -348,24 +357,24 @@ static void __init init_tags( void ) * check that there is a free tag and the target's queue won't overflow. This * function should be called with interrupts disabled to avoid race * conditions. - */ + */ -static int is_lun_busy( Scsi_Cmnd *cmd, int should_be_tagged ) +static int is_lun_busy(Scsi_Cmnd *cmd, int should_be_tagged) { - SETUP_HOSTDATA(cmd->device->host); - - if (hostdata->busy[cmd->device->id] & (1 << cmd->device->lun)) - return( 1 ); - if (!should_be_tagged || - !setup_use_tagged_queuing || !cmd->device->tagged_supported) - return( 0 ); - if (TagAlloc[cmd->device->id][cmd->device->lun].nr_allocated >= - TagAlloc[cmd->device->id][cmd->device->lun].queue_size ) { - TAG_PRINTK( "scsi%d: target %d lun %d: no free tags\n", - H_NO(cmd), cmd->device->id, cmd->device->lun ); - return( 1 ); - } - return( 0 ); + SETUP_HOSTDATA(cmd->device->host); + + if (hostdata->busy[cmd->device->id] & (1 << cmd->device->lun)) + return 1; + if (!should_be_tagged || + !setup_use_tagged_queuing || !cmd->device->tagged_supported) + return 0; + if (TagAlloc[cmd->device->id][cmd->device->lun].nr_allocated >= + TagAlloc[cmd->device->id][cmd->device->lun].queue_size) { + TAG_PRINTK("scsi%d: target %d lun %d: no free tags\n", + H_NO(cmd), cmd->device->id, cmd->device->lun); + return 1; + } + return 0; } @@ -374,31 +383,30 @@ static int is_lun_busy( Scsi_Cmnd *cmd, int should_be_tagged ) * untagged. */ -static void cmd_get_tag( Scsi_Cmnd *cmd, int should_be_tagged ) +static void cmd_get_tag(Scsi_Cmnd *cmd, int should_be_tagged) { - SETUP_HOSTDATA(cmd->device->host); - - /* If we or the target don't support tagged queuing, allocate the LUN for - * an untagged command. - */ - if (!should_be_tagged || - !setup_use_tagged_queuing || !cmd->device->tagged_supported) { - cmd->tag = TAG_NONE; - hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun); - TAG_PRINTK( "scsi%d: target %d lun %d now allocated by untagged " - "command\n", H_NO(cmd), cmd->device->id, cmd->device->lun ); - } - else { - TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun]; - - cmd->tag = find_first_zero_bit( ta->allocated, MAX_TAGS ); - set_bit( cmd->tag, ta->allocated ); - ta->nr_allocated++; - TAG_PRINTK( "scsi%d: using tag %d for target %d lun %d " - "(now %d tags in use)\n", - H_NO(cmd), cmd->tag, cmd->device->id, cmd->device->lun, - ta->nr_allocated ); - } + SETUP_HOSTDATA(cmd->device->host); + + /* If we or the target don't support tagged queuing, allocate the LUN for + * an untagged command. + */ + if (!should_be_tagged || + !setup_use_tagged_queuing || !cmd->device->tagged_supported) { + cmd->tag = TAG_NONE; + hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun); + TAG_PRINTK("scsi%d: target %d lun %d now allocated by untagged " + "command\n", H_NO(cmd), cmd->device->id, cmd->device->lun); + } else { + TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun]; + + cmd->tag = find_first_zero_bit(ta->allocated, MAX_TAGS); + set_bit(cmd->tag, ta->allocated); + ta->nr_allocated++; + TAG_PRINTK("scsi%d: using tag %d for target %d lun %d " + "(now %d tags in use)\n", + H_NO(cmd), cmd->tag, cmd->device->id, + cmd->device->lun, ta->nr_allocated); + } } @@ -406,44 +414,42 @@ static void cmd_get_tag( Scsi_Cmnd *cmd, int should_be_tagged ) * unlock the LUN. */ -static void cmd_free_tag( Scsi_Cmnd *cmd ) +static void cmd_free_tag(Scsi_Cmnd *cmd) { - SETUP_HOSTDATA(cmd->device->host); - - if (cmd->tag == TAG_NONE) { - hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); - TAG_PRINTK( "scsi%d: target %d lun %d untagged cmd finished\n", - H_NO(cmd), cmd->device->id, cmd->device->lun ); - } - else if (cmd->tag >= MAX_TAGS) { - printk(KERN_NOTICE "scsi%d: trying to free bad tag %d!\n", - H_NO(cmd), cmd->tag ); - } - else { - TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun]; - clear_bit( cmd->tag, ta->allocated ); - ta->nr_allocated--; - TAG_PRINTK( "scsi%d: freed tag %d for target %d lun %d\n", - H_NO(cmd), cmd->tag, cmd->device->id, cmd->device->lun ); - } + SETUP_HOSTDATA(cmd->device->host); + + if (cmd->tag == TAG_NONE) { + hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); + TAG_PRINTK("scsi%d: target %d lun %d untagged cmd finished\n", + H_NO(cmd), cmd->device->id, cmd->device->lun); + } else if (cmd->tag >= MAX_TAGS) { + printk(KERN_NOTICE "scsi%d: trying to free bad tag %d!\n", + H_NO(cmd), cmd->tag); + } else { + TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun]; + clear_bit(cmd->tag, ta->allocated); + ta->nr_allocated--; + TAG_PRINTK("scsi%d: freed tag %d for target %d lun %d\n", + H_NO(cmd), cmd->tag, cmd->device->id, cmd->device->lun); + } } -static void free_all_tags( void ) +static void free_all_tags(void) { - int target, lun; - TAG_ALLOC *ta; - - if (!setup_use_tagged_queuing) - return; - - for( target = 0; target < 8; ++target ) { - for( lun = 0; lun < 8; ++lun ) { - ta = &TagAlloc[target][lun]; - bitmap_zero(ta->allocated, MAX_TAGS); - ta->nr_allocated = 0; + int target, lun; + TAG_ALLOC *ta; + + if (!setup_use_tagged_queuing) + return; + + for (target = 0; target < 8; ++target) { + for (lun = 0; lun < 8; ++lun) { + ta = &TagAlloc[target][lun]; + bitmap_zero(ta->allocated, MAX_TAGS); + ta->nr_allocated = 0; + } } - } } #endif /* SUPPORT_TAGS */ @@ -461,89 +467,94 @@ static void free_all_tags( void ) * assumed to be already transfered into ptr/this_residual. */ -static void merge_contiguous_buffers( Scsi_Cmnd *cmd ) +static void merge_contiguous_buffers(Scsi_Cmnd *cmd) { - unsigned long endaddr; + unsigned long endaddr; #if (NDEBUG & NDEBUG_MERGING) - unsigned long oldlen = cmd->SCp.this_residual; - int cnt = 1; + unsigned long oldlen = cmd->SCp.this_residual; + int cnt = 1; #endif - for (endaddr = virt_to_phys(cmd->SCp.ptr + cmd->SCp.this_residual - 1) + 1; - cmd->SCp.buffers_residual && - virt_to_phys(page_address(cmd->SCp.buffer[1].page)+ - cmd->SCp.buffer[1].offset) == endaddr; ) { - MER_PRINTK("VTOP(%p) == %08lx -> merging\n", - cmd->SCp.buffer[1].address, endaddr); + for (endaddr = virt_to_phys(cmd->SCp.ptr + cmd->SCp.this_residual - 1) + 1; + cmd->SCp.buffers_residual && + virt_to_phys(page_address(cmd->SCp.buffer[1].page) + + cmd->SCp.buffer[1].offset) == endaddr;) { + MER_PRINTK("VTOP(%p) == %08lx -> merging\n", + page_address(cmd->SCp.buffer[1].page), endaddr); #if (NDEBUG & NDEBUG_MERGING) - ++cnt; + ++cnt; #endif - ++cmd->SCp.buffer; - --cmd->SCp.buffers_residual; - cmd->SCp.this_residual += cmd->SCp.buffer->length; - endaddr += cmd->SCp.buffer->length; - } + ++cmd->SCp.buffer; + --cmd->SCp.buffers_residual; + cmd->SCp.this_residual += cmd->SCp.buffer->length; + endaddr += cmd->SCp.buffer->length; + } #if (NDEBUG & NDEBUG_MERGING) - if (oldlen != cmd->SCp.this_residual) - MER_PRINTK("merged %d buffers from %p, new length %08x\n", - cnt, cmd->SCp.ptr, cmd->SCp.this_residual); + if (oldlen != cmd->SCp.this_residual) + MER_PRINTK("merged %d buffers from %p, new length %08x\n", + cnt, cmd->SCp.ptr, cmd->SCp.this_residual); #endif } /* * Function : void initialize_SCp(Scsi_Cmnd *cmd) * - * Purpose : initialize the saved data pointers for cmd to point to the + * Purpose : initialize the saved data pointers for cmd to point to the * start of the buffer. * * Inputs : cmd - Scsi_Cmnd structure to have pointers reset. */ -static __inline__ void initialize_SCp(Scsi_Cmnd *cmd) +static inline void initialize_SCp(Scsi_Cmnd *cmd) { - /* - * Initialize the Scsi Pointer field so that all of the commands in the - * various queues are valid. - */ - - if (cmd->use_sg) { - cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer; - cmd->SCp.buffers_residual = cmd->use_sg - 1; - cmd->SCp.ptr = (char *)page_address(cmd->SCp.buffer->page)+ - cmd->SCp.buffer->offset; - cmd->SCp.this_residual = cmd->SCp.buffer->length; - /* ++roman: Try to merge some scatter-buffers if they are at - * contiguous physical addresses. + /* + * Initialize the Scsi Pointer field so that all of the commands in the + * various queues are valid. */ - merge_contiguous_buffers( cmd ); - } else { - cmd->SCp.buffer = NULL; - cmd->SCp.buffers_residual = 0; - cmd->SCp.ptr = (char *) cmd->request_buffer; - cmd->SCp.this_residual = cmd->request_bufflen; - } + + if (cmd->use_sg) { + cmd->SCp.buffer = (struct scatterlist *)cmd->request_buffer; + cmd->SCp.buffers_residual = cmd->use_sg - 1; + cmd->SCp.ptr = (char *)page_address(cmd->SCp.buffer->page) + + cmd->SCp.buffer->offset; + cmd->SCp.this_residual = cmd->SCp.buffer->length; + /* ++roman: Try to merge some scatter-buffers if they are at + * contiguous physical addresses. + */ + merge_contiguous_buffers(cmd); + } else { + cmd->SCp.buffer = NULL; + cmd->SCp.buffers_residual = 0; + cmd->SCp.ptr = (char *)cmd->request_buffer; + cmd->SCp.this_residual = cmd->request_bufflen; + } } #include <linux/delay.h> #if NDEBUG static struct { - unsigned char mask; - const char * name;} -signals[] = {{ SR_DBP, "PARITY"}, { SR_RST, "RST" }, { SR_BSY, "BSY" }, - { SR_REQ, "REQ" }, { SR_MSG, "MSG" }, { SR_CD, "CD" }, { SR_IO, "IO" }, - { SR_SEL, "SEL" }, {0, NULL}}, -basrs[] = {{BASR_ATN, "ATN"}, {BASR_ACK, "ACK"}, {0, NULL}}, -icrs[] = {{ICR_ASSERT_RST, "ASSERT RST"},{ICR_ASSERT_ACK, "ASSERT ACK"}, - {ICR_ASSERT_BSY, "ASSERT BSY"}, {ICR_ASSERT_SEL, "ASSERT SEL"}, - {ICR_ASSERT_ATN, "ASSERT ATN"}, {ICR_ASSERT_DATA, "ASSERT DATA"}, - {0, NULL}}, -mrs[] = {{MR_BLOCK_DMA_MODE, "MODE BLOCK DMA"}, {MR_TARGET, "MODE TARGET"}, - {MR_ENABLE_PAR_CHECK, "MODE PARITY CHECK"}, {MR_ENABLE_PAR_INTR, - "MODE PARITY INTR"}, {MR_ENABLE_EOP_INTR,"MODE EOP INTR"}, - {MR_MONITOR_BSY, "MODE MONITOR BSY"}, - {MR_DMA_MODE, "MODE DMA"}, {MR_ARBITRATE, "MODE ARBITRATION"}, - {0, NULL}}; + unsigned char mask; + const char *name; +} signals[] = { + { SR_DBP, "PARITY"}, { SR_RST, "RST" }, { SR_BSY, "BSY" }, + { SR_REQ, "REQ" }, { SR_MSG, "MSG" }, { SR_CD, "CD" }, { SR_IO, "IO" }, + { SR_SEL, "SEL" }, {0, NULL} +}, basrs[] = { + {BASR_ATN, "ATN"}, {BASR_ACK, "ACK"}, {0, NULL} +}, icrs[] = { + {ICR_ASSERT_RST, "ASSERT RST"},{ICR_ASSERT_ACK, "ASSERT ACK"}, + {ICR_ASSERT_BSY, "ASSERT BSY"}, {ICR_ASSERT_SEL, "ASSERT SEL"}, + {ICR_ASSERT_ATN, "ASSERT ATN"}, {ICR_ASSERT_DATA, "ASSERT DATA"}, + {0, NULL} +}, mrs[] = { + {MR_BLOCK_DMA_MODE, "MODE BLOCK DMA"}, {MR_TARGET, "MODE TARGET"}, + {MR_ENABLE_PAR_CHECK, "MODE PARITY CHECK"}, {MR_ENABLE_PAR_INTR, + "MODE PARITY INTR"}, {MR_ENABLE_EOP_INTR,"MODE EOP INTR"}, + {MR_MONITOR_BSY, "MODE MONITOR BSY"}, + {MR_DMA_MODE, "MODE DMA"}, {MR_ARBITRATE, "MODE ARBITRATION"}, + {0, NULL} +}; /* * Function : void NCR5380_print(struct Scsi_Host *instance) @@ -553,45 +564,47 @@ mrs[] = {{MR_BLOCK_DMA_MODE, "MODE BLOCK DMA"}, {MR_TARGET, "MODE TARGET"}, * Input : instance - which NCR5380 */ -static void NCR5380_print(struct Scsi_Host *instance) { - unsigned char status, data, basr, mr, icr, i; - unsigned long flags; - - local_irq_save(flags); - data = NCR5380_read(CURRENT_SCSI_DATA_REG); - status = NCR5380_read(STATUS_REG); - mr = NCR5380_read(MODE_REG); - icr = NCR5380_read(INITIATOR_COMMAND_REG); - basr = NCR5380_read(BUS_AND_STATUS_REG); - local_irq_restore(flags); - printk("STATUS_REG: %02x ", status); - for (i = 0; signals[i].mask ; ++i) - if (status & signals[i].mask) - printk(",%s", signals[i].name); - printk("\nBASR: %02x ", basr); - for (i = 0; basrs[i].mask ; ++i) - if (basr & basrs[i].mask) - printk(",%s", basrs[i].name); - printk("\nICR: %02x ", icr); - for (i = 0; icrs[i].mask; ++i) - if (icr & icrs[i].mask) - printk(",%s", icrs[i].name); - printk("\nMODE: %02x ", mr); - for (i = 0; mrs[i].mask; ++i) - if (mr & mrs[i].mask) - printk(",%s", mrs[i].name); - printk("\n"); +static void NCR5380_print(struct Scsi_Host *instance) +{ + unsigned char status, data, basr, mr, icr, i; + unsigned long flags; + + local_irq_save(flags); + data = NCR5380_read(CURRENT_SCSI_DATA_REG); + status = NCR5380_read(STATUS_REG); + mr = NCR5380_read(MODE_REG); + icr = NCR5380_read(INITIATOR_COMMAND_REG); + basr = NCR5380_read(BUS_AND_STATUS_REG); + local_irq_restore(flags); + printk("STATUS_REG: %02x ", status); + for (i = 0; signals[i].mask; ++i) + if (status & signals[i].mask) + printk(",%s", signals[i].name); + printk("\nBASR: %02x ", basr); + for (i = 0; basrs[i].mask; ++i) + if (basr & basrs[i].mask) + printk(",%s", basrs[i].name); + printk("\nICR: %02x ", icr); + for (i = 0; icrs[i].mask; ++i) + if (icr & icrs[i].mask) + printk(",%s", icrs[i].name); + printk("\nMODE: %02x ", mr); + for (i = 0; mrs[i].mask; ++i) + if (mr & mrs[i].mask) + printk(",%s", mrs[i].name); + printk("\n"); } static struct { - unsigned char value; - const char *name; + unsigned char value; + const char *name; } phases[] = { - {PHASE_DATAOUT, "DATAOUT"}, {PHASE_DATAIN, "DATAIN"}, {PHASE_CMDOUT, "CMDOUT"}, - {PHASE_STATIN, "STATIN"}, {PHASE_MSGOUT, "MSGOUT"}, {PHASE_MSGIN, "MSGIN"}, - {PHASE_UNKNOWN, "UNKNOWN"}}; + {PHASE_DATAOUT, "DATAOUT"}, {PHASE_DATAIN, "DATAIN"}, {PHASE_CMDOUT, "CMDOUT"}, + {PHASE_STATIN, "STATIN"}, {PHASE_MSGOUT, "MSGOUT"}, {PHASE_MSGIN, "MSGIN"}, + {PHASE_UNKNOWN, "UNKNOWN"} +}; -/* +/* * Function : void NCR5380_print_phase(struct Scsi_Host *instance) * * Purpose : print the current SCSI phase for debugging purposes @@ -601,30 +614,35 @@ static struct { static void NCR5380_print_phase(struct Scsi_Host *instance) { - unsigned char status; - int i; - - status = NCR5380_read(STATUS_REG); - if (!(status & SR_REQ)) - printk(KERN_DEBUG "scsi%d: REQ not asserted, phase unknown.\n", HOSTNO); - else { - for (i = 0; (phases[i].value != PHASE_UNKNOWN) && - (phases[i].value != (status & PHASE_MASK)); ++i); - printk(KERN_DEBUG "scsi%d: phase %s\n", HOSTNO, phases[i].name); - } + unsigned char status; + int i; + + status = NCR5380_read(STATUS_REG); + if (!(status & SR_REQ)) + printk(KERN_DEBUG "scsi%d: REQ not asserted, phase unknown.\n", HOSTNO); + else { + for (i = 0; (phases[i].value != PHASE_UNKNOWN) && + (phases[i].value != (status & PHASE_MASK)); ++i) + ; + printk(KERN_DEBUG "scsi%d: phase %s\n", HOSTNO, phases[i].name); + } } #else /* !NDEBUG */ /* dummies... */ -__inline__ void NCR5380_print(struct Scsi_Host *instance) { }; -__inline__ void NCR5380_print_phase(struct Scsi_Host *instance) { }; +static inline void NCR5380_print(struct Scsi_Host *instance) +{ +}; +static inline void NCR5380_print_phase(struct Scsi_Host *instance) +{ +}; #endif /* * ++roman: New scheme of calling NCR5380_main() - * + * * If we're not in an interrupt, we can call our main directly, it cannot be * already running. Else, we queue it on a task queue, if not 'main_running' * tells us that a lower level is already executing it. This way, @@ -638,33 +656,33 @@ __inline__ void NCR5380_print_phase(struct Scsi_Host *instance) { }; #include <linux/workqueue.h> #include <linux/interrupt.h> -static volatile int main_running = 0; -static DECLARE_WORK(NCR5380_tqueue, (void (*)(void*))NCR5380_main, NULL); +static volatile int main_running; +static DECLARE_WORK(NCR5380_tqueue, NCR5380_main); -static __inline__ void queue_main(void) +static inline void queue_main(void) { - if (!main_running) { - /* If in interrupt and NCR5380_main() not already running, - queue it on the 'immediate' task queue, to be processed - immediately after the current interrupt processing has - finished. */ - schedule_work(&NCR5380_tqueue); - } - /* else: nothing to do: the running NCR5380_main() will pick up - any newly queued command. */ + if (!main_running) { + /* If in interrupt and NCR5380_main() not already running, + queue it on the 'immediate' task queue, to be processed + immediately after the current interrupt processing has + finished. */ + schedule_work(&NCR5380_tqueue); + } + /* else: nothing to do: the running NCR5380_main() will pick up + any newly queued command. */ } -static inline void NCR5380_all_init (void) +static inline void NCR5380_all_init(void) { - static int done = 0; - if (!done) { - INI_PRINTK("scsi : NCR5380_all_init()\n"); - done = 1; - } + static int done = 0; + if (!done) { + INI_PRINTK("scsi : NCR5380_all_init()\n"); + done = 1; + } } - + /* * Function : void NCR58380_print_options (struct Scsi_Host *instance) * @@ -674,23 +692,23 @@ static inline void NCR5380_all_init (void) * Inputs : instance, pointer to this instance. Unused. */ -static void __init NCR5380_print_options (struct Scsi_Host *instance) +static void __init NCR5380_print_options(struct Scsi_Host *instance) { - printk(" generic options" -#ifdef AUTOSENSE - " AUTOSENSE" + printk(" generic options" +#ifdef AUTOSENSE + " AUTOSENSE" #endif #ifdef REAL_DMA - " REAL DMA" + " REAL DMA" #endif #ifdef PARITY - " PARITY" + " PARITY" #endif #ifdef SUPPORT_TAGS - " SCSI-2 TAGGED QUEUING" + " SCSI-2 TAGGED QUEUING" #endif - ); - printk(" generic release=%d", NCR5380_PUBLIC_RELEASE); + ); + printk(" generic release=%d", NCR5380_PUBLIC_RELEASE); } /* @@ -699,27 +717,27 @@ static void __init NCR5380_print_options (struct Scsi_Host *instance) * Purpose : print commands in the various queues, called from * NCR5380_abort and NCR5380_debug to aid debugging. * - * Inputs : instance, pointer to this instance. + * Inputs : instance, pointer to this instance. */ -static void NCR5380_print_status (struct Scsi_Host *instance) +static void NCR5380_print_status(struct Scsi_Host *instance) { - char *pr_bfr; - char *start; - int len; - - NCR_PRINT(NDEBUG_ANY); - NCR_PRINT_PHASE(NDEBUG_ANY); - - pr_bfr = (char *) __get_free_page(GFP_ATOMIC); - if (!pr_bfr) { - printk("NCR5380_print_status: no memory for print buffer\n"); - return; - } - len = NCR5380_proc_info(pr_bfr, &start, 0, PAGE_SIZE, HOSTNO, 0); - pr_bfr[len] = 0; - printk("\n%s\n", pr_bfr); - free_page((unsigned long) pr_bfr); + char *pr_bfr; + char *start; + int len; + + NCR_PRINT(NDEBUG_ANY); + NCR_PRINT_PHASE(NDEBUG_ANY); + + pr_bfr = (char *)__get_free_page(GFP_ATOMIC); + if (!pr_bfr) { + printk("NCR5380_print_status: no memory for print buffer\n"); + return; + } + len = NCR5380_proc_info(instance, pr_bfr, &start, 0, PAGE_SIZE, 0); + pr_bfr[len] = 0; + printk("\n%s\n", pr_bfr); + free_page((unsigned long)pr_bfr); } @@ -738,443 +756,478 @@ static void NCR5380_print_status (struct Scsi_Host *instance) */ #undef SPRINTF -#define SPRINTF(fmt,args...) \ - do { if (pos + strlen(fmt) + 20 /* slop */ < buffer + length) \ - pos += sprintf(pos, fmt , ## args); } while(0) -static -char *lprint_Scsi_Cmnd (Scsi_Cmnd *cmd, char *pos, char *buffer, int length); - -static -int NCR5380_proc_info (struct Scsi_Host *instance, char *buffer, char **start, off_t offset, - int length, int inout) +#define SPRINTF(fmt,args...) \ + do { \ + if (pos + strlen(fmt) + 20 /* slop */ < buffer + length) \ + pos += sprintf(pos, fmt , ## args); \ + } while(0) +static char *lprint_Scsi_Cmnd(Scsi_Cmnd *cmd, char *pos, char *buffer, int length); + +static int NCR5380_proc_info(struct Scsi_Host *instance, char *buffer, + char **start, off_t offset, int length, int inout) { - char *pos = buffer; - struct NCR5380_hostdata *hostdata; - Scsi_Cmnd *ptr; - unsigned long flags; - off_t begin = 0; -#define check_offset() \ - do { \ - if (pos - buffer < offset - begin) { \ - begin += pos - buffer; \ - pos = buffer; \ - } \ - } while (0) - - hostdata = (struct NCR5380_hostdata *)instance->hostdata; - - if (inout) { /* Has data been written to the file ? */ - return(-ENOSYS); /* Currently this is a no-op */ - } - SPRINTF("NCR5380 core release=%d.\n", NCR5380_PUBLIC_RELEASE); - check_offset(); - local_irq_save(flags); - SPRINTF("NCR5380: coroutine is%s running.\n", main_running ? "" : "n't"); - check_offset(); - if (!hostdata->connected) - SPRINTF("scsi%d: no currently connected command\n", HOSTNO); - else - pos = lprint_Scsi_Cmnd ((Scsi_Cmnd *) hostdata->connected, - pos, buffer, length); - SPRINTF("scsi%d: issue_queue\n", HOSTNO); - check_offset(); - for (ptr = (Scsi_Cmnd *) hostdata->issue_queue; ptr; ptr = NEXT(ptr)) { - pos = lprint_Scsi_Cmnd (ptr, pos, buffer, length); + char *pos = buffer; + struct NCR5380_hostdata *hostdata; + Scsi_Cmnd *ptr; + unsigned long flags; + off_t begin = 0; +#define check_offset() \ + do { \ + if (pos - buffer < offset - begin) { \ + begin += pos - buffer; \ + pos = buffer; \ + } \ + } while (0) + + hostdata = (struct NCR5380_hostdata *)instance->hostdata; + + if (inout) /* Has data been written to the file ? */ + return -ENOSYS; /* Currently this is a no-op */ + SPRINTF("NCR5380 core release=%d.\n", NCR5380_PUBLIC_RELEASE); check_offset(); - } + local_irq_save(flags); + SPRINTF("NCR5380: coroutine is%s running.\n", + main_running ? "" : "n't"); + check_offset(); + if (!hostdata->connected) + SPRINTF("scsi%d: no currently connected command\n", HOSTNO); + else + pos = lprint_Scsi_Cmnd((Scsi_Cmnd *) hostdata->connected, + pos, buffer, length); + SPRINTF("scsi%d: issue_queue\n", HOSTNO); + check_offset(); + for (ptr = (Scsi_Cmnd *)hostdata->issue_queue; ptr; ptr = NEXT(ptr)) { + pos = lprint_Scsi_Cmnd(ptr, pos, buffer, length); + check_offset(); + } - SPRINTF("scsi%d: disconnected_queue\n", HOSTNO); - check_offset(); - for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr; - ptr = NEXT(ptr)) { - pos = lprint_Scsi_Cmnd (ptr, pos, buffer, length); + SPRINTF("scsi%d: disconnected_queue\n", HOSTNO); check_offset(); - } + for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr; + ptr = NEXT(ptr)) { + pos = lprint_Scsi_Cmnd(ptr, pos, buffer, length); + check_offset(); + } - local_irq_restore(flags); - *start = buffer + (offset - begin); - if (pos - buffer < offset - begin) - return 0; - else if (pos - buffer - (offset - begin) < length) - return pos - buffer - (offset - begin); - return length; + local_irq_restore(flags); + *start = buffer + (offset - begin); + if (pos - buffer < offset - begin) + return 0; + else if (pos - buffer - (offset - begin) < length) + return pos - buffer - (offset - begin); + return length; } -static char * -lprint_Scsi_Cmnd (Scsi_Cmnd *cmd, char *pos, char *buffer, int length) +static char *lprint_Scsi_Cmnd(Scsi_Cmnd *cmd, char *pos, char *buffer, int length) { - int i, s; - unsigned char *command; - SPRINTF("scsi%d: destination target %d, lun %d\n", - H_NO(cmd), cmd->device->id, cmd->device->lun); - SPRINTF(" command = "); - command = cmd->cmnd; - SPRINTF("%2d (0x%02x)", command[0], command[0]); - for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i) - SPRINTF(" %02x", command[i]); - SPRINTF("\n"); - return pos; + int i, s; + unsigned char *command; + SPRINTF("scsi%d: destination target %d, lun %d\n", + H_NO(cmd), cmd->device->id, cmd->device->lun); + SPRINTF(" command = "); + command = cmd->cmnd; + SPRINTF("%2d (0x%02x)", command[0], command[0]); + for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i) + SPRINTF(" %02x", command[i]); + SPRINTF("\n"); + return pos; } -/* +/* * Function : void NCR5380_init (struct Scsi_Host *instance) * * Purpose : initializes *instance and corresponding 5380 chip. * - * Inputs : instance - instantiation of the 5380 driver. + * Inputs : instance - instantiation of the 5380 driver. * * Notes : I assume that the host, hostno, and id bits have been - * set correctly. I don't care about the irq and other fields. - * + * set correctly. I don't care about the irq and other fields. + * */ -static int NCR5380_init (struct Scsi_Host *instance, int flags) +static int NCR5380_init(struct Scsi_Host *instance, int flags) { - int i; - SETUP_HOSTDATA(instance); - - NCR5380_all_init(); - - hostdata->aborted = 0; - hostdata->id_mask = 1 << instance->this_id; - hostdata->id_higher_mask = 0; - for (i = hostdata->id_mask; i <= 0x80; i <<= 1) - if (i > hostdata->id_mask) - hostdata->id_higher_mask |= i; - for (i = 0; i < 8; ++i) - hostdata->busy[i] = 0; + int i; + SETUP_HOSTDATA(instance); + + NCR5380_all_init(); + + hostdata->aborted = 0; + hostdata->id_mask = 1 << instance->this_id; + hostdata->id_higher_mask = 0; + for (i = hostdata->id_mask; i <= 0x80; i <<= 1) + if (i > hostdata->id_mask) + hostdata->id_higher_mask |= i; + for (i = 0; i < 8; ++i) + hostdata->busy[i] = 0; #ifdef SUPPORT_TAGS - init_tags(); + init_tags(); #endif #if defined (REAL_DMA) - hostdata->dma_len = 0; + hostdata->dma_len = 0; #endif - hostdata->targets_present = 0; - hostdata->connected = NULL; - hostdata->issue_queue = NULL; - hostdata->disconnected_queue = NULL; - hostdata->flags = FLAG_CHECK_LAST_BYTE_SENT; - - if (!the_template) { - the_template = instance->hostt; - first_instance = instance; - } - + hostdata->targets_present = 0; + hostdata->connected = NULL; + hostdata->issue_queue = NULL; + hostdata->disconnected_queue = NULL; + hostdata->flags = FLAG_CHECK_LAST_BYTE_SENT; + + if (!the_template) { + the_template = instance->hostt; + first_instance = instance; + } #ifndef AUTOSENSE - if ((instance->cmd_per_lun > 1) || (instance->can_queue > 1)) - printk("scsi%d: WARNING : support for multiple outstanding commands enabled\n" - " without AUTOSENSE option, contingent allegiance conditions may\n" - " be incorrectly cleared.\n", HOSTNO); + if ((instance->cmd_per_lun > 1) || (instance->can_queue > 1)) + printk("scsi%d: WARNING : support for multiple outstanding commands enabled\n" + " without AUTOSENSE option, contingent allegiance conditions may\n" + " be incorrectly cleared.\n", HOSTNO); #endif /* def AUTOSENSE */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - NCR5380_write(MODE_REG, MR_BASE); - NCR5380_write(TARGET_COMMAND_REG, 0); - NCR5380_write(SELECT_ENABLE_REG, 0); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + NCR5380_write(MODE_REG, MR_BASE); + NCR5380_write(TARGET_COMMAND_REG, 0); + NCR5380_write(SELECT_ENABLE_REG, 0); - return 0; + return 0; } -/* - * Function : int NCR5380_queue_command (Scsi_Cmnd *cmd, - * void (*done)(Scsi_Cmnd *)) +/* + * our own old-style timeout update + */ +/* + * The strategy is to cause the timer code to call scsi_times_out() + * when the soonest timeout is pending. + * The arguments are used when we are queueing a new command, because + * we do not want to subtract the time used from this time, but when we + * set the timer, we want to take this value into account. + */ + +int atari_scsi_update_timeout(Scsi_Cmnd * SCset, int timeout) +{ + int rtn; + + /* + * We are using the new error handling code to actually register/deregister + * timers for timeout. + */ + + if (!timer_pending(&SCset->eh_timeout)) + rtn = 0; + else + rtn = SCset->eh_timeout.expires - jiffies; + + if (timeout == 0) { + del_timer(&SCset->eh_timeout); + SCset->eh_timeout.data = (unsigned long)NULL; + SCset->eh_timeout.expires = 0; + } else { + if (SCset->eh_timeout.data != (unsigned long)NULL) + del_timer(&SCset->eh_timeout); + SCset->eh_timeout.data = (unsigned long)SCset; + SCset->eh_timeout.expires = jiffies + timeout; + add_timer(&SCset->eh_timeout); + } + return rtn; +} + +/* + * Function : int NCR5380_queue_command (Scsi_Cmnd *cmd, + * void (*done)(Scsi_Cmnd *)) * * Purpose : enqueues a SCSI command * * Inputs : cmd - SCSI command, done - function called on completion, with * a pointer to the command descriptor. - * + * * Returns : 0 * - * Side effects : - * cmd is added to the per instance issue_queue, with minor - * twiddling done to the host specific fields of cmd. If the + * Side effects : + * cmd is added to the per instance issue_queue, with minor + * twiddling done to the host specific fields of cmd. If the * main coroutine is not running, it is restarted. * */ -static -int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) +static int NCR5380_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) { - SETUP_HOSTDATA(cmd->device->host); - Scsi_Cmnd *tmp; - int oldto; - unsigned long flags; - extern int update_timeout(Scsi_Cmnd * SCset, int timeout); + SETUP_HOSTDATA(cmd->device->host); + Scsi_Cmnd *tmp; + int oldto; + unsigned long flags; + // extern int update_timeout(Scsi_Cmnd * SCset, int timeout); #if (NDEBUG & NDEBUG_NO_WRITE) - switch (cmd->cmnd[0]) { - case WRITE_6: - case WRITE_10: - printk(KERN_NOTICE "scsi%d: WRITE attempted with NO_WRITE debugging flag set\n", - H_NO(cmd)); - cmd->result = (DID_ERROR << 16); - done(cmd); - return 0; - } + switch (cmd->cmnd[0]) { + case WRITE_6: + case WRITE_10: + printk(KERN_NOTICE "scsi%d: WRITE attempted with NO_WRITE debugging flag set\n", + H_NO(cmd)); + cmd->result = (DID_ERROR << 16); + done(cmd); + return 0; + } #endif /* (NDEBUG & NDEBUG_NO_WRITE) */ - #ifdef NCR5380_STATS # if 0 - if (!hostdata->connected && !hostdata->issue_queue && - !hostdata->disconnected_queue) { - hostdata->timebase = jiffies; - } + if (!hostdata->connected && !hostdata->issue_queue && + !hostdata->disconnected_queue) { + hostdata->timebase = jiffies; + } # endif # ifdef NCR5380_STAT_LIMIT - if (cmd->request_bufflen > NCR5380_STAT_LIMIT) + if (cmd->request_bufflen > NCR5380_STAT_LIMIT) # endif - switch (cmd->cmnd[0]) - { - case WRITE: - case WRITE_6: - case WRITE_10: - hostdata->time_write[cmd->device->id] -= (jiffies - hostdata->timebase); - hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen; - hostdata->pendingw++; - break; - case READ: - case READ_6: - case READ_10: - hostdata->time_read[cmd->device->id] -= (jiffies - hostdata->timebase); - hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen; - hostdata->pendingr++; - break; - } + switch (cmd->cmnd[0]) { + case WRITE: + case WRITE_6: + case WRITE_10: + hostdata->time_write[cmd->device->id] -= (jiffies - hostdata->timebase); + hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen; + hostdata->pendingw++; + break; + case READ: + case READ_6: + case READ_10: + hostdata->time_read[cmd->device->id] -= (jiffies - hostdata->timebase); + hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen; + hostdata->pendingr++; + break; + } #endif - /* - * We use the host_scribble field as a pointer to the next command - * in a queue - */ - - NEXT(cmd) = NULL; - cmd->scsi_done = done; - - cmd->result = 0; - - - /* - * Insert the cmd into the issue queue. Note that REQUEST SENSE - * commands are added to the head of the queue since any command will - * clear the contingent allegiance condition that exists and the - * sense data is only guaranteed to be valid while the condition exists. - */ - - local_irq_save(flags); - /* ++guenther: now that the issue queue is being set up, we can lock ST-DMA. - * Otherwise a running NCR5380_main may steal the lock. - * Lock before actually inserting due to fairness reasons explained in - * atari_scsi.c. If we insert first, then it's impossible for this driver - * to release the lock. - * Stop timer for this command while waiting for the lock, or timeouts - * may happen (and they really do), and it's no good if the command doesn't - * appear in any of the queues. - * ++roman: Just disabling the NCR interrupt isn't sufficient here, - * because also a timer int can trigger an abort or reset, which would - * alter queues and touch the lock. - */ - if (!IS_A_TT()) { - oldto = update_timeout(cmd, 0); - falcon_get_lock(); - update_timeout(cmd, oldto); - } - if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) { - LIST(cmd, hostdata->issue_queue); - NEXT(cmd) = hostdata->issue_queue; - hostdata->issue_queue = cmd; - } else { - for (tmp = (Scsi_Cmnd *)hostdata->issue_queue; - NEXT(tmp); tmp = NEXT(tmp)) - ; - LIST(cmd, tmp); - NEXT(tmp) = cmd; - } - local_irq_restore(flags); - - QU_PRINTK("scsi%d: command added to %s of queue\n", H_NO(cmd), - (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail"); - - /* If queue_command() is called from an interrupt (real one or bottom - * half), we let queue_main() do the job of taking care about main. If it - * is already running, this is a no-op, else main will be queued. - * - * If we're not in an interrupt, we can call NCR5380_main() - * unconditionally, because it cannot be already running. - */ - if (in_interrupt() || ((flags >> 8) & 7) >= 6) - queue_main(); - else - NCR5380_main(NULL); - return 0; + /* + * We use the host_scribble field as a pointer to the next command + * in a queue + */ + + SET_NEXT(cmd, NULL); + cmd->scsi_done = done; + + cmd->result = 0; + + /* + * Insert the cmd into the issue queue. Note that REQUEST SENSE + * commands are added to the head of the queue since any command will + * clear the contingent allegiance condition that exists and the + * sense data is only guaranteed to be valid while the condition exists. + */ + + local_irq_save(flags); + /* ++guenther: now that the issue queue is being set up, we can lock ST-DMA. + * Otherwise a running NCR5380_main may steal the lock. + * Lock before actually inserting due to fairness reasons explained in + * atari_scsi.c. If we insert first, then it's impossible for this driver + * to release the lock. + * Stop timer for this command while waiting for the lock, or timeouts + * may happen (and they really do), and it's no good if the command doesn't + * appear in any of the queues. + * ++roman: Just disabling the NCR interrupt isn't sufficient here, + * because also a timer int can trigger an abort or reset, which would + * alter queues and touch the lock. + */ + if (!IS_A_TT()) { + oldto = atari_scsi_update_timeout(cmd, 0); + falcon_get_lock(); + atari_scsi_update_timeout(cmd, oldto); + } + if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) { + LIST(cmd, hostdata->issue_queue); + SET_NEXT(cmd, hostdata->issue_queue); + hostdata->issue_queue = cmd; + } else { + for (tmp = (Scsi_Cmnd *)hostdata->issue_queue; + NEXT(tmp); tmp = NEXT(tmp)) + ; + LIST(cmd, tmp); + SET_NEXT(tmp, cmd); + } + local_irq_restore(flags); + + QU_PRINTK("scsi%d: command added to %s of queue\n", H_NO(cmd), + (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail"); + + /* If queue_command() is called from an interrupt (real one or bottom + * half), we let queue_main() do the job of taking care about main. If it + * is already running, this is a no-op, else main will be queued. + * + * If we're not in an interrupt, we can call NCR5380_main() + * unconditionally, because it cannot be already running. + */ + if (in_interrupt() || ((flags >> 8) & 7) >= 6) + queue_main(); + else + NCR5380_main(NULL); + return 0; } /* - * Function : NCR5380_main (void) + * Function : NCR5380_main (void) * - * Purpose : NCR5380_main is a coroutine that runs as long as more work can - * be done on the NCR5380 host adapters in a system. Both - * NCR5380_queue_command() and NCR5380_intr() will try to start it + * Purpose : NCR5380_main is a coroutine that runs as long as more work can + * be done on the NCR5380 host adapters in a system. Both + * NCR5380_queue_command() and NCR5380_intr() will try to start it * in case it is not running. - * - * NOTE : NCR5380_main exits with interrupts *disabled*, the caller should + * + * NOTE : NCR5380_main exits with interrupts *disabled*, the caller should * reenable them. This prevents reentrancy and kernel stack overflow. - */ - -static void NCR5380_main (void *bl) + */ + +static void NCR5380_main(struct work_struct *work) { - Scsi_Cmnd *tmp, *prev; - struct Scsi_Host *instance = first_instance; - struct NCR5380_hostdata *hostdata = HOSTDATA(instance); - int done; - unsigned long flags; - - /* - * We run (with interrupts disabled) until we're sure that none of - * the host adapters have anything that can be done, at which point - * we set main_running to 0 and exit. - * - * Interrupts are enabled before doing various other internal - * instructions, after we've decided that we need to run through - * the loop again. - * - * this should prevent any race conditions. - * - * ++roman: Just disabling the NCR interrupt isn't sufficient here, - * because also a timer int can trigger an abort or reset, which can - * alter queues and touch the Falcon lock. - */ - - /* Tell int handlers main() is now already executing. Note that - no races are possible here. If an int comes in before - 'main_running' is set here, and queues/executes main via the - task queue, it doesn't do any harm, just this instance of main - won't find any work left to do. */ - if (main_running) - return; - main_running = 1; - - local_save_flags(flags); - do { - local_irq_disable(); /* Freeze request queues */ - done = 1; - - if (!hostdata->connected) { - MAIN_PRINTK( "scsi%d: not connected\n", HOSTNO ); - /* - * Search through the issue_queue for a command destined - * for a target that's not busy. - */ + Scsi_Cmnd *tmp, *prev; + struct Scsi_Host *instance = first_instance; + struct NCR5380_hostdata *hostdata = HOSTDATA(instance); + int done; + unsigned long flags; + + /* + * We run (with interrupts disabled) until we're sure that none of + * the host adapters have anything that can be done, at which point + * we set main_running to 0 and exit. + * + * Interrupts are enabled before doing various other internal + * instructions, after we've decided that we need to run through + * the loop again. + * + * this should prevent any race conditions. + * + * ++roman: Just disabling the NCR interrupt isn't sufficient here, + * because also a timer int can trigger an abort or reset, which can + * alter queues and touch the Falcon lock. + */ + + /* Tell int handlers main() is now already executing. Note that + no races are possible here. If an int comes in before + 'main_running' is set here, and queues/executes main via the + task queue, it doesn't do any harm, just this instance of main + won't find any work left to do. */ + if (main_running) + return; + main_running = 1; + + local_save_flags(flags); + do { + local_irq_disable(); /* Freeze request queues */ + done = 1; + + if (!hostdata->connected) { + MAIN_PRINTK("scsi%d: not connected\n", HOSTNO); + /* + * Search through the issue_queue for a command destined + * for a target that's not busy. + */ #if (NDEBUG & NDEBUG_LISTS) - for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, prev = NULL; - tmp && (tmp != prev); prev = tmp, tmp = NEXT(tmp)) - ; - /*printk("%p ", tmp);*/ - if ((tmp == prev) && tmp) printk(" LOOP\n");/* else printk("\n");*/ + for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, prev = NULL; + tmp && (tmp != prev); prev = tmp, tmp = NEXT(tmp)) + ; + /*printk("%p ", tmp);*/ + if ((tmp == prev) && tmp) + printk(" LOOP\n"); + /* else printk("\n"); */ #endif - for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, - prev = NULL; tmp; prev = tmp, tmp = NEXT(tmp) ) { + for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, + prev = NULL; tmp; prev = tmp, tmp = NEXT(tmp)) { #if (NDEBUG & NDEBUG_LISTS) - if (prev != tmp) - printk("MAIN tmp=%p target=%d busy=%d lun=%d\n", - tmp, tmp->device->id, hostdata->busy[tmp->device->id], - tmp->device->lun); + if (prev != tmp) + printk("MAIN tmp=%p target=%d busy=%d lun=%d\n", + tmp, tmp->device->id, hostdata->busy[tmp->device->id], + tmp->device->lun); #endif - /* When we find one, remove it from the issue queue. */ - /* ++guenther: possible race with Falcon locking */ - if ( + /* When we find one, remove it from the issue queue. */ + /* ++guenther: possible race with Falcon locking */ + if ( #ifdef SUPPORT_TAGS - !is_lun_busy( tmp, tmp->cmnd[0] != REQUEST_SENSE) + !is_lun_busy( tmp, tmp->cmnd[0] != REQUEST_SENSE) #else - !(hostdata->busy[tmp->device->id] & (1 << tmp->device->lun)) + !(hostdata->busy[tmp->device->id] & (1 << tmp->device->lun)) #endif - ) { - /* ++guenther: just to be sure, this must be atomic */ - local_irq_disable(); - if (prev) { - REMOVE(prev, NEXT(prev), tmp, NEXT(tmp)); - NEXT(prev) = NEXT(tmp); - } else { - REMOVE(-1, hostdata->issue_queue, tmp, NEXT(tmp)); - hostdata->issue_queue = NEXT(tmp); - } - NEXT(tmp) = NULL; - falcon_dont_release++; - - /* reenable interrupts after finding one */ - local_irq_restore(flags); - - /* - * Attempt to establish an I_T_L nexus here. - * On success, instance->hostdata->connected is set. - * On failure, we must add the command back to the - * issue queue so we can keep trying. - */ - MAIN_PRINTK("scsi%d: main(): command for target %d " - "lun %d removed from issue_queue\n", - HOSTNO, tmp->device->id, tmp->device->lun); - /* - * REQUEST SENSE commands are issued without tagged - * queueing, even on SCSI-II devices because the - * contingent allegiance condition exists for the - * entire unit. - */ - /* ++roman: ...and the standard also requires that - * REQUEST SENSE command are untagged. - */ - + ) { + /* ++guenther: just to be sure, this must be atomic */ + local_irq_disable(); + if (prev) { + REMOVE(prev, NEXT(prev), tmp, NEXT(tmp)); + SET_NEXT(prev, NEXT(tmp)); + } else { + REMOVE(-1, hostdata->issue_queue, tmp, NEXT(tmp)); + hostdata->issue_queue = NEXT(tmp); + } + SET_NEXT(tmp, NULL); + falcon_dont_release++; + + /* reenable interrupts after finding one */ + local_irq_restore(flags); + + /* + * Attempt to establish an I_T_L nexus here. + * On success, instance->hostdata->connected is set. + * On failure, we must add the command back to the + * issue queue so we can keep trying. + */ + MAIN_PRINTK("scsi%d: main(): command for target %d " + "lun %d removed from issue_queue\n", + HOSTNO, tmp->device->id, tmp->device->lun); + /* + * REQUEST SENSE commands are issued without tagged + * queueing, even on SCSI-II devices because the + * contingent allegiance condition exists for the + * entire unit. + */ + /* ++roman: ...and the standard also requires that + * REQUEST SENSE command are untagged. + */ + #ifdef SUPPORT_TAGS - cmd_get_tag( tmp, tmp->cmnd[0] != REQUEST_SENSE ); + cmd_get_tag(tmp, tmp->cmnd[0] != REQUEST_SENSE); #endif - if (!NCR5380_select(instance, tmp, - (tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE : - TAG_NEXT)) { - falcon_dont_release--; - /* release if target did not response! */ - falcon_release_lock_if_possible( hostdata ); - break; - } else { - local_irq_disable(); - LIST(tmp, hostdata->issue_queue); - NEXT(tmp) = hostdata->issue_queue; - hostdata->issue_queue = tmp; + if (!NCR5380_select(instance, tmp, + (tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE : + TAG_NEXT)) { + falcon_dont_release--; + /* release if target did not response! */ + falcon_release_lock_if_possible(hostdata); + break; + } else { + local_irq_disable(); + LIST(tmp, hostdata->issue_queue); + SET_NEXT(tmp, hostdata->issue_queue); + hostdata->issue_queue = tmp; #ifdef SUPPORT_TAGS - cmd_free_tag( tmp ); + cmd_free_tag(tmp); #endif - falcon_dont_release--; - local_irq_restore(flags); - MAIN_PRINTK("scsi%d: main(): select() failed, " - "returned to issue_queue\n", HOSTNO); - if (hostdata->connected) - break; - } - } /* if target/lun/target queue is not busy */ - } /* for issue_queue */ - } /* if (!hostdata->connected) */ - - if (hostdata->connected + falcon_dont_release--; + local_irq_restore(flags); + MAIN_PRINTK("scsi%d: main(): select() failed, " + "returned to issue_queue\n", HOSTNO); + if (hostdata->connected) + break; + } + } /* if target/lun/target queue is not busy */ + } /* for issue_queue */ + } /* if (!hostdata->connected) */ + + if (hostdata->connected #ifdef REAL_DMA - && !hostdata->dma_len + && !hostdata->dma_len #endif - ) { - local_irq_restore(flags); - MAIN_PRINTK("scsi%d: main: performing information transfer\n", - HOSTNO); - NCR5380_information_transfer(instance); - MAIN_PRINTK("scsi%d: main: done set false\n", HOSTNO); - done = 0; - } - } while (!done); + ) { + local_irq_restore(flags); + MAIN_PRINTK("scsi%d: main: performing information transfer\n", + HOSTNO); + NCR5380_information_transfer(instance); + MAIN_PRINTK("scsi%d: main: done set false\n", HOSTNO); + done = 0; + } + } while (!done); - /* Better allow ints _after_ 'main_running' has been cleared, else - an interrupt could believe we'll pick up the work it left for - us, but we won't see it anymore here... */ - main_running = 0; - local_irq_restore(flags); + /* Better allow ints _after_ 'main_running' has been cleared, else + an interrupt could believe we'll pick up the work it left for + us, but we won't see it anymore here... */ + main_running = 0; + local_irq_restore(flags); } @@ -1183,1441 +1236,1439 @@ static void NCR5380_main (void *bl) * Function : void NCR5380_dma_complete (struct Scsi_Host *instance) * * Purpose : Called by interrupt handler when DMA finishes or a phase - * mismatch occurs (which would finish the DMA transfer). + * mismatch occurs (which would finish the DMA transfer). * * Inputs : instance - this instance of the NCR5380. * */ -static void NCR5380_dma_complete( struct Scsi_Host *instance ) +static void NCR5380_dma_complete(struct Scsi_Host *instance) { - SETUP_HOSTDATA(instance); - int transfered, saved_data = 0, overrun = 0, cnt, toPIO; - unsigned char **data, p; - volatile int *count; - - if (!hostdata->connected) { - printk(KERN_WARNING "scsi%d: received end of DMA interrupt with " - "no connected cmd\n", HOSTNO); - return; - } - - if (atari_read_overruns) { - p = hostdata->connected->SCp.phase; - if (p & SR_IO) { - udelay(10); - if ((((NCR5380_read(BUS_AND_STATUS_REG)) & - (BASR_PHASE_MATCH|BASR_ACK)) == - (BASR_PHASE_MATCH|BASR_ACK))) { - saved_data = NCR5380_read(INPUT_DATA_REG); - overrun = 1; - DMA_PRINTK("scsi%d: read overrun handled\n", HOSTNO); - } + SETUP_HOSTDATA(instance); + int transfered, saved_data = 0, overrun = 0, cnt, toPIO; + unsigned char **data, p; + volatile int *count; + + if (!hostdata->connected) { + printk(KERN_WARNING "scsi%d: received end of DMA interrupt with " + "no connected cmd\n", HOSTNO); + return; } - } - - DMA_PRINTK("scsi%d: real DMA transfer complete, basr 0x%X, sr 0x%X\n", - HOSTNO, NCR5380_read(BUS_AND_STATUS_REG), - NCR5380_read(STATUS_REG)); - - (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); - NCR5380_write(MODE_REG, MR_BASE); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - - transfered = hostdata->dma_len - NCR5380_dma_residual(instance); - hostdata->dma_len = 0; - - data = (unsigned char **) &(hostdata->connected->SCp.ptr); - count = &(hostdata->connected->SCp.this_residual); - *data += transfered; - *count -= transfered; - - if (atari_read_overruns) { - if ((NCR5380_read(STATUS_REG) & PHASE_MASK) == p && (p & SR_IO)) { - cnt = toPIO = atari_read_overruns; - if (overrun) { - DMA_PRINTK("Got an input overrun, using saved byte\n"); - *(*data)++ = saved_data; - (*count)--; - cnt--; - toPIO--; - } - DMA_PRINTK("Doing %d-byte PIO to 0x%08lx\n", cnt, (long)*data); - NCR5380_transfer_pio(instance, &p, &cnt, data); - *count -= toPIO - cnt; + + if (atari_read_overruns) { + p = hostdata->connected->SCp.phase; + if (p & SR_IO) { + udelay(10); + if ((NCR5380_read(BUS_AND_STATUS_REG) & + (BASR_PHASE_MATCH|BASR_ACK)) == + (BASR_PHASE_MATCH|BASR_ACK)) { + saved_data = NCR5380_read(INPUT_DATA_REG); + overrun = 1; + DMA_PRINTK("scsi%d: read overrun handled\n", HOSTNO); + } + } + } + + DMA_PRINTK("scsi%d: real DMA transfer complete, basr 0x%X, sr 0x%X\n", + HOSTNO, NCR5380_read(BUS_AND_STATUS_REG), + NCR5380_read(STATUS_REG)); + + (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG); + NCR5380_write(MODE_REG, MR_BASE); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + + transfered = hostdata->dma_len - NCR5380_dma_residual(instance); + hostdata->dma_len = 0; + + data = (unsigned char **)&hostdata->connected->SCp.ptr; + count = &hostdata->connected->SCp.this_residual; + *data += transfered; + *count -= transfered; + + if (atari_read_overruns) { + if ((NCR5380_read(STATUS_REG) & PHASE_MASK) == p && (p & SR_IO)) { + cnt = toPIO = atari_read_overruns; + if (overrun) { + DMA_PRINTK("Got an input overrun, using saved byte\n"); + *(*data)++ = saved_data; + (*count)--; + cnt--; + toPIO--; + } + DMA_PRINTK("Doing %d-byte PIO to 0x%08lx\n", cnt, (long)*data); + NCR5380_transfer_pio(instance, &p, &cnt, data); + *count -= toPIO - cnt; + } } - } } #endif /* REAL_DMA */ /* * Function : void NCR5380_intr (int irq) - * + * * Purpose : handle interrupts, reestablishing I_T_L or I_T_L_Q nexuses - * from the disconnected queue, and restarting NCR5380_main() + * from the disconnected queue, and restarting NCR5380_main() * as required. * * Inputs : int irq, irq that caused this interrupt. * */ -static irqreturn_t NCR5380_intr (int irq, void *dev_id) +static irqreturn_t NCR5380_intr(int irq, void *dev_id) { - struct Scsi_Host *instance = first_instance; - int done = 1, handled = 0; - unsigned char basr; - - INT_PRINTK("scsi%d: NCR5380 irq triggered\n", HOSTNO); - - /* Look for pending interrupts */ - basr = NCR5380_read(BUS_AND_STATUS_REG); - INT_PRINTK("scsi%d: BASR=%02x\n", HOSTNO, basr); - /* dispatch to appropriate routine if found and done=0 */ - if (basr & BASR_IRQ) { - NCR_PRINT(NDEBUG_INTR); - if ((NCR5380_read(STATUS_REG) & (SR_SEL|SR_IO)) == (SR_SEL|SR_IO)) { - done = 0; - ENABLE_IRQ(); - INT_PRINTK("scsi%d: SEL interrupt\n", HOSTNO); - NCR5380_reselect(instance); - (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); - } - else if (basr & BASR_PARITY_ERROR) { - INT_PRINTK("scsi%d: PARITY interrupt\n", HOSTNO); - (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); - } - else if ((NCR5380_read(STATUS_REG) & SR_RST) == SR_RST) { - INT_PRINTK("scsi%d: RESET interrupt\n", HOSTNO); - (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG); - } - else { - /* - * The rest of the interrupt conditions can occur only during a - * DMA transfer - */ + struct Scsi_Host *instance = first_instance; + int done = 1, handled = 0; + unsigned char basr; + + INT_PRINTK("scsi%d: NCR5380 irq triggered\n", HOSTNO); + + /* Look for pending interrupts */ + basr = NCR5380_read(BUS_AND_STATUS_REG); + INT_PRINTK("scsi%d: BASR=%02x\n", HOSTNO, basr); + /* dispatch to appropriate routine if found and done=0 */ + if (basr & BASR_IRQ) { + NCR_PRINT(NDEBUG_INTR); + if ((NCR5380_read(STATUS_REG) & (SR_SEL|SR_IO)) == (SR_SEL|SR_IO)) { + done = 0; + ENABLE_IRQ(); + INT_PRINTK("scsi%d: SEL interrupt\n", HOSTNO); + NCR5380_reselect(instance); + (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG); + } else if (basr & BASR_PARITY_ERROR) { + INT_PRINTK("scsi%d: PARITY interrupt\n", HOSTNO); + (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG); + } else if ((NCR5380_read(STATUS_REG) & SR_RST) == SR_RST) { + INT_PRINTK("scsi%d: RESET interrupt\n", HOSTNO); + (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG); + } else { + /* + * The rest of the interrupt conditions can occur only during a + * DMA transfer + */ #if defined(REAL_DMA) - /* - * We should only get PHASE MISMATCH and EOP interrupts if we have - * DMA enabled, so do a sanity check based on the current setting - * of the MODE register. - */ - - if ((NCR5380_read(MODE_REG) & MR_DMA_MODE) && - ((basr & BASR_END_DMA_TRANSFER) || - !(basr & BASR_PHASE_MATCH))) { - - INT_PRINTK("scsi%d: PHASE MISM or EOP interrupt\n", HOSTNO); - NCR5380_dma_complete( instance ); - done = 0; - ENABLE_IRQ(); - } else + /* + * We should only get PHASE MISMATCH and EOP interrupts if we have + * DMA enabled, so do a sanity check based on the current setting + * of the MODE register. + */ + + if ((NCR5380_read(MODE_REG) & MR_DMA_MODE) && + ((basr & BASR_END_DMA_TRANSFER) || + !(basr & BASR_PHASE_MATCH))) { + + INT_PRINTK("scsi%d: PHASE MISM or EOP interrupt\n", HOSTNO); + NCR5380_dma_complete( instance ); + done = 0; + ENABLE_IRQ(); + } else #endif /* REAL_DMA */ - { + { /* MS: Ignore unknown phase mismatch interrupts (caused by EOP interrupt) */ - if (basr & BASR_PHASE_MATCH) - printk(KERN_NOTICE "scsi%d: unknown interrupt, " - "BASR 0x%x, MR 0x%x, SR 0x%x\n", - HOSTNO, basr, NCR5380_read(MODE_REG), - NCR5380_read(STATUS_REG)); - (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); - } - } /* if !(SELECTION || PARITY) */ - handled = 1; - } /* BASR & IRQ */ - else { - printk(KERN_NOTICE "scsi%d: interrupt without IRQ bit set in BASR, " - "BASR 0x%X, MR 0x%X, SR 0x%x\n", HOSTNO, basr, - NCR5380_read(MODE_REG), NCR5380_read(STATUS_REG)); - (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); - } - - if (!done) { - INT_PRINTK("scsi%d: in int routine, calling main\n", HOSTNO); - /* Put a call to NCR5380_main() on the queue... */ - queue_main(); - } - return IRQ_RETVAL(handled); + if (basr & BASR_PHASE_MATCH) + printk(KERN_NOTICE "scsi%d: unknown interrupt, " + "BASR 0x%x, MR 0x%x, SR 0x%x\n", + HOSTNO, basr, NCR5380_read(MODE_REG), + NCR5380_read(STATUS_REG)); + (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG); + } + } /* if !(SELECTION || PARITY) */ + handled = 1; + } /* BASR & IRQ */ else { + printk(KERN_NOTICE "scsi%d: interrupt without IRQ bit set in BASR, " + "BASR 0x%X, MR 0x%X, SR 0x%x\n", HOSTNO, basr, + NCR5380_read(MODE_REG), NCR5380_read(STATUS_REG)); + (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG); + } + + if (!done) { + INT_PRINTK("scsi%d: in int routine, calling main\n", HOSTNO); + /* Put a call to NCR5380_main() on the queue... */ + queue_main(); + } + return IRQ_RETVAL(handled); } #ifdef NCR5380_STATS -static void collect_stats(struct NCR5380_hostdata* hostdata, Scsi_Cmnd* cmd) +static void collect_stats(struct NCR5380_hostdata* hostdata, Scsi_Cmnd *cmd) { # ifdef NCR5380_STAT_LIMIT - if (cmd->request_bufflen > NCR5380_STAT_LIMIT) + if (cmd->request_bufflen > NCR5380_STAT_LIMIT) # endif - switch (cmd->cmnd[0]) - { - case WRITE: - case WRITE_6: - case WRITE_10: - hostdata->time_write[cmd->device->id] += (jiffies - hostdata->timebase); - /*hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen;*/ - hostdata->pendingw--; - break; - case READ: - case READ_6: - case READ_10: - hostdata->time_read[cmd->device->id] += (jiffies - hostdata->timebase); - /*hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen;*/ - hostdata->pendingr--; - break; - } + switch (cmd->cmnd[0]) { + case WRITE: + case WRITE_6: + case WRITE_10: + hostdata->time_write[cmd->device->id] += (jiffies - hostdata->timebase); + /*hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen;*/ + hostdata->pendingw--; + break; + case READ: + case READ_6: + case READ_10: + hostdata->time_read[cmd->device->id] += (jiffies - hostdata->timebase); + /*hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen;*/ + hostdata->pendingr--; + break; + } } #endif -/* - * Function : int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, +/* + * Function : int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, * int tag); * * Purpose : establishes I_T_L or I_T_L_Q nexus for new or existing command, - * including ARBITRATION, SELECTION, and initial message out for - * IDENTIFY and queue messages. + * including ARBITRATION, SELECTION, and initial message out for + * IDENTIFY and queue messages. * - * Inputs : instance - instantiation of the 5380 driver on which this - * target lives, cmd - SCSI command to execute, tag - set to TAG_NEXT for - * new tag, TAG_NONE for untagged queueing, otherwise set to the tag for + * Inputs : instance - instantiation of the 5380 driver on which this + * target lives, cmd - SCSI command to execute, tag - set to TAG_NEXT for + * new tag, TAG_NONE for untagged queueing, otherwise set to the tag for * the command that is presently connected. - * + * * Returns : -1 if selection could not execute for some reason, - * 0 if selection succeeded or failed because the target - * did not respond. + * 0 if selection succeeded or failed because the target + * did not respond. * - * Side effects : - * If bus busy, arbitration failed, etc, NCR5380_select() will exit + * Side effects : + * If bus busy, arbitration failed, etc, NCR5380_select() will exit * with registers as they should have been on entry - ie * SELECT_ENABLE will be set appropriately, the NCR5380 * will cease to drive any SCSI bus signals. * - * If successful : I_T_L or I_T_L_Q nexus will be established, - * instance->connected will be set to cmd. - * SELECT interrupt will be disabled. + * If successful : I_T_L or I_T_L_Q nexus will be established, + * instance->connected will be set to cmd. + * SELECT interrupt will be disabled. * - * If failed (no target) : cmd->scsi_done() will be called, and the + * If failed (no target) : cmd->scsi_done() will be called, and the * cmd->result host byte set to DID_BAD_TARGET. */ -static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag) +static int NCR5380_select(struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag) { - SETUP_HOSTDATA(instance); - unsigned char tmp[3], phase; - unsigned char *data; - int len; - unsigned long timeout; - unsigned long flags; - - hostdata->restart_select = 0; - NCR_PRINT(NDEBUG_ARBITRATION); - ARB_PRINTK("scsi%d: starting arbitration, id = %d\n", HOSTNO, - instance->this_id); - - /* - * Set the phase bits to 0, otherwise the NCR5380 won't drive the - * data bus during SELECTION. - */ - - local_irq_save(flags); - if (hostdata->connected) { + SETUP_HOSTDATA(instance); + unsigned char tmp[3], phase; + unsigned char *data; + int len; + unsigned long timeout; + unsigned long flags; + + hostdata->restart_select = 0; + NCR_PRINT(NDEBUG_ARBITRATION); + ARB_PRINTK("scsi%d: starting arbitration, id = %d\n", HOSTNO, + instance->this_id); + + /* + * Set the phase bits to 0, otherwise the NCR5380 won't drive the + * data bus during SELECTION. + */ + + local_irq_save(flags); + if (hostdata->connected) { + local_irq_restore(flags); + return -1; + } + NCR5380_write(TARGET_COMMAND_REG, 0); + + /* + * Start arbitration. + */ + + NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask); + NCR5380_write(MODE_REG, MR_ARBITRATE); + local_irq_restore(flags); - return -1; - } - NCR5380_write(TARGET_COMMAND_REG, 0); - - - /* - * Start arbitration. - */ - - NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask); - NCR5380_write(MODE_REG, MR_ARBITRATE); - - local_irq_restore(flags); - - /* Wait for arbitration logic to complete */ -#if NCR_TIMEOUT - { - unsigned long timeout = jiffies + 2*NCR_TIMEOUT; - - while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS) - && time_before(jiffies, timeout) && !hostdata->connected) - ; - if (time_after_eq(jiffies, timeout)) - { - printk("scsi : arbitration timeout at %d\n", __LINE__); - NCR5380_write(MODE_REG, MR_BASE); - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - return -1; - } - } + + /* Wait for arbitration logic to complete */ +#if defined(NCR_TIMEOUT) + { + unsigned long timeout = jiffies + 2*NCR_TIMEOUT; + + while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS) && + time_before(jiffies, timeout) && !hostdata->connected) + ; + if (time_after_eq(jiffies, timeout)) { + printk("scsi : arbitration timeout at %d\n", __LINE__); + NCR5380_write(MODE_REG, MR_BASE); + NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); + return -1; + } + } #else /* NCR_TIMEOUT */ - while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS) - && !hostdata->connected); + while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS) && + !hostdata->connected) + ; #endif - ARB_PRINTK("scsi%d: arbitration complete\n", HOSTNO); - - if (hostdata->connected) { - NCR5380_write(MODE_REG, MR_BASE); - return -1; - } - /* - * The arbitration delay is 2.2us, but this is a minimum and there is - * no maximum so we can safely sleep for ceil(2.2) usecs to accommodate - * the integral nature of udelay(). - * - */ - - udelay(3); - - /* Check for lost arbitration */ - if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) || - (NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_higher_mask) || - (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) || - hostdata->connected) { - NCR5380_write(MODE_REG, MR_BASE); - ARB_PRINTK("scsi%d: lost arbitration, deasserting MR_ARBITRATE\n", - HOSTNO); - return -1; - } - - /* after/during arbitration, BSY should be asserted. - IBM DPES-31080 Version S31Q works now */ - /* Tnx to Thomas_Roesch@m2.maus.de for finding this! (Roman) */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_SEL | - ICR_ASSERT_BSY ) ; - - if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) || - hostdata->connected) { - NCR5380_write(MODE_REG, MR_BASE); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - ARB_PRINTK("scsi%d: lost arbitration, deasserting ICR_ASSERT_SEL\n", - HOSTNO); - return -1; - } + ARB_PRINTK("scsi%d: arbitration complete\n", HOSTNO); - /* - * Again, bus clear + bus settle time is 1.2us, however, this is - * a minimum so we'll udelay ceil(1.2) - */ + if (hostdata->connected) { + NCR5380_write(MODE_REG, MR_BASE); + return -1; + } + /* + * The arbitration delay is 2.2us, but this is a minimum and there is + * no maximum so we can safely sleep for ceil(2.2) usecs to accommodate + * the integral nature of udelay(). + * + */ + + udelay(3); + + /* Check for lost arbitration */ + if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) || + (NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_higher_mask) || + (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) || + hostdata->connected) { + NCR5380_write(MODE_REG, MR_BASE); + ARB_PRINTK("scsi%d: lost arbitration, deasserting MR_ARBITRATE\n", + HOSTNO); + return -1; + } + + /* after/during arbitration, BSY should be asserted. + IBM DPES-31080 Version S31Q works now */ + /* Tnx to Thomas_Roesch@m2.maus.de for finding this! (Roman) */ + NCR5380_write(INITIATOR_COMMAND_REG, + ICR_BASE | ICR_ASSERT_SEL | ICR_ASSERT_BSY); + + if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) || + hostdata->connected) { + NCR5380_write(MODE_REG, MR_BASE); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + ARB_PRINTK("scsi%d: lost arbitration, deasserting ICR_ASSERT_SEL\n", + HOSTNO); + return -1; + } + + /* + * Again, bus clear + bus settle time is 1.2us, however, this is + * a minimum so we'll udelay ceil(1.2) + */ #ifdef CONFIG_ATARI_SCSI_TOSHIBA_DELAY - /* ++roman: But some targets (see above :-) seem to need a bit more... */ - udelay(15); + /* ++roman: But some targets (see above :-) seem to need a bit more... */ + udelay(15); #else - udelay(2); + udelay(2); #endif - - if (hostdata->connected) { + + if (hostdata->connected) { + NCR5380_write(MODE_REG, MR_BASE); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + return -1; + } + + ARB_PRINTK("scsi%d: won arbitration\n", HOSTNO); + + /* + * Now that we have won arbitration, start Selection process, asserting + * the host and target ID's on the SCSI bus. + */ + + NCR5380_write(OUTPUT_DATA_REG, (hostdata->id_mask | (1 << cmd->device->id))); + + /* + * Raise ATN while SEL is true before BSY goes false from arbitration, + * since this is the only way to guarantee that we'll get a MESSAGE OUT + * phase immediately after selection. + */ + + NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_BSY | + ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL )); NCR5380_write(MODE_REG, MR_BASE); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - return -1; - } - ARB_PRINTK("scsi%d: won arbitration\n", HOSTNO); + /* + * Reselect interrupts must be turned off prior to the dropping of BSY, + * otherwise we will trigger an interrupt. + */ + + if (hostdata->connected) { + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + return -1; + } - /* - * Now that we have won arbitration, start Selection process, asserting - * the host and target ID's on the SCSI bus. - */ + NCR5380_write(SELECT_ENABLE_REG, 0); + + /* + * The initiator shall then wait at least two deskew delays and release + * the BSY signal. + */ + udelay(1); /* wingel -- wait two bus deskew delay >2*45ns */ + + /* Reset BSY */ + NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_DATA | + ICR_ASSERT_ATN | ICR_ASSERT_SEL)); + + /* + * Something weird happens when we cease to drive BSY - looks + * like the board/chip is letting us do another read before the + * appropriate propagation delay has expired, and we're confusing + * a BSY signal from ourselves as the target's response to SELECTION. + * + * A small delay (the 'C++' frontend breaks the pipeline with an + * unnecessary jump, making it work on my 386-33/Trantor T128, the + * tighter 'C' code breaks and requires this) solves the problem - + * the 1 us delay is arbitrary, and only used because this delay will + * be the same on other platforms and since it works here, it should + * work there. + * + * wingel suggests that this could be due to failing to wait + * one deskew delay. + */ - NCR5380_write(OUTPUT_DATA_REG, (hostdata->id_mask | (1 << cmd->device->id))); + udelay(1); - /* - * Raise ATN while SEL is true before BSY goes false from arbitration, - * since this is the only way to guarantee that we'll get a MESSAGE OUT - * phase immediately after selection. - */ + SEL_PRINTK("scsi%d: selecting target %d\n", HOSTNO, cmd->device->id); - NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_BSY | - ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL )); - NCR5380_write(MODE_REG, MR_BASE); + /* + * The SCSI specification calls for a 250 ms timeout for the actual + * selection. + */ - /* - * Reselect interrupts must be turned off prior to the dropping of BSY, - * otherwise we will trigger an interrupt. - */ + timeout = jiffies + 25; - if (hostdata->connected) { - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - return -1; - } - - NCR5380_write(SELECT_ENABLE_REG, 0); - - /* - * The initiator shall then wait at least two deskew delays and release - * the BSY signal. - */ - udelay(1); /* wingel -- wait two bus deskew delay >2*45ns */ - - /* Reset BSY */ - NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_DATA | - ICR_ASSERT_ATN | ICR_ASSERT_SEL)); - - /* - * Something weird happens when we cease to drive BSY - looks - * like the board/chip is letting us do another read before the - * appropriate propagation delay has expired, and we're confusing - * a BSY signal from ourselves as the target's response to SELECTION. - * - * A small delay (the 'C++' frontend breaks the pipeline with an - * unnecessary jump, making it work on my 386-33/Trantor T128, the - * tighter 'C' code breaks and requires this) solves the problem - - * the 1 us delay is arbitrary, and only used because this delay will - * be the same on other platforms and since it works here, it should - * work there. - * - * wingel suggests that this could be due to failing to wait - * one deskew delay. - */ - - udelay(1); - - SEL_PRINTK("scsi%d: selecting target %d\n", HOSTNO, cmd->device->id); - - /* - * The SCSI specification calls for a 250 ms timeout for the actual - * selection. - */ - - timeout = jiffies + 25; - - /* - * XXX very interesting - we're seeing a bounce where the BSY we - * asserted is being reflected / still asserted (propagation delay?) - * and it's detecting as true. Sigh. - */ + /* + * XXX very interesting - we're seeing a bounce where the BSY we + * asserted is being reflected / still asserted (propagation delay?) + * and it's detecting as true. Sigh. + */ #if 0 - /* ++roman: If a target conformed to the SCSI standard, it wouldn't assert - * IO while SEL is true. But again, there are some disks out the in the - * world that do that nevertheless. (Somebody claimed that this announces - * reselection capability of the target.) So we better skip that test and - * only wait for BSY... (Famous german words: Der Klügere gibt nach :-) - */ - - while (time_before(jiffies, timeout) && !(NCR5380_read(STATUS_REG) & - (SR_BSY | SR_IO))); - - if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == - (SR_SEL | SR_IO)) { - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - NCR5380_reselect(instance); - printk (KERN_ERR "scsi%d: reselection after won arbitration?\n", - HOSTNO); - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - return -1; - } + /* ++roman: If a target conformed to the SCSI standard, it wouldn't assert + * IO while SEL is true. But again, there are some disks out the in the + * world that do that nevertheless. (Somebody claimed that this announces + * reselection capability of the target.) So we better skip that test and + * only wait for BSY... (Famous german words: Der Klügere gibt nach :-) + */ + + while (time_before(jiffies, timeout) && + !(NCR5380_read(STATUS_REG) & (SR_BSY | SR_IO))) + ; + + if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == (SR_SEL | SR_IO)) { + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + NCR5380_reselect(instance); + printk(KERN_ERR "scsi%d: reselection after won arbitration?\n", + HOSTNO); + NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); + return -1; + } #else - while (time_before(jiffies, timeout) && !(NCR5380_read(STATUS_REG) & SR_BSY)); + while (time_before(jiffies, timeout) && !(NCR5380_read(STATUS_REG) & SR_BSY)) + ; #endif - /* - * No less than two deskew delays after the initiator detects the - * BSY signal is true, it shall release the SEL signal and may - * change the DATA BUS. -wingel - */ + /* + * No less than two deskew delays after the initiator detects the + * BSY signal is true, it shall release the SEL signal and may + * change the DATA BUS. -wingel + */ - udelay(1); + udelay(1); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); - if (!(NCR5380_read(STATUS_REG) & SR_BSY)) { - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - if (hostdata->targets_present & (1 << cmd->device->id)) { - printk(KERN_ERR "scsi%d: weirdness\n", HOSTNO); - if (hostdata->restart_select) - printk(KERN_NOTICE "\trestart select\n"); - NCR_PRINT(NDEBUG_ANY); - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - return -1; - } - cmd->result = DID_BAD_TARGET << 16; + if (!(NCR5380_read(STATUS_REG) & SR_BSY)) { + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + if (hostdata->targets_present & (1 << cmd->device->id)) { + printk(KERN_ERR "scsi%d: weirdness\n", HOSTNO); + if (hostdata->restart_select) + printk(KERN_NOTICE "\trestart select\n"); + NCR_PRINT(NDEBUG_ANY); + NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); + return -1; + } + cmd->result = DID_BAD_TARGET << 16; #ifdef NCR5380_STATS - collect_stats(hostdata, cmd); + collect_stats(hostdata, cmd); #endif #ifdef SUPPORT_TAGS - cmd_free_tag( cmd ); + cmd_free_tag(cmd); #endif - cmd->scsi_done(cmd); - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - SEL_PRINTK("scsi%d: target did not respond within 250ms\n", HOSTNO); - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - return 0; - } - - hostdata->targets_present |= (1 << cmd->device->id); - - /* - * Since we followed the SCSI spec, and raised ATN while SEL - * was true but before BSY was false during selection, the information - * transfer phase should be a MESSAGE OUT phase so that we can send the - * IDENTIFY message. - * - * If SCSI-II tagged queuing is enabled, we also send a SIMPLE_QUEUE_TAG - * message (2 bytes) with a tag ID that we increment with every command - * until it wraps back to 0. - * - * XXX - it turns out that there are some broken SCSI-II devices, - * which claim to support tagged queuing but fail when more than - * some number of commands are issued at once. - */ - - /* Wait for start of REQ/ACK handshake */ - while (!(NCR5380_read(STATUS_REG) & SR_REQ)); - - SEL_PRINTK("scsi%d: target %d selected, going into MESSAGE OUT phase.\n", - HOSTNO, cmd->device->id); - tmp[0] = IDENTIFY(1, cmd->device->lun); + cmd->scsi_done(cmd); + NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); + SEL_PRINTK("scsi%d: target did not respond within 250ms\n", HOSTNO); + NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); + return 0; + } + + hostdata->targets_present |= (1 << cmd->device->id); + + /* + * Since we followed the SCSI spec, and raised ATN while SEL + * was true but before BSY was false during selection, the information + * transfer phase should be a MESSAGE OUT phase so that we can send the + * IDENTIFY message. + * + * If SCSI-II tagged queuing is enabled, we also send a SIMPLE_QUEUE_TAG + * message (2 bytes) with a tag ID that we increment with every command + * until it wraps back to 0. + * + * XXX - it turns out that there are some broken SCSI-II devices, + * which claim to support tagged queuing but fail when more than + * some number of commands are issued at once. + */ + + /* Wait for start of REQ/ACK handshake */ + while (!(NCR5380_read(STATUS_REG) & SR_REQ)) + ; + + SEL_PRINTK("scsi%d: target %d selected, going into MESSAGE OUT phase.\n", + HOSTNO, cmd->device->id); + tmp[0] = IDENTIFY(1, cmd->device->lun); #ifdef SUPPORT_TAGS - if (cmd->tag != TAG_NONE) { - tmp[1] = hostdata->last_message = SIMPLE_QUEUE_TAG; - tmp[2] = cmd->tag; - len = 3; - } else - len = 1; + if (cmd->tag != TAG_NONE) { + tmp[1] = hostdata->last_message = SIMPLE_QUEUE_TAG; + tmp[2] = cmd->tag; + len = 3; + } else + len = 1; #else - len = 1; - cmd->tag=0; + len = 1; + cmd->tag = 0; #endif /* SUPPORT_TAGS */ - /* Send message(s) */ - data = tmp; - phase = PHASE_MSGOUT; - NCR5380_transfer_pio(instance, &phase, &len, &data); - SEL_PRINTK("scsi%d: nexus established.\n", HOSTNO); - /* XXX need to handle errors here */ - hostdata->connected = cmd; + /* Send message(s) */ + data = tmp; + phase = PHASE_MSGOUT; + NCR5380_transfer_pio(instance, &phase, &len, &data); + SEL_PRINTK("scsi%d: nexus established.\n", HOSTNO); + /* XXX need to handle errors here */ + hostdata->connected = cmd; #ifndef SUPPORT_TAGS - hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun); -#endif - - initialize_SCp(cmd); + hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun); +#endif + initialize_SCp(cmd); - return 0; + return 0; } -/* - * Function : int NCR5380_transfer_pio (struct Scsi_Host *instance, +/* + * Function : int NCR5380_transfer_pio (struct Scsi_Host *instance, * unsigned char *phase, int *count, unsigned char **data) * * Purpose : transfers data in given phase using polled I/O * - * Inputs : instance - instance of driver, *phase - pointer to - * what phase is expected, *count - pointer to number of + * Inputs : instance - instance of driver, *phase - pointer to + * what phase is expected, *count - pointer to number of * bytes to transfer, **data - pointer to data pointer. - * + * * Returns : -1 when different phase is entered without transferring * maximum number of bytes, 0 if all bytes are transfered or exit * is in same phase. * - * Also, *phase, *count, *data are modified in place. + * Also, *phase, *count, *data are modified in place. * * XXX Note : handling for bus free may be useful. */ /* - * Note : this code is not as quick as it could be, however it + * Note : this code is not as quick as it could be, however it * IS 100% reliable, and for the actual data transfer where speed * counts, we will always do a pseudo DMA or DMA transfer. */ -static int NCR5380_transfer_pio( struct Scsi_Host *instance, - unsigned char *phase, int *count, - unsigned char **data) +static int NCR5380_transfer_pio(struct Scsi_Host *instance, + unsigned char *phase, int *count, + unsigned char **data) { - register unsigned char p = *phase, tmp; - register int c = *count; - register unsigned char *d = *data; - - /* - * The NCR5380 chip will only drive the SCSI bus when the - * phase specified in the appropriate bits of the TARGET COMMAND - * REGISTER match the STATUS REGISTER - */ - - NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p)); - - do { - /* - * Wait for assertion of REQ, after which the phase bits will be - * valid + register unsigned char p = *phase, tmp; + register int c = *count; + register unsigned char *d = *data; + + /* + * The NCR5380 chip will only drive the SCSI bus when the + * phase specified in the appropriate bits of the TARGET COMMAND + * REGISTER match the STATUS REGISTER */ - while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ)); - HSH_PRINTK("scsi%d: REQ detected\n", HOSTNO); + NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p)); - /* Check for phase mismatch */ - if ((tmp & PHASE_MASK) != p) { - PIO_PRINTK("scsi%d: phase mismatch\n", HOSTNO); - NCR_PRINT_PHASE(NDEBUG_PIO); - break; - } + do { + /* + * Wait for assertion of REQ, after which the phase bits will be + * valid + */ + while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ)) + ; - /* Do actual transfer from SCSI bus to / from memory */ - if (!(p & SR_IO)) - NCR5380_write(OUTPUT_DATA_REG, *d); - else - *d = NCR5380_read(CURRENT_SCSI_DATA_REG); + HSH_PRINTK("scsi%d: REQ detected\n", HOSTNO); - ++d; + /* Check for phase mismatch */ + if ((tmp & PHASE_MASK) != p) { + PIO_PRINTK("scsi%d: phase mismatch\n", HOSTNO); + NCR_PRINT_PHASE(NDEBUG_PIO); + break; + } - /* - * The SCSI standard suggests that in MSGOUT phase, the initiator - * should drop ATN on the last byte of the message phase - * after REQ has been asserted for the handshake but before - * the initiator raises ACK. - */ + /* Do actual transfer from SCSI bus to / from memory */ + if (!(p & SR_IO)) + NCR5380_write(OUTPUT_DATA_REG, *d); + else + *d = NCR5380_read(CURRENT_SCSI_DATA_REG); - if (!(p & SR_IO)) { - if (!((p & SR_MSG) && c > 1)) { - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | - ICR_ASSERT_DATA); - NCR_PRINT(NDEBUG_PIO); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | - ICR_ASSERT_DATA | ICR_ASSERT_ACK); - } else { - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | - ICR_ASSERT_DATA | ICR_ASSERT_ATN); - NCR_PRINT(NDEBUG_PIO); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | - ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK); - } - } else { - NCR_PRINT(NDEBUG_PIO); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK); - } + ++d; - while (NCR5380_read(STATUS_REG) & SR_REQ); + /* + * The SCSI standard suggests that in MSGOUT phase, the initiator + * should drop ATN on the last byte of the message phase + * after REQ has been asserted for the handshake but before + * the initiator raises ACK. + */ - HSH_PRINTK("scsi%d: req false, handshake complete\n", HOSTNO); + if (!(p & SR_IO)) { + if (!((p & SR_MSG) && c > 1)) { + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA); + NCR_PRINT(NDEBUG_PIO); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | + ICR_ASSERT_DATA | ICR_ASSERT_ACK); + } else { + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | + ICR_ASSERT_DATA | ICR_ASSERT_ATN); + NCR_PRINT(NDEBUG_PIO); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | + ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK); + } + } else { + NCR_PRINT(NDEBUG_PIO); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK); + } -/* - * We have several special cases to consider during REQ/ACK handshaking : - * 1. We were in MSGOUT phase, and we are on the last byte of the - * message. ATN must be dropped as ACK is dropped. - * - * 2. We are in a MSGIN phase, and we are on the last byte of the - * message. We must exit with ACK asserted, so that the calling - * code may raise ATN before dropping ACK to reject the message. - * - * 3. ACK and ATN are clear and the target may proceed as normal. - */ - if (!(p == PHASE_MSGIN && c == 1)) { - if (p == PHASE_MSGOUT && c > 1) - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); - else - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - } - } while (--c); - - PIO_PRINTK("scsi%d: residual %d\n", HOSTNO, c); - - *count = c; - *data = d; - tmp = NCR5380_read(STATUS_REG); - /* The phase read from the bus is valid if either REQ is (already) - * asserted or if ACK hasn't been released yet. The latter is the case if - * we're in MSGIN and all wanted bytes have been received. */ - if ((tmp & SR_REQ) || (p == PHASE_MSGIN && c == 0)) - *phase = tmp & PHASE_MASK; - else - *phase = PHASE_UNKNOWN; - - if (!c || (*phase == p)) - return 0; - else - return -1; + while (NCR5380_read(STATUS_REG) & SR_REQ) + ; + + HSH_PRINTK("scsi%d: req false, handshake complete\n", HOSTNO); + + /* + * We have several special cases to consider during REQ/ACK handshaking : + * 1. We were in MSGOUT phase, and we are on the last byte of the + * message. ATN must be dropped as ACK is dropped. + * + * 2. We are in a MSGIN phase, and we are on the last byte of the + * message. We must exit with ACK asserted, so that the calling + * code may raise ATN before dropping ACK to reject the message. + * + * 3. ACK and ATN are clear and the target may proceed as normal. + */ + if (!(p == PHASE_MSGIN && c == 1)) { + if (p == PHASE_MSGOUT && c > 1) + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); + else + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + } + } while (--c); + + PIO_PRINTK("scsi%d: residual %d\n", HOSTNO, c); + + *count = c; + *data = d; + tmp = NCR5380_read(STATUS_REG); + /* The phase read from the bus is valid if either REQ is (already) + * asserted or if ACK hasn't been released yet. The latter is the case if + * we're in MSGIN and all wanted bytes have been received. + */ + if ((tmp & SR_REQ) || (p == PHASE_MSGIN && c == 0)) + *phase = tmp & PHASE_MASK; + else + *phase = PHASE_UNKNOWN; + + if (!c || (*phase == p)) + return 0; + else + return -1; } /* * Function : do_abort (Scsi_Host *host) - * - * Purpose : abort the currently established nexus. Should only be - * called from a routine which can drop into a - * + * + * Purpose : abort the currently established nexus. Should only be + * called from a routine which can drop into a + * * Returns : 0 on success, -1 on failure. */ -static int do_abort (struct Scsi_Host *host) +static int do_abort(struct Scsi_Host *host) { - unsigned char tmp, *msgptr, phase; - int len; - - /* Request message out phase */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); - - /* - * Wait for the target to indicate a valid phase by asserting - * REQ. Once this happens, we'll have either a MSGOUT phase - * and can immediately send the ABORT message, or we'll have some - * other phase and will have to source/sink data. - * - * We really don't care what value was on the bus or what value - * the target sees, so we just handshake. - */ - - while (!(tmp = NCR5380_read(STATUS_REG)) & SR_REQ); - - NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp)); - - if ((tmp & PHASE_MASK) != PHASE_MSGOUT) { - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | - ICR_ASSERT_ACK); - while (NCR5380_read(STATUS_REG) & SR_REQ); + unsigned char tmp, *msgptr, phase; + int len; + + /* Request message out phase */ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); - } - - tmp = ABORT; - msgptr = &tmp; - len = 1; - phase = PHASE_MSGOUT; - NCR5380_transfer_pio (host, &phase, &len, &msgptr); - - /* - * If we got here, and the command completed successfully, - * we're about to go into bus free state. - */ - - return len ? -1 : 0; + + /* + * Wait for the target to indicate a valid phase by asserting + * REQ. Once this happens, we'll have either a MSGOUT phase + * and can immediately send the ABORT message, or we'll have some + * other phase and will have to source/sink data. + * + * We really don't care what value was on the bus or what value + * the target sees, so we just handshake. + */ + + while (!(tmp = NCR5380_read(STATUS_REG)) & SR_REQ) + ; + + NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp)); + + if ((tmp & PHASE_MASK) != PHASE_MSGOUT) { + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | + ICR_ASSERT_ACK); + while (NCR5380_read(STATUS_REG) & SR_REQ) + ; + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); + } + + tmp = ABORT; + msgptr = &tmp; + len = 1; + phase = PHASE_MSGOUT; + NCR5380_transfer_pio(host, &phase, &len, &msgptr); + + /* + * If we got here, and the command completed successfully, + * we're about to go into bus free state. + */ + + return len ? -1 : 0; } #if defined(REAL_DMA) -/* - * Function : int NCR5380_transfer_dma (struct Scsi_Host *instance, +/* + * Function : int NCR5380_transfer_dma (struct Scsi_Host *instance, * unsigned char *phase, int *count, unsigned char **data) * * Purpose : transfers data in given phase using either real * or pseudo DMA. * - * Inputs : instance - instance of driver, *phase - pointer to - * what phase is expected, *count - pointer to number of + * Inputs : instance - instance of driver, *phase - pointer to + * what phase is expected, *count - pointer to number of * bytes to transfer, **data - pointer to data pointer. - * + * * Returns : -1 when different phase is entered without transferring * maximum number of bytes, 0 if all bytes or transfered or exit * is in same phase. * - * Also, *phase, *count, *data are modified in place. + * Also, *phase, *count, *data are modified in place. * */ -static int NCR5380_transfer_dma( struct Scsi_Host *instance, - unsigned char *phase, int *count, - unsigned char **data) +static int NCR5380_transfer_dma(struct Scsi_Host *instance, + unsigned char *phase, int *count, + unsigned char **data) { - SETUP_HOSTDATA(instance); - register int c = *count; - register unsigned char p = *phase; - register unsigned char *d = *data; - unsigned char tmp; - unsigned long flags; - - if ((tmp = (NCR5380_read(STATUS_REG) & PHASE_MASK)) != p) { - *phase = tmp; - return -1; - } + SETUP_HOSTDATA(instance); + register int c = *count; + register unsigned char p = *phase; + register unsigned char *d = *data; + unsigned char tmp; + unsigned long flags; + + if ((tmp = (NCR5380_read(STATUS_REG) & PHASE_MASK)) != p) { + *phase = tmp; + return -1; + } - if (atari_read_overruns && (p & SR_IO)) { - c -= atari_read_overruns; - } + if (atari_read_overruns && (p & SR_IO)) + c -= atari_read_overruns; - DMA_PRINTK("scsi%d: initializing DMA for %s, %d bytes %s %p\n", - HOSTNO, (p & SR_IO) ? "reading" : "writing", - c, (p & SR_IO) ? "to" : "from", d); + DMA_PRINTK("scsi%d: initializing DMA for %s, %d bytes %s %p\n", + HOSTNO, (p & SR_IO) ? "reading" : "writing", + c, (p & SR_IO) ? "to" : "from", d); - NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p)); + NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p)); #ifdef REAL_DMA - NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_ENABLE_EOP_INTR | MR_MONITOR_BSY); + NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_ENABLE_EOP_INTR | MR_MONITOR_BSY); #endif /* def REAL_DMA */ - if (IS_A_TT()) { - /* On the Medusa, it is a must to initialize the DMA before - * starting the NCR. This is also the cleaner way for the TT. - */ - local_irq_save(flags); - hostdata->dma_len = (p & SR_IO) ? - NCR5380_dma_read_setup(instance, d, c) : - NCR5380_dma_write_setup(instance, d, c); - local_irq_restore(flags); - } - - if (p & SR_IO) - NCR5380_write(START_DMA_INITIATOR_RECEIVE_REG, 0); - else { - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA); - NCR5380_write(START_DMA_SEND_REG, 0); - } - - if (!IS_A_TT()) { - /* On the Falcon, the DMA setup must be done after the last */ - /* NCR access, else the DMA setup gets trashed! - */ - local_irq_save(flags); - hostdata->dma_len = (p & SR_IO) ? - NCR5380_dma_read_setup(instance, d, c) : - NCR5380_dma_write_setup(instance, d, c); - local_irq_restore(flags); - } - return 0; + if (IS_A_TT()) { + /* On the Medusa, it is a must to initialize the DMA before + * starting the NCR. This is also the cleaner way for the TT. + */ + local_irq_save(flags); + hostdata->dma_len = (p & SR_IO) ? + NCR5380_dma_read_setup(instance, d, c) : + NCR5380_dma_write_setup(instance, d, c); + local_irq_restore(flags); + } + + if (p & SR_IO) + NCR5380_write(START_DMA_INITIATOR_RECEIVE_REG, 0); + else { + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA); + NCR5380_write(START_DMA_SEND_REG, 0); + } + + if (!IS_A_TT()) { + /* On the Falcon, the DMA setup must be done after the last */ + /* NCR access, else the DMA setup gets trashed! + */ + local_irq_save(flags); + hostdata->dma_len = (p & SR_IO) ? + NCR5380_dma_read_setup(instance, d, c) : + NCR5380_dma_write_setup(instance, d, c); + local_irq_restore(flags); + } + return 0; } #endif /* defined(REAL_DMA) */ /* * Function : NCR5380_information_transfer (struct Scsi_Host *instance) * - * Purpose : run through the various SCSI phases and do as the target - * directs us to. Operates on the currently connected command, + * Purpose : run through the various SCSI phases and do as the target + * directs us to. Operates on the currently connected command, * instance->connected. * * Inputs : instance, instance for which we are doing commands * - * Side effects : SCSI things happen, the disconnected queue will be + * Side effects : SCSI things happen, the disconnected queue will be * modified if a command disconnects, *instance->connected will * change. * - * XXX Note : we need to watch for bus free or a reset condition here - * to recover from an unexpected bus free condition. + * XXX Note : we need to watch for bus free or a reset condition here + * to recover from an unexpected bus free condition. */ - -static void NCR5380_information_transfer (struct Scsi_Host *instance) + +static void NCR5380_information_transfer(struct Scsi_Host *instance) { - SETUP_HOSTDATA(instance); - unsigned long flags; - unsigned char msgout = NOP; - int sink = 0; - int len; + SETUP_HOSTDATA(instance); + unsigned long flags; + unsigned char msgout = NOP; + int sink = 0; + int len; #if defined(REAL_DMA) - int transfersize; + int transfersize; #endif - unsigned char *data; - unsigned char phase, tmp, extended_msg[10], old_phase=0xff; - Scsi_Cmnd *cmd = (Scsi_Cmnd *) hostdata->connected; + unsigned char *data; + unsigned char phase, tmp, extended_msg[10], old_phase = 0xff; + Scsi_Cmnd *cmd = (Scsi_Cmnd *) hostdata->connected; + + while (1) { + tmp = NCR5380_read(STATUS_REG); + /* We only have a valid SCSI phase when REQ is asserted */ + if (tmp & SR_REQ) { + phase = (tmp & PHASE_MASK); + if (phase != old_phase) { + old_phase = phase; + NCR_PRINT_PHASE(NDEBUG_INFORMATION); + } - while (1) { - tmp = NCR5380_read(STATUS_REG); - /* We only have a valid SCSI phase when REQ is asserted */ - if (tmp & SR_REQ) { - phase = (tmp & PHASE_MASK); - if (phase != old_phase) { - old_phase = phase; - NCR_PRINT_PHASE(NDEBUG_INFORMATION); - } - - if (sink && (phase != PHASE_MSGOUT)) { - NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp)); - - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | - ICR_ASSERT_ACK); - while (NCR5380_read(STATUS_REG) & SR_REQ); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | - ICR_ASSERT_ATN); - sink = 0; - continue; - } - - switch (phase) { - case PHASE_DATAOUT: + if (sink && (phase != PHASE_MSGOUT)) { + NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp)); + + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | + ICR_ASSERT_ACK); + while (NCR5380_read(STATUS_REG) & SR_REQ) + ; + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | + ICR_ASSERT_ATN); + sink = 0; + continue; + } + + switch (phase) { + case PHASE_DATAOUT: #if (NDEBUG & NDEBUG_NO_DATAOUT) - printk("scsi%d: NDEBUG_NO_DATAOUT set, attempted DATAOUT " - "aborted\n", HOSTNO); - sink = 1; - do_abort(instance); - cmd->result = DID_ERROR << 16; - cmd->done(cmd); - return; + printk("scsi%d: NDEBUG_NO_DATAOUT set, attempted DATAOUT " + "aborted\n", HOSTNO); + sink = 1; + do_abort(instance); + cmd->result = DID_ERROR << 16; + cmd->done(cmd); + return; #endif - case PHASE_DATAIN: - /* - * If there is no room left in the current buffer in the - * scatter-gather list, move onto the next one. - */ - - if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) { - ++cmd->SCp.buffer; - --cmd->SCp.buffers_residual; - cmd->SCp.this_residual = cmd->SCp.buffer->length; - cmd->SCp.ptr = page_address(cmd->SCp.buffer->page)+ - cmd->SCp.buffer->offset; - /* ++roman: Try to merge some scatter-buffers if - * they are at contiguous physical addresses. - */ - merge_contiguous_buffers( cmd ); - INF_PRINTK("scsi%d: %d bytes and %d buffers left\n", - HOSTNO, cmd->SCp.this_residual, - cmd->SCp.buffers_residual); - } - - /* - * The preferred transfer method is going to be - * PSEUDO-DMA for systems that are strictly PIO, - * since we can let the hardware do the handshaking. - * - * For this to work, we need to know the transfersize - * ahead of time, since the pseudo-DMA code will sit - * in an unconditional loop. - */ - -/* ++roman: I suggest, this should be - * #if def(REAL_DMA) - * instead of leaving REAL_DMA out. - */ + case PHASE_DATAIN: + /* + * If there is no room left in the current buffer in the + * scatter-gather list, move onto the next one. + */ + + if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) { + ++cmd->SCp.buffer; + --cmd->SCp.buffers_residual; + cmd->SCp.this_residual = cmd->SCp.buffer->length; + cmd->SCp.ptr = page_address(cmd->SCp.buffer->page) + + cmd->SCp.buffer->offset; + /* ++roman: Try to merge some scatter-buffers if + * they are at contiguous physical addresses. + */ + merge_contiguous_buffers(cmd); + INF_PRINTK("scsi%d: %d bytes and %d buffers left\n", + HOSTNO, cmd->SCp.this_residual, + cmd->SCp.buffers_residual); + } + + /* + * The preferred transfer method is going to be + * PSEUDO-DMA for systems that are strictly PIO, + * since we can let the hardware do the handshaking. + * + * For this to work, we need to know the transfersize + * ahead of time, since the pseudo-DMA code will sit + * in an unconditional loop. + */ + + /* ++roman: I suggest, this should be + * #if def(REAL_DMA) + * instead of leaving REAL_DMA out. + */ #if defined(REAL_DMA) - if (!cmd->device->borken && - (transfersize = NCR5380_dma_xfer_len(instance,cmd,phase)) > 31) { - len = transfersize; - cmd->SCp.phase = phase; - if (NCR5380_transfer_dma(instance, &phase, - &len, (unsigned char **) &cmd->SCp.ptr)) { - /* - * If the watchdog timer fires, all future - * accesses to this device will use the - * polled-IO. */ - printk(KERN_NOTICE "scsi%d: switching target %d " - "lun %d to slow handshake\n", HOSTNO, - cmd->device->id, cmd->device->lun); - cmd->device->borken = 1; - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | - ICR_ASSERT_ATN); - sink = 1; - do_abort(instance); - cmd->result = DID_ERROR << 16; - cmd->done(cmd); - /* XXX - need to source or sink data here, as appropriate */ - } else { + if (!cmd->device->borken && + (transfersize = NCR5380_dma_xfer_len(instance,cmd,phase)) > 31) { + len = transfersize; + cmd->SCp.phase = phase; + if (NCR5380_transfer_dma(instance, &phase, + &len, (unsigned char **)&cmd->SCp.ptr)) { + /* + * If the watchdog timer fires, all future + * accesses to this device will use the + * polled-IO. */ + printk(KERN_NOTICE "scsi%d: switching target %d " + "lun %d to slow handshake\n", HOSTNO, + cmd->device->id, cmd->device->lun); + cmd->device->borken = 1; + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | + ICR_ASSERT_ATN); + sink = 1; + do_abort(instance); + cmd->result = DID_ERROR << 16; + cmd->done(cmd); + /* XXX - need to source or sink data here, as appropriate */ + } else { #ifdef REAL_DMA - /* ++roman: When using real DMA, - * information_transfer() should return after - * starting DMA since it has nothing more to - * do. - */ - return; -#else - cmd->SCp.this_residual -= transfersize - len; + /* ++roman: When using real DMA, + * information_transfer() should return after + * starting DMA since it has nothing more to + * do. + */ + return; +#else + cmd->SCp.this_residual -= transfersize - len; #endif - } - } else + } + } else #endif /* defined(REAL_DMA) */ - NCR5380_transfer_pio(instance, &phase, - (int *) &cmd->SCp.this_residual, (unsigned char **) - &cmd->SCp.ptr); - break; - case PHASE_MSGIN: - len = 1; - data = &tmp; - NCR5380_write(SELECT_ENABLE_REG, 0); /* disable reselects */ - NCR5380_transfer_pio(instance, &phase, &len, &data); - cmd->SCp.Message = tmp; - - switch (tmp) { - /* - * Linking lets us reduce the time required to get the - * next command out to the device, hopefully this will - * mean we don't waste another revolution due to the delays - * required by ARBITRATION and another SELECTION. - * - * In the current implementation proposal, low level drivers - * merely have to start the next command, pointed to by - * next_link, done() is called as with unlinked commands. - */ + NCR5380_transfer_pio(instance, &phase, + (int *)&cmd->SCp.this_residual, + (unsigned char **)&cmd->SCp.ptr); + break; + case PHASE_MSGIN: + len = 1; + data = &tmp; + NCR5380_write(SELECT_ENABLE_REG, 0); /* disable reselects */ + NCR5380_transfer_pio(instance, &phase, &len, &data); + cmd->SCp.Message = tmp; + + switch (tmp) { + /* + * Linking lets us reduce the time required to get the + * next command out to the device, hopefully this will + * mean we don't waste another revolution due to the delays + * required by ARBITRATION and another SELECTION. + * + * In the current implementation proposal, low level drivers + * merely have to start the next command, pointed to by + * next_link, done() is called as with unlinked commands. + */ #ifdef LINKED - case LINKED_CMD_COMPLETE: - case LINKED_FLG_CMD_COMPLETE: - /* Accept message by clearing ACK */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - - LNK_PRINTK("scsi%d: target %d lun %d linked command " - "complete.\n", HOSTNO, cmd->device->id, cmd->device->lun); - - /* Enable reselect interrupts */ - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - /* - * Sanity check : A linked command should only terminate - * with one of these messages if there are more linked - * commands available. - */ - - if (!cmd->next_link) { - printk(KERN_NOTICE "scsi%d: target %d lun %d " - "linked command complete, no next_link\n", - HOSTNO, cmd->device->id, cmd->device->lun); - sink = 1; - do_abort (instance); - return; - } - - initialize_SCp(cmd->next_link); - /* The next command is still part of this process; copy it - * and don't free it! */ - cmd->next_link->tag = cmd->tag; - cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); - LNK_PRINTK("scsi%d: target %d lun %d linked request " - "done, calling scsi_done().\n", - HOSTNO, cmd->device->id, cmd->device->lun); + case LINKED_CMD_COMPLETE: + case LINKED_FLG_CMD_COMPLETE: + /* Accept message by clearing ACK */ + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + + LNK_PRINTK("scsi%d: target %d lun %d linked command " + "complete.\n", HOSTNO, cmd->device->id, cmd->device->lun); + + /* Enable reselect interrupts */ + NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); + /* + * Sanity check : A linked command should only terminate + * with one of these messages if there are more linked + * commands available. + */ + + if (!cmd->next_link) { + printk(KERN_NOTICE "scsi%d: target %d lun %d " + "linked command complete, no next_link\n", + HOSTNO, cmd->device->id, cmd->device->lun); + sink = 1; + do_abort(instance); + return; + } + + initialize_SCp(cmd->next_link); + /* The next command is still part of this process; copy it + * and don't free it! */ + cmd->next_link->tag = cmd->tag; + cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); + LNK_PRINTK("scsi%d: target %d lun %d linked request " + "done, calling scsi_done().\n", + HOSTNO, cmd->device->id, cmd->device->lun); #ifdef NCR5380_STATS - collect_stats(hostdata, cmd); + collect_stats(hostdata, cmd); #endif - cmd->scsi_done(cmd); - cmd = hostdata->connected; - break; + cmd->scsi_done(cmd); + cmd = hostdata->connected; + break; #endif /* def LINKED */ - case ABORT: - case COMMAND_COMPLETE: - /* Accept message by clearing ACK */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - /* ++guenther: possible race with Falcon locking */ - falcon_dont_release++; - hostdata->connected = NULL; - QU_PRINTK("scsi%d: command for target %d, lun %d " - "completed\n", HOSTNO, cmd->device->id, cmd->device->lun); + case ABORT: + case COMMAND_COMPLETE: + /* Accept message by clearing ACK */ + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + /* ++guenther: possible race with Falcon locking */ + falcon_dont_release++; + hostdata->connected = NULL; + QU_PRINTK("scsi%d: command for target %d, lun %d " + "completed\n", HOSTNO, cmd->device->id, cmd->device->lun); #ifdef SUPPORT_TAGS - cmd_free_tag( cmd ); - if (status_byte(cmd->SCp.Status) == QUEUE_FULL) { - /* Turn a QUEUE FULL status into BUSY, I think the - * mid level cannot handle QUEUE FULL :-( (The - * command is retried after BUSY). Also update our - * queue size to the number of currently issued - * commands now. - */ - /* ++Andreas: the mid level code knows about - QUEUE_FULL now. */ - TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun]; - TAG_PRINTK("scsi%d: target %d lun %d returned " - "QUEUE_FULL after %d commands\n", - HOSTNO, cmd->device->id, cmd->device->lun, - ta->nr_allocated); - if (ta->queue_size > ta->nr_allocated) - ta->nr_allocated = ta->queue_size; - } + cmd_free_tag(cmd); + if (status_byte(cmd->SCp.Status) == QUEUE_FULL) { + /* Turn a QUEUE FULL status into BUSY, I think the + * mid level cannot handle QUEUE FULL :-( (The + * command is retried after BUSY). Also update our + * queue size to the number of currently issued + * commands now. + */ + /* ++Andreas: the mid level code knows about + QUEUE_FULL now. */ + TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun]; + TAG_PRINTK("scsi%d: target %d lun %d returned " + "QUEUE_FULL after %d commands\n", + HOSTNO, cmd->device->id, cmd->device->lun, + ta->nr_allocated); + if (ta->queue_size > ta->nr_allocated) + ta->nr_allocated = ta->queue_size; + } #else - hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); + hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); #endif - /* Enable reselect interrupts */ - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - - /* - * I'm not sure what the correct thing to do here is : - * - * If the command that just executed is NOT a request - * sense, the obvious thing to do is to set the result - * code to the values of the stored parameters. - * - * If it was a REQUEST SENSE command, we need some way to - * differentiate between the failure code of the original - * and the failure code of the REQUEST sense - the obvious - * case is success, where we fall through and leave the - * result code unchanged. - * - * The non-obvious place is where the REQUEST SENSE failed - */ - - if (cmd->cmnd[0] != REQUEST_SENSE) - cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); - else if (status_byte(cmd->SCp.Status) != GOOD) - cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16); - -#ifdef AUTOSENSE - if ((cmd->cmnd[0] != REQUEST_SENSE) && - (status_byte(cmd->SCp.Status) == CHECK_CONDITION)) { - ASEN_PRINTK("scsi%d: performing request sense\n", - HOSTNO); - cmd->cmnd[0] = REQUEST_SENSE; - cmd->cmnd[1] &= 0xe0; - cmd->cmnd[2] = 0; - cmd->cmnd[3] = 0; - cmd->cmnd[4] = sizeof(cmd->sense_buffer); - cmd->cmnd[5] = 0; - cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]); - - cmd->use_sg = 0; - /* this is initialized from initialize_SCp - cmd->SCp.buffer = NULL; - cmd->SCp.buffers_residual = 0; - */ - cmd->request_buffer = (char *) cmd->sense_buffer; - cmd->request_bufflen = sizeof(cmd->sense_buffer); + /* Enable reselect interrupts */ + NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); + + /* + * I'm not sure what the correct thing to do here is : + * + * If the command that just executed is NOT a request + * sense, the obvious thing to do is to set the result + * code to the values of the stored parameters. + * + * If it was a REQUEST SENSE command, we need some way to + * differentiate between the failure code of the original + * and the failure code of the REQUEST sense - the obvious + * case is success, where we fall through and leave the + * result code unchanged. + * + * The non-obvious place is where the REQUEST SENSE failed + */ + + if (cmd->cmnd[0] != REQUEST_SENSE) + cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); + else if (status_byte(cmd->SCp.Status) != GOOD) + cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16); - local_irq_save(flags); - LIST(cmd,hostdata->issue_queue); - NEXT(cmd) = hostdata->issue_queue; - hostdata->issue_queue = (Scsi_Cmnd *) cmd; - local_irq_restore(flags); - QU_PRINTK("scsi%d: REQUEST SENSE added to head of " - "issue queue\n", H_NO(cmd)); - } else +#ifdef AUTOSENSE + if ((cmd->cmnd[0] != REQUEST_SENSE) && + (status_byte(cmd->SCp.Status) == CHECK_CONDITION)) { + ASEN_PRINTK("scsi%d: performing request sense\n", HOSTNO); + cmd->cmnd[0] = REQUEST_SENSE; + cmd->cmnd[1] &= 0xe0; + cmd->cmnd[2] = 0; + cmd->cmnd[3] = 0; + cmd->cmnd[4] = sizeof(cmd->sense_buffer); + cmd->cmnd[5] = 0; + cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]); + + cmd->use_sg = 0; + /* this is initialized from initialize_SCp + cmd->SCp.buffer = NULL; + cmd->SCp.buffers_residual = 0; + */ + cmd->request_buffer = (char *) cmd->sense_buffer; + cmd->request_bufflen = sizeof(cmd->sense_buffer); + + local_irq_save(flags); + LIST(cmd,hostdata->issue_queue); + SET_NEXT(cmd, hostdata->issue_queue); + hostdata->issue_queue = (Scsi_Cmnd *) cmd; + local_irq_restore(flags); + QU_PRINTK("scsi%d: REQUEST SENSE added to head of " + "issue queue\n", H_NO(cmd)); + } else #endif /* def AUTOSENSE */ - { + { #ifdef NCR5380_STATS - collect_stats(hostdata, cmd); + collect_stats(hostdata, cmd); #endif - cmd->scsi_done(cmd); - } - - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - /* - * Restore phase bits to 0 so an interrupted selection, - * arbitration can resume. - */ - NCR5380_write(TARGET_COMMAND_REG, 0); - - while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected) - barrier(); - - falcon_dont_release--; - /* ++roman: For Falcon SCSI, release the lock on the - * ST-DMA here if no other commands are waiting on the - * disconnected queue. - */ - falcon_release_lock_if_possible( hostdata ); - return; - case MESSAGE_REJECT: - /* Accept message by clearing ACK */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - /* Enable reselect interrupts */ - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - switch (hostdata->last_message) { - case HEAD_OF_QUEUE_TAG: - case ORDERED_QUEUE_TAG: - case SIMPLE_QUEUE_TAG: - /* The target obviously doesn't support tagged - * queuing, even though it announced this ability in - * its INQUIRY data ?!? (maybe only this LUN?) Ok, - * clear 'tagged_supported' and lock the LUN, since - * the command is treated as untagged further on. - */ - cmd->device->tagged_supported = 0; - hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun); - cmd->tag = TAG_NONE; - TAG_PRINTK("scsi%d: target %d lun %d rejected " - "QUEUE_TAG message; tagged queuing " - "disabled\n", - HOSTNO, cmd->device->id, cmd->device->lun); - break; - } - break; - case DISCONNECT: - /* Accept message by clearing ACK */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - local_irq_save(flags); - cmd->device->disconnect = 1; - LIST(cmd,hostdata->disconnected_queue); - NEXT(cmd) = hostdata->disconnected_queue; - hostdata->connected = NULL; - hostdata->disconnected_queue = cmd; - local_irq_restore(flags); - QU_PRINTK("scsi%d: command for target %d lun %d was " - "moved from connected to the " - "disconnected_queue\n", HOSTNO, - cmd->device->id, cmd->device->lun); - /* - * Restore phase bits to 0 so an interrupted selection, - * arbitration can resume. - */ - NCR5380_write(TARGET_COMMAND_REG, 0); - - /* Enable reselect interrupts */ - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - /* Wait for bus free to avoid nasty timeouts */ - while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected) - barrier(); - return; - /* - * The SCSI data pointer is *IMPLICITLY* saved on a disconnect - * operation, in violation of the SCSI spec so we can safely - * ignore SAVE/RESTORE pointers calls. - * - * Unfortunately, some disks violate the SCSI spec and - * don't issue the required SAVE_POINTERS message before - * disconnecting, and we have to break spec to remain - * compatible. - */ - case SAVE_POINTERS: - case RESTORE_POINTERS: - /* Accept message by clearing ACK */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - /* Enable reselect interrupts */ - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - break; - case EXTENDED_MESSAGE: -/* - * Extended messages are sent in the following format : - * Byte - * 0 EXTENDED_MESSAGE == 1 - * 1 length (includes one byte for code, doesn't - * include first two bytes) - * 2 code - * 3..length+1 arguments - * - * Start the extended message buffer with the EXTENDED_MESSAGE - * byte, since spi_print_msg() wants the whole thing. - */ - extended_msg[0] = EXTENDED_MESSAGE; - /* Accept first byte by clearing ACK */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - - EXT_PRINTK("scsi%d: receiving extended message\n", HOSTNO); - - len = 2; - data = extended_msg + 1; - phase = PHASE_MSGIN; - NCR5380_transfer_pio(instance, &phase, &len, &data); - EXT_PRINTK("scsi%d: length=%d, code=0x%02x\n", HOSTNO, - (int)extended_msg[1], (int)extended_msg[2]); - - if (!len && extended_msg[1] <= - (sizeof (extended_msg) - 1)) { - /* Accept third byte by clearing ACK */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - len = extended_msg[1] - 1; - data = extended_msg + 3; - phase = PHASE_MSGIN; - - NCR5380_transfer_pio(instance, &phase, &len, &data); - EXT_PRINTK("scsi%d: message received, residual %d\n", - HOSTNO, len); - - switch (extended_msg[2]) { - case EXTENDED_SDTR: - case EXTENDED_WDTR: - case EXTENDED_MODIFY_DATA_POINTER: - case EXTENDED_EXTENDED_IDENTIFY: - tmp = 0; - } - } else if (len) { - printk(KERN_NOTICE "scsi%d: error receiving " - "extended message\n", HOSTNO); - tmp = 0; - } else { - printk(KERN_NOTICE "scsi%d: extended message " - "code %02x length %d is too long\n", - HOSTNO, extended_msg[2], extended_msg[1]); - tmp = 0; - } - /* Fall through to reject message */ - - /* - * If we get something weird that we aren't expecting, - * reject it. - */ - default: - if (!tmp) { - printk(KERN_DEBUG "scsi%d: rejecting message ", HOSTNO); - spi_print_msg(extended_msg); - printk("\n"); - } else if (tmp != EXTENDED_MESSAGE) - printk(KERN_DEBUG "scsi%d: rejecting unknown " - "message %02x from target %d, lun %d\n", - HOSTNO, tmp, cmd->device->id, cmd->device->lun); - else - printk(KERN_DEBUG "scsi%d: rejecting unknown " - "extended message " - "code %02x, length %d from target %d, lun %d\n", - HOSTNO, extended_msg[1], extended_msg[0], - cmd->device->id, cmd->device->lun); - - - msgout = MESSAGE_REJECT; - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | - ICR_ASSERT_ATN); - break; - } /* switch (tmp) */ - break; - case PHASE_MSGOUT: - len = 1; - data = &msgout; - hostdata->last_message = msgout; - NCR5380_transfer_pio(instance, &phase, &len, &data); - if (msgout == ABORT) { + cmd->scsi_done(cmd); + } + + NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); + /* + * Restore phase bits to 0 so an interrupted selection, + * arbitration can resume. + */ + NCR5380_write(TARGET_COMMAND_REG, 0); + + while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected) + barrier(); + + falcon_dont_release--; + /* ++roman: For Falcon SCSI, release the lock on the + * ST-DMA here if no other commands are waiting on the + * disconnected queue. + */ + falcon_release_lock_if_possible(hostdata); + return; + case MESSAGE_REJECT: + /* Accept message by clearing ACK */ + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + /* Enable reselect interrupts */ + NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); + switch (hostdata->last_message) { + case HEAD_OF_QUEUE_TAG: + case ORDERED_QUEUE_TAG: + case SIMPLE_QUEUE_TAG: + /* The target obviously doesn't support tagged + * queuing, even though it announced this ability in + * its INQUIRY data ?!? (maybe only this LUN?) Ok, + * clear 'tagged_supported' and lock the LUN, since + * the command is treated as untagged further on. + */ + cmd->device->tagged_supported = 0; + hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun); + cmd->tag = TAG_NONE; + TAG_PRINTK("scsi%d: target %d lun %d rejected " + "QUEUE_TAG message; tagged queuing " + "disabled\n", + HOSTNO, cmd->device->id, cmd->device->lun); + break; + } + break; + case DISCONNECT: + /* Accept message by clearing ACK */ + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + local_irq_save(flags); + cmd->device->disconnect = 1; + LIST(cmd,hostdata->disconnected_queue); + SET_NEXT(cmd, hostdata->disconnected_queue); + hostdata->connected = NULL; + hostdata->disconnected_queue = cmd; + local_irq_restore(flags); + QU_PRINTK("scsi%d: command for target %d lun %d was " + "moved from connected to the " + "disconnected_queue\n", HOSTNO, + cmd->device->id, cmd->device->lun); + /* + * Restore phase bits to 0 so an interrupted selection, + * arbitration can resume. + */ + NCR5380_write(TARGET_COMMAND_REG, 0); + + /* Enable reselect interrupts */ + NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); + /* Wait for bus free to avoid nasty timeouts */ + while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected) + barrier(); + return; + /* + * The SCSI data pointer is *IMPLICITLY* saved on a disconnect + * operation, in violation of the SCSI spec so we can safely + * ignore SAVE/RESTORE pointers calls. + * + * Unfortunately, some disks violate the SCSI spec and + * don't issue the required SAVE_POINTERS message before + * disconnecting, and we have to break spec to remain + * compatible. + */ + case SAVE_POINTERS: + case RESTORE_POINTERS: + /* Accept message by clearing ACK */ + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + /* Enable reselect interrupts */ + NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); + break; + case EXTENDED_MESSAGE: + /* + * Extended messages are sent in the following format : + * Byte + * 0 EXTENDED_MESSAGE == 1 + * 1 length (includes one byte for code, doesn't + * include first two bytes) + * 2 code + * 3..length+1 arguments + * + * Start the extended message buffer with the EXTENDED_MESSAGE + * byte, since spi_print_msg() wants the whole thing. + */ + extended_msg[0] = EXTENDED_MESSAGE; + /* Accept first byte by clearing ACK */ + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + + EXT_PRINTK("scsi%d: receiving extended message\n", HOSTNO); + + len = 2; + data = extended_msg + 1; + phase = PHASE_MSGIN; + NCR5380_transfer_pio(instance, &phase, &len, &data); + EXT_PRINTK("scsi%d: length=%d, code=0x%02x\n", HOSTNO, + (int)extended_msg[1], (int)extended_msg[2]); + + if (!len && extended_msg[1] <= + (sizeof(extended_msg) - 1)) { + /* Accept third byte by clearing ACK */ + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + len = extended_msg[1] - 1; + data = extended_msg + 3; + phase = PHASE_MSGIN; + + NCR5380_transfer_pio(instance, &phase, &len, &data); + EXT_PRINTK("scsi%d: message received, residual %d\n", + HOSTNO, len); + + switch (extended_msg[2]) { + case EXTENDED_SDTR: + case EXTENDED_WDTR: + case EXTENDED_MODIFY_DATA_POINTER: + case EXTENDED_EXTENDED_IDENTIFY: + tmp = 0; + } + } else if (len) { + printk(KERN_NOTICE "scsi%d: error receiving " + "extended message\n", HOSTNO); + tmp = 0; + } else { + printk(KERN_NOTICE "scsi%d: extended message " + "code %02x length %d is too long\n", + HOSTNO, extended_msg[2], extended_msg[1]); + tmp = 0; + } + /* Fall through to reject message */ + + /* + * If we get something weird that we aren't expecting, + * reject it. + */ + default: + if (!tmp) { + printk(KERN_DEBUG "scsi%d: rejecting message ", HOSTNO); + spi_print_msg(extended_msg); + printk("\n"); + } else if (tmp != EXTENDED_MESSAGE) + printk(KERN_DEBUG "scsi%d: rejecting unknown " + "message %02x from target %d, lun %d\n", + HOSTNO, tmp, cmd->device->id, cmd->device->lun); + else + printk(KERN_DEBUG "scsi%d: rejecting unknown " + "extended message " + "code %02x, length %d from target %d, lun %d\n", + HOSTNO, extended_msg[1], extended_msg[0], + cmd->device->id, cmd->device->lun); + + + msgout = MESSAGE_REJECT; + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); + break; + } /* switch (tmp) */ + break; + case PHASE_MSGOUT: + len = 1; + data = &msgout; + hostdata->last_message = msgout; + NCR5380_transfer_pio(instance, &phase, &len, &data); + if (msgout == ABORT) { #ifdef SUPPORT_TAGS - cmd_free_tag( cmd ); + cmd_free_tag(cmd); #else - hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); + hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); #endif - hostdata->connected = NULL; - cmd->result = DID_ERROR << 16; + hostdata->connected = NULL; + cmd->result = DID_ERROR << 16; #ifdef NCR5380_STATS - collect_stats(hostdata, cmd); + collect_stats(hostdata, cmd); #endif - cmd->scsi_done(cmd); - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - falcon_release_lock_if_possible( hostdata ); - return; - } - msgout = NOP; - break; - case PHASE_CMDOUT: - len = cmd->cmd_len; - data = cmd->cmnd; - /* - * XXX for performance reasons, on machines with a - * PSEUDO-DMA architecture we should probably - * use the dma transfer function. - */ - NCR5380_transfer_pio(instance, &phase, &len, - &data); - break; - case PHASE_STATIN: - len = 1; - data = &tmp; - NCR5380_transfer_pio(instance, &phase, &len, &data); - cmd->SCp.Status = tmp; - break; - default: - printk("scsi%d: unknown phase\n", HOSTNO); - NCR_PRINT(NDEBUG_ANY); - } /* switch(phase) */ - } /* if (tmp * SR_REQ) */ - } /* while (1) */ + cmd->scsi_done(cmd); + NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); + falcon_release_lock_if_possible(hostdata); + return; + } + msgout = NOP; + break; + case PHASE_CMDOUT: + len = cmd->cmd_len; + data = cmd->cmnd; + /* + * XXX for performance reasons, on machines with a + * PSEUDO-DMA architecture we should probably + * use the dma transfer function. + */ + NCR5380_transfer_pio(instance, &phase, &len, &data); + break; + case PHASE_STATIN: + len = 1; + data = &tmp; + NCR5380_transfer_pio(instance, &phase, &len, &data); + cmd->SCp.Status = tmp; + break; + default: + printk("scsi%d: unknown phase\n", HOSTNO); + NCR_PRINT(NDEBUG_ANY); + } /* switch(phase) */ + } /* if (tmp * SR_REQ) */ + } /* while (1) */ } /* * Function : void NCR5380_reselect (struct Scsi_Host *instance) * - * Purpose : does reselection, initializing the instance->connected - * field to point to the Scsi_Cmnd for which the I_T_L or I_T_L_Q + * Purpose : does reselection, initializing the instance->connected + * field to point to the Scsi_Cmnd for which the I_T_L or I_T_L_Q * nexus has been reestablished, - * + * * Inputs : instance - this instance of the NCR5380. * */ -static void NCR5380_reselect (struct Scsi_Host *instance) +static void NCR5380_reselect(struct Scsi_Host *instance) { - SETUP_HOSTDATA(instance); - unsigned char target_mask; - unsigned char lun, phase; - int len; + SETUP_HOSTDATA(instance); + unsigned char target_mask; + unsigned char lun, phase; + int len; #ifdef SUPPORT_TAGS - unsigned char tag; + unsigned char tag; #endif - unsigned char msg[3]; - unsigned char *data; - Scsi_Cmnd *tmp = NULL, *prev; -/* unsigned long flags; */ - - /* - * Disable arbitration, etc. since the host adapter obviously - * lost, and tell an interrupted NCR5380_select() to restart. - */ - - NCR5380_write(MODE_REG, MR_BASE); - hostdata->restart_select = 1; - - target_mask = NCR5380_read(CURRENT_SCSI_DATA_REG) & ~(hostdata->id_mask); - - RSL_PRINTK("scsi%d: reselect\n", HOSTNO); - - /* - * At this point, we have detected that our SCSI ID is on the bus, - * SEL is true and BSY was false for at least one bus settle delay - * (400 ns). - * - * We must assert BSY ourselves, until the target drops the SEL - * signal. - */ - - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY); - - while (NCR5380_read(STATUS_REG) & SR_SEL); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - - /* - * Wait for target to go into MSGIN. - */ - - while (!(NCR5380_read(STATUS_REG) & SR_REQ)); - - len = 1; - data = msg; - phase = PHASE_MSGIN; - NCR5380_transfer_pio(instance, &phase, &len, &data); - - if (!(msg[0] & 0x80)) { - printk(KERN_DEBUG "scsi%d: expecting IDENTIFY message, got ", HOSTNO); - spi_print_msg(msg); - do_abort(instance); - return; - } - lun = (msg[0] & 0x07); + unsigned char msg[3]; + unsigned char *data; + Scsi_Cmnd *tmp = NULL, *prev; +/* unsigned long flags; */ + + /* + * Disable arbitration, etc. since the host adapter obviously + * lost, and tell an interrupted NCR5380_select() to restart. + */ + + NCR5380_write(MODE_REG, MR_BASE); + hostdata->restart_select = 1; + + target_mask = NCR5380_read(CURRENT_SCSI_DATA_REG) & ~(hostdata->id_mask); + + RSL_PRINTK("scsi%d: reselect\n", HOSTNO); + + /* + * At this point, we have detected that our SCSI ID is on the bus, + * SEL is true and BSY was false for at least one bus settle delay + * (400 ns). + * + * We must assert BSY ourselves, until the target drops the SEL + * signal. + */ + + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY); + + while (NCR5380_read(STATUS_REG) & SR_SEL) + ; + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + + /* + * Wait for target to go into MSGIN. + */ + + while (!(NCR5380_read(STATUS_REG) & SR_REQ)) + ; + + len = 1; + data = msg; + phase = PHASE_MSGIN; + NCR5380_transfer_pio(instance, &phase, &len, &data); + + if (!(msg[0] & 0x80)) { + printk(KERN_DEBUG "scsi%d: expecting IDENTIFY message, got ", HOSTNO); + spi_print_msg(msg); + do_abort(instance); + return; + } + lun = (msg[0] & 0x07); #ifdef SUPPORT_TAGS - /* If the phase is still MSGIN, the target wants to send some more - * messages. In case it supports tagged queuing, this is probably a - * SIMPLE_QUEUE_TAG for the I_T_L_Q nexus. - */ - tag = TAG_NONE; - if (phase == PHASE_MSGIN && setup_use_tagged_queuing) { - /* Accept previous IDENTIFY message by clearing ACK */ - NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE ); - len = 2; - data = msg+1; - if (!NCR5380_transfer_pio(instance, &phase, &len, &data) && - msg[1] == SIMPLE_QUEUE_TAG) - tag = msg[2]; - TAG_PRINTK("scsi%d: target mask %02x, lun %d sent tag %d at " - "reselection\n", HOSTNO, target_mask, lun, tag); - } + /* If the phase is still MSGIN, the target wants to send some more + * messages. In case it supports tagged queuing, this is probably a + * SIMPLE_QUEUE_TAG for the I_T_L_Q nexus. + */ + tag = TAG_NONE; + if (phase == PHASE_MSGIN && setup_use_tagged_queuing) { + /* Accept previous IDENTIFY message by clearing ACK */ + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + len = 2; + data = msg + 1; + if (!NCR5380_transfer_pio(instance, &phase, &len, &data) && + msg[1] == SIMPLE_QUEUE_TAG) + tag = msg[2]; + TAG_PRINTK("scsi%d: target mask %02x, lun %d sent tag %d at " + "reselection\n", HOSTNO, target_mask, lun, tag); + } #endif - - /* - * Find the command corresponding to the I_T_L or I_T_L_Q nexus we - * just reestablished, and remove it from the disconnected queue. - */ - - for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue, prev = NULL; - tmp; prev = tmp, tmp = NEXT(tmp) ) { - if ((target_mask == (1 << tmp->device->id)) && (lun == tmp->device->lun) + + /* + * Find the command corresponding to the I_T_L or I_T_L_Q nexus we + * just reestablished, and remove it from the disconnected queue. + */ + + for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue, prev = NULL; + tmp; prev = tmp, tmp = NEXT(tmp)) { + if ((target_mask == (1 << tmp->device->id)) && (lun == tmp->device->lun) #ifdef SUPPORT_TAGS - && (tag == tmp->tag) + && (tag == tmp->tag) #endif - ) { - /* ++guenther: prevent race with falcon_release_lock */ - falcon_dont_release++; - if (prev) { - REMOVE(prev, NEXT(prev), tmp, NEXT(tmp)); - NEXT(prev) = NEXT(tmp); - } else { - REMOVE(-1, hostdata->disconnected_queue, tmp, NEXT(tmp)); - hostdata->disconnected_queue = NEXT(tmp); - } - NEXT(tmp) = NULL; - break; + ) { + /* ++guenther: prevent race with falcon_release_lock */ + falcon_dont_release++; + if (prev) { + REMOVE(prev, NEXT(prev), tmp, NEXT(tmp)); + SET_NEXT(prev, NEXT(tmp)); + } else { + REMOVE(-1, hostdata->disconnected_queue, tmp, NEXT(tmp)); + hostdata->disconnected_queue = NEXT(tmp); + } + SET_NEXT(tmp, NULL); + break; + } } - } - - if (!tmp) { - printk(KERN_WARNING "scsi%d: warning: target bitmask %02x lun %d " + + if (!tmp) { + printk(KERN_WARNING "scsi%d: warning: target bitmask %02x lun %d " #ifdef SUPPORT_TAGS - "tag %d " + "tag %d " #endif - "not in disconnected_queue.\n", - HOSTNO, target_mask, lun + "not in disconnected_queue.\n", + HOSTNO, target_mask, lun #ifdef SUPPORT_TAGS - , tag + , tag #endif - ); - /* - * Since we have an established nexus that we can't do anything - * with, we must abort it. - */ - do_abort(instance); - return; - } + ); + /* + * Since we have an established nexus that we can't do anything + * with, we must abort it. + */ + do_abort(instance); + return; + } - /* Accept message by clearing ACK */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + /* Accept message by clearing ACK */ + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - hostdata->connected = tmp; - RSL_PRINTK("scsi%d: nexus established, target = %d, lun = %d, tag = %d\n", - HOSTNO, tmp->device->id, tmp->device->lun, tmp->tag); - falcon_dont_release--; + hostdata->connected = tmp; + RSL_PRINTK("scsi%d: nexus established, target = %d, lun = %d, tag = %d\n", + HOSTNO, tmp->device->id, tmp->device->lun, tmp->tag); + falcon_dont_release--; } @@ -2626,362 +2677,361 @@ static void NCR5380_reselect (struct Scsi_Host *instance) * * Purpose : abort a command * - * Inputs : cmd - the Scsi_Cmnd to abort, code - code to set the - * host byte of the result field to, if zero DID_ABORTED is + * Inputs : cmd - the Scsi_Cmnd to abort, code - code to set the + * host byte of the result field to, if zero DID_ABORTED is * used. * * Returns : 0 - success, -1 on failure. * - * XXX - there is no way to abort the command that is currently - * connected, you have to wait for it to complete. If this is + * XXX - there is no way to abort the command that is currently + * connected, you have to wait for it to complete. If this is * a problem, we could implement longjmp() / setjmp(), setjmp() - * called where the loop started in NCR5380_main(). + * called where the loop started in NCR5380_main(). */ static -int NCR5380_abort (Scsi_Cmnd *cmd) +int NCR5380_abort(Scsi_Cmnd *cmd) { - struct Scsi_Host *instance = cmd->device->host; - SETUP_HOSTDATA(instance); - Scsi_Cmnd *tmp, **prev; - unsigned long flags; + struct Scsi_Host *instance = cmd->device->host; + SETUP_HOSTDATA(instance); + Scsi_Cmnd *tmp, **prev; + unsigned long flags; + + printk(KERN_NOTICE "scsi%d: aborting command\n", HOSTNO); + scsi_print_command(cmd); - printk(KERN_NOTICE "scsi%d: aborting command\n", HOSTNO); - scsi_print_command(cmd); + NCR5380_print_status(instance); - NCR5380_print_status (instance); + local_irq_save(flags); - local_irq_save(flags); - - if (!IS_A_TT() && !falcon_got_lock) - printk(KERN_ERR "scsi%d: !!BINGO!! Falcon has no lock in NCR5380_abort\n", - HOSTNO); + if (!IS_A_TT() && !falcon_got_lock) + printk(KERN_ERR "scsi%d: !!BINGO!! Falcon has no lock in NCR5380_abort\n", + HOSTNO); - ABRT_PRINTK("scsi%d: abort called basr 0x%02x, sr 0x%02x\n", HOSTNO, - NCR5380_read(BUS_AND_STATUS_REG), - NCR5380_read(STATUS_REG)); + ABRT_PRINTK("scsi%d: abort called basr 0x%02x, sr 0x%02x\n", HOSTNO, + NCR5380_read(BUS_AND_STATUS_REG), + NCR5380_read(STATUS_REG)); #if 1 -/* - * Case 1 : If the command is the currently executing command, - * we'll set the aborted flag and return control so that - * information transfer routine can exit cleanly. - */ + /* + * Case 1 : If the command is the currently executing command, + * we'll set the aborted flag and return control so that + * information transfer routine can exit cleanly. + */ - if (hostdata->connected == cmd) { + if (hostdata->connected == cmd) { - ABRT_PRINTK("scsi%d: aborting connected command\n", HOSTNO); -/* - * We should perform BSY checking, and make sure we haven't slipped - * into BUS FREE. - */ + ABRT_PRINTK("scsi%d: aborting connected command\n", HOSTNO); + /* + * We should perform BSY checking, and make sure we haven't slipped + * into BUS FREE. + */ -/* NCR5380_write(INITIATOR_COMMAND_REG, ICR_ASSERT_ATN); */ -/* - * Since we can't change phases until we've completed the current - * handshake, we have to source or sink a byte of data if the current - * phase is not MSGOUT. - */ + /* NCR5380_write(INITIATOR_COMMAND_REG, ICR_ASSERT_ATN); */ + /* + * Since we can't change phases until we've completed the current + * handshake, we have to source or sink a byte of data if the current + * phase is not MSGOUT. + */ -/* - * Return control to the executing NCR drive so we can clear the - * aborted flag and get back into our main loop. - */ + /* + * Return control to the executing NCR drive so we can clear the + * aborted flag and get back into our main loop. + */ - if (do_abort(instance) == 0) { - hostdata->aborted = 1; - hostdata->connected = NULL; - cmd->result = DID_ABORT << 16; + if (do_abort(instance) == 0) { + hostdata->aborted = 1; + hostdata->connected = NULL; + cmd->result = DID_ABORT << 16; #ifdef SUPPORT_TAGS - cmd_free_tag( cmd ); + cmd_free_tag(cmd); #else - hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); + hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); #endif - local_irq_restore(flags); - cmd->scsi_done(cmd); - falcon_release_lock_if_possible( hostdata ); - return SCSI_ABORT_SUCCESS; - } else { -/* local_irq_restore(flags); */ - printk("scsi%d: abort of connected command failed!\n", HOSTNO); - return SCSI_ABORT_ERROR; - } - } + local_irq_restore(flags); + cmd->scsi_done(cmd); + falcon_release_lock_if_possible(hostdata); + return SCSI_ABORT_SUCCESS; + } else { +/* local_irq_restore(flags); */ + printk("scsi%d: abort of connected command failed!\n", HOSTNO); + return SCSI_ABORT_ERROR; + } + } #endif -/* - * Case 2 : If the command hasn't been issued yet, we simply remove it - * from the issue queue. - */ - for (prev = (Scsi_Cmnd **) &(hostdata->issue_queue), - tmp = (Scsi_Cmnd *) hostdata->issue_queue; - tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp) ) - if (cmd == tmp) { - REMOVE(5, *prev, tmp, NEXT(tmp)); - (*prev) = NEXT(tmp); - NEXT(tmp) = NULL; - tmp->result = DID_ABORT << 16; - local_irq_restore(flags); - ABRT_PRINTK("scsi%d: abort removed command from issue queue.\n", - HOSTNO); - /* Tagged queuing note: no tag to free here, hasn't been assigned - * yet... */ - tmp->scsi_done(tmp); - falcon_release_lock_if_possible( hostdata ); - return SCSI_ABORT_SUCCESS; + /* + * Case 2 : If the command hasn't been issued yet, we simply remove it + * from the issue queue. + */ + for (prev = (Scsi_Cmnd **)&(hostdata->issue_queue), + tmp = (Scsi_Cmnd *)hostdata->issue_queue; + tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp)) { + if (cmd == tmp) { + REMOVE(5, *prev, tmp, NEXT(tmp)); + (*prev) = NEXT(tmp); + SET_NEXT(tmp, NULL); + tmp->result = DID_ABORT << 16; + local_irq_restore(flags); + ABRT_PRINTK("scsi%d: abort removed command from issue queue.\n", + HOSTNO); + /* Tagged queuing note: no tag to free here, hasn't been assigned + * yet... */ + tmp->scsi_done(tmp); + falcon_release_lock_if_possible(hostdata); + return SCSI_ABORT_SUCCESS; + } } -/* - * Case 3 : If any commands are connected, we're going to fail the abort - * and let the high level SCSI driver retry at a later time or - * issue a reset. - * - * Timeouts, and therefore aborted commands, will be highly unlikely - * and handling them cleanly in this situation would make the common - * case of noresets less efficient, and would pollute our code. So, - * we fail. - */ + /* + * Case 3 : If any commands are connected, we're going to fail the abort + * and let the high level SCSI driver retry at a later time or + * issue a reset. + * + * Timeouts, and therefore aborted commands, will be highly unlikely + * and handling them cleanly in this situation would make the common + * case of noresets less efficient, and would pollute our code. So, + * we fail. + */ - if (hostdata->connected) { - local_irq_restore(flags); - ABRT_PRINTK("scsi%d: abort failed, command connected.\n", HOSTNO); - return SCSI_ABORT_SNOOZE; - } + if (hostdata->connected) { + local_irq_restore(flags); + ABRT_PRINTK("scsi%d: abort failed, command connected.\n", HOSTNO); + return SCSI_ABORT_SNOOZE; + } -/* - * Case 4: If the command is currently disconnected from the bus, and - * there are no connected commands, we reconnect the I_T_L or - * I_T_L_Q nexus associated with it, go into message out, and send - * an abort message. - * - * This case is especially ugly. In order to reestablish the nexus, we - * need to call NCR5380_select(). The easiest way to implement this - * function was to abort if the bus was busy, and let the interrupt - * handler triggered on the SEL for reselect take care of lost arbitrations - * where necessary, meaning interrupts need to be enabled. - * - * When interrupts are enabled, the queues may change - so we - * can't remove it from the disconnected queue before selecting it - * because that could cause a failure in hashing the nexus if that - * device reselected. - * - * Since the queues may change, we can't use the pointers from when we - * first locate it. - * - * So, we must first locate the command, and if NCR5380_select() - * succeeds, then issue the abort, relocate the command and remove - * it from the disconnected queue. - */ + /* + * Case 4: If the command is currently disconnected from the bus, and + * there are no connected commands, we reconnect the I_T_L or + * I_T_L_Q nexus associated with it, go into message out, and send + * an abort message. + * + * This case is especially ugly. In order to reestablish the nexus, we + * need to call NCR5380_select(). The easiest way to implement this + * function was to abort if the bus was busy, and let the interrupt + * handler triggered on the SEL for reselect take care of lost arbitrations + * where necessary, meaning interrupts need to be enabled. + * + * When interrupts are enabled, the queues may change - so we + * can't remove it from the disconnected queue before selecting it + * because that could cause a failure in hashing the nexus if that + * device reselected. + * + * Since the queues may change, we can't use the pointers from when we + * first locate it. + * + * So, we must first locate the command, and if NCR5380_select() + * succeeds, then issue the abort, relocate the command and remove + * it from the disconnected queue. + */ + + for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp; + tmp = NEXT(tmp)) { + if (cmd == tmp) { + local_irq_restore(flags); + ABRT_PRINTK("scsi%d: aborting disconnected command.\n", HOSTNO); - for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp; - tmp = NEXT(tmp)) - if (cmd == tmp) { - local_irq_restore(flags); - ABRT_PRINTK("scsi%d: aborting disconnected command.\n", HOSTNO); - - if (NCR5380_select (instance, cmd, (int) cmd->tag)) - return SCSI_ABORT_BUSY; - - ABRT_PRINTK("scsi%d: nexus reestablished.\n", HOSTNO); - - do_abort (instance); - - local_irq_save(flags); - for (prev = (Scsi_Cmnd **) &(hostdata->disconnected_queue), - tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; - tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp) ) - if (cmd == tmp) { - REMOVE(5, *prev, tmp, NEXT(tmp)); - *prev = NEXT(tmp); - NEXT(tmp) = NULL; - tmp->result = DID_ABORT << 16; - /* We must unlock the tag/LUN immediately here, since the - * target goes to BUS FREE and doesn't send us another - * message (COMMAND_COMPLETE or the like) - */ + if (NCR5380_select(instance, cmd, (int)cmd->tag)) + return SCSI_ABORT_BUSY; + + ABRT_PRINTK("scsi%d: nexus reestablished.\n", HOSTNO); + + do_abort(instance); + + local_irq_save(flags); + for (prev = (Scsi_Cmnd **)&(hostdata->disconnected_queue), + tmp = (Scsi_Cmnd *)hostdata->disconnected_queue; + tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp)) { + if (cmd == tmp) { + REMOVE(5, *prev, tmp, NEXT(tmp)); + *prev = NEXT(tmp); + SET_NEXT(tmp, NULL); + tmp->result = DID_ABORT << 16; + /* We must unlock the tag/LUN immediately here, since the + * target goes to BUS FREE and doesn't send us another + * message (COMMAND_COMPLETE or the like) + */ #ifdef SUPPORT_TAGS - cmd_free_tag( tmp ); + cmd_free_tag(tmp); #else - hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); + hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); #endif - local_irq_restore(flags); - tmp->scsi_done(tmp); - falcon_release_lock_if_possible( hostdata ); - return SCSI_ABORT_SUCCESS; + local_irq_restore(flags); + tmp->scsi_done(tmp); + falcon_release_lock_if_possible(hostdata); + return SCSI_ABORT_SUCCESS; + } + } } } -/* - * Case 5 : If we reached this point, the command was not found in any of - * the queues. - * - * We probably reached this point because of an unlikely race condition - * between the command completing successfully and the abortion code, - * so we won't panic, but we will notify the user in case something really - * broke. - */ + /* + * Case 5 : If we reached this point, the command was not found in any of + * the queues. + * + * We probably reached this point because of an unlikely race condition + * between the command completing successfully and the abortion code, + * so we won't panic, but we will notify the user in case something really + * broke. + */ - local_irq_restore(flags); - printk(KERN_INFO "scsi%d: warning : SCSI command probably completed successfully\n" - KERN_INFO " before abortion\n", HOSTNO); + local_irq_restore(flags); + printk(KERN_INFO "scsi%d: warning : SCSI command probably completed successfully\n" + KERN_INFO " before abortion\n", HOSTNO); -/* Maybe it is sufficient just to release the ST-DMA lock... (if - * possible at all) At least, we should check if the lock could be - * released after the abort, in case it is kept due to some bug. - */ - falcon_release_lock_if_possible( hostdata ); + /* Maybe it is sufficient just to release the ST-DMA lock... (if + * possible at all) At least, we should check if the lock could be + * released after the abort, in case it is kept due to some bug. + */ + falcon_release_lock_if_possible(hostdata); - return SCSI_ABORT_NOT_RUNNING; + return SCSI_ABORT_NOT_RUNNING; } -/* +/* * Function : int NCR5380_reset (Scsi_Cmnd *cmd) - * + * * Purpose : reset the SCSI bus. * * Returns : SCSI_RESET_WAKEUP * - */ + */ -static int NCR5380_bus_reset( Scsi_Cmnd *cmd) +static int NCR5380_bus_reset(Scsi_Cmnd *cmd) { - SETUP_HOSTDATA(cmd->device->host); - int i; - unsigned long flags; + SETUP_HOSTDATA(cmd->device->host); + int i; + unsigned long flags; #if 1 - Scsi_Cmnd *connected, *disconnected_queue; + Scsi_Cmnd *connected, *disconnected_queue; #endif - if (!IS_A_TT() && !falcon_got_lock) - printk(KERN_ERR "scsi%d: !!BINGO!! Falcon has no lock in NCR5380_reset\n", - H_NO(cmd) ); - - NCR5380_print_status (cmd->device->host); - - /* get in phase */ - NCR5380_write( TARGET_COMMAND_REG, - PHASE_SR_TO_TCR( NCR5380_read(STATUS_REG) )); - /* assert RST */ - NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST ); - udelay (40); - /* reset NCR registers */ - NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE ); - NCR5380_write( MODE_REG, MR_BASE ); - NCR5380_write( TARGET_COMMAND_REG, 0 ); - NCR5380_write( SELECT_ENABLE_REG, 0 ); - /* ++roman: reset interrupt condition! otherwise no interrupts don't get - * through anymore ... */ - (void)NCR5380_read( RESET_PARITY_INTERRUPT_REG ); - -#if 1 /* XXX Should now be done by midlevel code, but it's broken XXX */ - /* XXX see below XXX */ - - /* MSch: old-style reset: actually abort all command processing here */ - - /* After the reset, there are no more connected or disconnected commands - * and no busy units; to avoid problems with re-inserting the commands - * into the issue_queue (via scsi_done()), the aborted commands are - * remembered in local variables first. - */ - local_irq_save(flags); - connected = (Scsi_Cmnd *)hostdata->connected; - hostdata->connected = NULL; - disconnected_queue = (Scsi_Cmnd *)hostdata->disconnected_queue; - hostdata->disconnected_queue = NULL; + if (!IS_A_TT() && !falcon_got_lock) + printk(KERN_ERR "scsi%d: !!BINGO!! Falcon has no lock in NCR5380_reset\n", + H_NO(cmd)); + + NCR5380_print_status(cmd->device->host); + + /* get in phase */ + NCR5380_write(TARGET_COMMAND_REG, + PHASE_SR_TO_TCR(NCR5380_read(STATUS_REG))); + /* assert RST */ + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST); + udelay(40); + /* reset NCR registers */ + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + NCR5380_write(MODE_REG, MR_BASE); + NCR5380_write(TARGET_COMMAND_REG, 0); + NCR5380_write(SELECT_ENABLE_REG, 0); + /* ++roman: reset interrupt condition! otherwise no interrupts don't get + * through anymore ... */ + (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG); + +#if 1 /* XXX Should now be done by midlevel code, but it's broken XXX */ + /* XXX see below XXX */ + + /* MSch: old-style reset: actually abort all command processing here */ + + /* After the reset, there are no more connected or disconnected commands + * and no busy units; to avoid problems with re-inserting the commands + * into the issue_queue (via scsi_done()), the aborted commands are + * remembered in local variables first. + */ + local_irq_save(flags); + connected = (Scsi_Cmnd *)hostdata->connected; + hostdata->connected = NULL; + disconnected_queue = (Scsi_Cmnd *)hostdata->disconnected_queue; + hostdata->disconnected_queue = NULL; #ifdef SUPPORT_TAGS - free_all_tags(); + free_all_tags(); #endif - for( i = 0; i < 8; ++i ) - hostdata->busy[i] = 0; + for (i = 0; i < 8; ++i) + hostdata->busy[i] = 0; #ifdef REAL_DMA - hostdata->dma_len = 0; + hostdata->dma_len = 0; #endif - local_irq_restore(flags); - - /* In order to tell the mid-level code which commands were aborted, - * set the command status to DID_RESET and call scsi_done() !!! - * This ultimately aborts processing of these commands in the mid-level. - */ - - if ((cmd = connected)) { - ABRT_PRINTK("scsi%d: reset aborted a connected command\n", H_NO(cmd)); - cmd->result = (cmd->result & 0xffff) | (DID_RESET << 16); - cmd->scsi_done( cmd ); - } - - for (i = 0; (cmd = disconnected_queue); ++i) { - disconnected_queue = NEXT(cmd); - NEXT(cmd) = NULL; - cmd->result = (cmd->result & 0xffff) | (DID_RESET << 16); - cmd->scsi_done( cmd ); - } - if (i > 0) - ABRT_PRINTK("scsi: reset aborted %d disconnected command(s)\n", i); - -/* The Falcon lock should be released after a reset... - */ -/* ++guenther: moved to atari_scsi_reset(), to prevent a race between - * unlocking and enabling dma interrupt. - */ -/* falcon_release_lock_if_possible( hostdata );*/ + local_irq_restore(flags); + + /* In order to tell the mid-level code which commands were aborted, + * set the command status to DID_RESET and call scsi_done() !!! + * This ultimately aborts processing of these commands in the mid-level. + */ + + if ((cmd = connected)) { + ABRT_PRINTK("scsi%d: reset aborted a connected command\n", H_NO(cmd)); + cmd->result = (cmd->result & 0xffff) | (DID_RESET << 16); + cmd->scsi_done(cmd); + } - /* since all commands have been explicitly terminated, we need to tell - * the midlevel code that the reset was SUCCESSFUL, and there is no - * need to 'wake up' the commands by a request_sense - */ - return SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET; + for (i = 0; (cmd = disconnected_queue); ++i) { + disconnected_queue = NEXT(cmd); + SET_NEXT(cmd, NULL); + cmd->result = (cmd->result & 0xffff) | (DID_RESET << 16); + cmd->scsi_done(cmd); + } + if (i > 0) + ABRT_PRINTK("scsi: reset aborted %d disconnected command(s)\n", i); + + /* The Falcon lock should be released after a reset... + */ + /* ++guenther: moved to atari_scsi_reset(), to prevent a race between + * unlocking and enabling dma interrupt. + */ +/* falcon_release_lock_if_possible( hostdata );*/ + + /* since all commands have been explicitly terminated, we need to tell + * the midlevel code that the reset was SUCCESSFUL, and there is no + * need to 'wake up' the commands by a request_sense + */ + return SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET; #else /* 1 */ - /* MSch: new-style reset handling: let the mid-level do what it can */ - - /* ++guenther: MID-LEVEL IS STILL BROKEN. - * Mid-level is supposed to requeue all commands that were active on the - * various low-level queues. In fact it does this, but that's not enough - * because all these commands are subject to timeout. And if a timeout - * happens for any removed command, *_abort() is called but all queues - * are now empty. Abort then gives up the falcon lock, which is fatal, - * since the mid-level will queue more commands and must have the lock - * (it's all happening inside timer interrupt handler!!). - * Even worse, abort will return NOT_RUNNING for all those commands not - * on any queue, so they won't be retried ... - * - * Conclusion: either scsi.c disables timeout for all resetted commands - * immediately, or we lose! As of linux-2.0.20 it doesn't. - */ - - /* After the reset, there are no more connected or disconnected commands - * and no busy units; so clear the low-level status here to avoid - * conflicts when the mid-level code tries to wake up the affected - * commands! - */ - - if (hostdata->issue_queue) - ABRT_PRINTK("scsi%d: reset aborted issued command(s)\n", H_NO(cmd)); - if (hostdata->connected) - ABRT_PRINTK("scsi%d: reset aborted a connected command\n", H_NO(cmd)); - if (hostdata->disconnected_queue) - ABRT_PRINTK("scsi%d: reset aborted disconnected command(s)\n", H_NO(cmd)); - - local_irq_save(flags); - hostdata->issue_queue = NULL; - hostdata->connected = NULL; - hostdata->disconnected_queue = NULL; + /* MSch: new-style reset handling: let the mid-level do what it can */ + + /* ++guenther: MID-LEVEL IS STILL BROKEN. + * Mid-level is supposed to requeue all commands that were active on the + * various low-level queues. In fact it does this, but that's not enough + * because all these commands are subject to timeout. And if a timeout + * happens for any removed command, *_abort() is called but all queues + * are now empty. Abort then gives up the falcon lock, which is fatal, + * since the mid-level will queue more commands and must have the lock + * (it's all happening inside timer interrupt handler!!). + * Even worse, abort will return NOT_RUNNING for all those commands not + * on any queue, so they won't be retried ... + * + * Conclusion: either scsi.c disables timeout for all resetted commands + * immediately, or we lose! As of linux-2.0.20 it doesn't. + */ + + /* After the reset, there are no more connected or disconnected commands + * and no busy units; so clear the low-level status here to avoid + * conflicts when the mid-level code tries to wake up the affected + * commands! + */ + + if (hostdata->issue_queue) + ABRT_PRINTK("scsi%d: reset aborted issued command(s)\n", H_NO(cmd)); + if (hostdata->connected) + ABRT_PRINTK("scsi%d: reset aborted a connected command\n", H_NO(cmd)); + if (hostdata->disconnected_queue) + ABRT_PRINTK("scsi%d: reset aborted disconnected command(s)\n", H_NO(cmd)); + + local_irq_save(flags); + hostdata->issue_queue = NULL; + hostdata->connected = NULL; + hostdata->disconnected_queue = NULL; #ifdef SUPPORT_TAGS - free_all_tags(); + free_all_tags(); #endif - for( i = 0; i < 8; ++i ) - hostdata->busy[i] = 0; + for (i = 0; i < 8; ++i) + hostdata->busy[i] = 0; #ifdef REAL_DMA - hostdata->dma_len = 0; + hostdata->dma_len = 0; #endif - local_irq_restore(flags); + local_irq_restore(flags); - /* we did no complete reset of all commands, so a wakeup is required */ - return SCSI_RESET_WAKEUP | SCSI_RESET_BUS_RESET; + /* we did no complete reset of all commands, so a wakeup is required */ + return SCSI_RESET_WAKEUP | SCSI_RESET_BUS_RESET; #endif /* 1 */ } - -/* Local Variables: */ -/* tab-width: 8 */ -/* End: */ diff --git a/drivers/scsi/atari_scsi.c b/drivers/scsi/atari_scsi.c index 642de7b2b7a..6f8403b82ba 100644 --- a/drivers/scsi/atari_scsi.c +++ b/drivers/scsi/atari_scsi.c @@ -69,9 +69,9 @@ #define NDEBUG (0) -#define NDEBUG_ABORT 0x800000 -#define NDEBUG_TAGS 0x1000000 -#define NDEBUG_MERGING 0x2000000 +#define NDEBUG_ABORT 0x00100000 +#define NDEBUG_TAGS 0x00200000 +#define NDEBUG_MERGING 0x00400000 #define AUTOSENSE /* For the Atari version, use only polled IO or REAL_DMA */ @@ -186,38 +186,37 @@ static inline void DISABLE_IRQ(void) /***************************** Prototypes *****************************/ #ifdef REAL_DMA -static int scsi_dma_is_ignored_buserr( unsigned char dma_stat ); -static void atari_scsi_fetch_restbytes( void ); -static long atari_scsi_dma_residual( struct Scsi_Host *instance ); -static int falcon_classify_cmd( Scsi_Cmnd *cmd ); -static unsigned long atari_dma_xfer_len( unsigned long wanted_len, - Scsi_Cmnd *cmd, int write_flag ); +static int scsi_dma_is_ignored_buserr(unsigned char dma_stat); +static void atari_scsi_fetch_restbytes(void); +static long atari_scsi_dma_residual(struct Scsi_Host *instance); +static int falcon_classify_cmd(Scsi_Cmnd *cmd); +static unsigned long atari_dma_xfer_len(unsigned long wanted_len, + Scsi_Cmnd *cmd, int write_flag); #endif -static irqreturn_t scsi_tt_intr( int irq, void *dummy); -static irqreturn_t scsi_falcon_intr( int irq, void *dummy); -static void falcon_release_lock_if_possible( struct NCR5380_hostdata * - hostdata ); -static void falcon_get_lock( void ); +static irqreturn_t scsi_tt_intr(int irq, void *dummy); +static irqreturn_t scsi_falcon_intr(int irq, void *dummy); +static void falcon_release_lock_if_possible(struct NCR5380_hostdata *hostdata); +static void falcon_get_lock(void); #ifdef CONFIG_ATARI_SCSI_RESET_BOOT -static void atari_scsi_reset_boot( void ); +static void atari_scsi_reset_boot(void); #endif -static unsigned char atari_scsi_tt_reg_read( unsigned char reg ); -static void atari_scsi_tt_reg_write( unsigned char reg, unsigned char value); -static unsigned char atari_scsi_falcon_reg_read( unsigned char reg ); -static void atari_scsi_falcon_reg_write( unsigned char reg, unsigned char value ); +static unsigned char atari_scsi_tt_reg_read(unsigned char reg); +static void atari_scsi_tt_reg_write(unsigned char reg, unsigned char value); +static unsigned char atari_scsi_falcon_reg_read(unsigned char reg); +static void atari_scsi_falcon_reg_write(unsigned char reg, unsigned char value); /************************* End of Prototypes **************************/ -static struct Scsi_Host *atari_scsi_host = NULL; -static unsigned char (*atari_scsi_reg_read)( unsigned char reg ); -static void (*atari_scsi_reg_write)( unsigned char reg, unsigned char value ); +static struct Scsi_Host *atari_scsi_host; +static unsigned char (*atari_scsi_reg_read)(unsigned char reg); +static void (*atari_scsi_reg_write)(unsigned char reg, unsigned char value); #ifdef REAL_DMA static unsigned long atari_dma_residual, atari_dma_startaddr; static short atari_dma_active; /* pointer to the dribble buffer */ -static char *atari_dma_buffer = NULL; +static char *atari_dma_buffer; /* precalculated physical address of the dribble buffer */ static unsigned long atari_dma_phys_buffer; /* != 0 tells the Falcon int handler to copy data from the dribble buffer */ @@ -233,7 +232,7 @@ static char *atari_dma_orig_addr; static unsigned long atari_dma_stram_mask; #define STRAM_ADDR(a) (((a) & atari_dma_stram_mask) == 0) /* number of bytes to cut from a transfer to handle NCR overruns */ -static int atari_read_overruns = 0; +static int atari_read_overruns; #endif static int setup_can_queue = -1; @@ -256,10 +255,10 @@ module_param(setup_hostid, int, 0); #if defined(REAL_DMA) -static int scsi_dma_is_ignored_buserr( unsigned char dma_stat ) +static int scsi_dma_is_ignored_buserr(unsigned char dma_stat) { int i; - unsigned long addr = SCSI_DMA_READ_P( dma_addr ), end_addr; + unsigned long addr = SCSI_DMA_READ_P(dma_addr), end_addr; if (dma_stat & 0x01) { @@ -267,15 +266,14 @@ static int scsi_dma_is_ignored_buserr( unsigned char dma_stat ) * physical memory chunk (DMA prefetch!), but that doesn't hurt. * Check for this case: */ - - for( i = 0; i < m68k_num_memory; ++i ) { - end_addr = m68k_memory[i].addr + - m68k_memory[i].size; + + for (i = 0; i < m68k_num_memory; ++i) { + end_addr = m68k_memory[i].addr + m68k_memory[i].size; if (end_addr <= addr && addr <= end_addr + 4) - return( 1 ); + return 1; } } - return( 0 ); + return 0; } @@ -284,28 +282,27 @@ static int scsi_dma_is_ignored_buserr( unsigned char dma_stat ) * end-of-DMA, both SCSI ints are triggered simultaneously, so the NCR int has * to clear the DMA int pending bit before it allows other level 6 interrupts. */ -static void scsi_dma_buserr (int irq, void *dummy) +static void scsi_dma_buserr(int irq, void *dummy) { - unsigned char dma_stat = tt_scsi_dma.dma_ctrl; + unsigned char dma_stat = tt_scsi_dma.dma_ctrl; /* Don't do anything if a NCR interrupt is pending. Probably it's just * masked... */ - if (atari_irq_pending( IRQ_TT_MFP_SCSI )) + if (atari_irq_pending(IRQ_TT_MFP_SCSI)) return; - + printk("Bad SCSI DMA interrupt! dma_addr=0x%08lx dma_stat=%02x dma_cnt=%08lx\n", SCSI_DMA_READ_P(dma_addr), dma_stat, SCSI_DMA_READ_P(dma_cnt)); if (dma_stat & 0x80) { - if (!scsi_dma_is_ignored_buserr( dma_stat )) - printk( "SCSI DMA bus error -- bad DMA programming!\n" ); - } - else { + if (!scsi_dma_is_ignored_buserr(dma_stat)) + printk("SCSI DMA bus error -- bad DMA programming!\n"); + } else { /* Under normal circumstances we never should get to this point, * since both interrupts are triggered simultaneously and the 5380 * int has higher priority. When this irq is handled, that DMA * interrupt is cleared. So a warning message is printed here. */ - printk( "SCSI DMA intr ?? -- this shouldn't happen!\n" ); + printk("SCSI DMA intr ?? -- this shouldn't happen!\n"); } } #endif @@ -313,7 +310,7 @@ static void scsi_dma_buserr (int irq, void *dummy) #endif -static irqreturn_t scsi_tt_intr (int irq, void *dummy) +static irqreturn_t scsi_tt_intr(int irq, void *dummy) { #ifdef REAL_DMA int dma_stat; @@ -327,7 +324,7 @@ static irqreturn_t scsi_tt_intr (int irq, void *dummy) * is that a bus error occurred... */ if (dma_stat & 0x80) { - if (!scsi_dma_is_ignored_buserr( dma_stat )) { + if (!scsi_dma_is_ignored_buserr(dma_stat)) { printk(KERN_ERR "SCSI DMA caused bus error near 0x%08lx\n", SCSI_DMA_READ_P(dma_addr)); printk(KERN_CRIT "SCSI DMA bus error -- bad DMA programming!"); @@ -344,8 +341,7 @@ static irqreturn_t scsi_tt_intr (int irq, void *dummy) * data reg! */ if ((dma_stat & 0x02) && !(dma_stat & 0x40)) { - atari_dma_residual = HOSTDATA_DMALEN - (SCSI_DMA_READ_P( dma_addr ) - - atari_dma_startaddr); + atari_dma_residual = HOSTDATA_DMALEN - (SCSI_DMA_READ_P(dma_addr) - atari_dma_startaddr); DMA_PRINTK("SCSI DMA: There are %ld residual bytes.\n", atari_dma_residual); @@ -353,28 +349,30 @@ static irqreturn_t scsi_tt_intr (int irq, void *dummy) if ((signed int)atari_dma_residual < 0) atari_dma_residual = 0; if ((dma_stat & 1) == 0) { - /* After read operations, we maybe have to - transport some rest bytes */ + /* + * After read operations, we maybe have to + * transport some rest bytes + */ atari_scsi_fetch_restbytes(); - } - else { - /* There seems to be a nasty bug in some SCSI-DMA/NCR - combinations: If a target disconnects while a write - operation is going on, the address register of the - DMA may be a few bytes farer than it actually read. - This is probably due to DMA prefetching and a delay - between DMA and NCR. Experiments showed that the - dma_addr is 9 bytes to high, but this could vary. - The problem is, that the residual is thus calculated - wrong and the next transfer will start behind where - it should. So we round up the residual to the next - multiple of a sector size, if it isn't already a - multiple and the originally expected transfer size - was. The latter condition is there to ensure that - the correction is taken only for "real" data - transfers and not for, e.g., the parameters of some - other command. These shouldn't disconnect anyway. - */ + } else { + /* + * There seems to be a nasty bug in some SCSI-DMA/NCR + * combinations: If a target disconnects while a write + * operation is going on, the address register of the + * DMA may be a few bytes farer than it actually read. + * This is probably due to DMA prefetching and a delay + * between DMA and NCR. Experiments showed that the + * dma_addr is 9 bytes to high, but this could vary. + * The problem is, that the residual is thus calculated + * wrong and the next transfer will start behind where + * it should. So we round up the residual to the next + * multiple of a sector size, if it isn't already a + * multiple and the originally expected transfer size + * was. The latter condition is there to ensure that + * the correction is taken only for "real" data + * transfers and not for, e.g., the parameters of some + * other command. These shouldn't disconnect anyway. + */ if (atari_dma_residual & 0x1ff) { DMA_PRINTK("SCSI DMA: DMA bug corrected, " "difference %ld bytes\n", @@ -394,18 +392,18 @@ static irqreturn_t scsi_tt_intr (int irq, void *dummy) } #endif /* REAL_DMA */ - - NCR5380_intr (0, 0, 0); + + NCR5380_intr(0, 0); #if 0 /* To be sure the int is not masked */ - atari_enable_irq( IRQ_TT_MFP_SCSI ); + atari_enable_irq(IRQ_TT_MFP_SCSI); #endif return IRQ_HANDLED; } -static irqreturn_t scsi_falcon_intr (int irq, void *dummy) +static irqreturn_t scsi_falcon_intr(int irq, void *dummy) { #ifdef REAL_DMA int dma_stat; @@ -430,7 +428,7 @@ static irqreturn_t scsi_falcon_intr (int irq, void *dummy) * bytes are stuck in the ST-DMA fifo (there's no way to reach them!) */ if (atari_dma_active && (dma_stat & 0x02)) { - unsigned long transferred; + unsigned long transferred; transferred = SCSI_DMA_GETADR() - atari_dma_startaddr; /* The ST-DMA address is incremented in 2-byte steps, but the @@ -445,8 +443,7 @@ static irqreturn_t scsi_falcon_intr (int irq, void *dummy) atari_dma_residual = HOSTDATA_DMALEN - transferred; DMA_PRINTK("SCSI DMA: There are %ld residual bytes.\n", atari_dma_residual); - } - else + } else atari_dma_residual = 0; atari_dma_active = 0; @@ -461,13 +458,13 @@ static irqreturn_t scsi_falcon_intr (int irq, void *dummy) #endif /* REAL_DMA */ - NCR5380_intr (0, 0, 0); + NCR5380_intr(0, 0); return IRQ_HANDLED; } #ifdef REAL_DMA -static void atari_scsi_fetch_restbytes( void ) +static void atari_scsi_fetch_restbytes(void) { int nr; char *src, *dst; @@ -505,19 +502,17 @@ static int falcon_dont_release = 0; * again (but others waiting longer more probably will win). */ -static void -falcon_release_lock_if_possible( struct NCR5380_hostdata * hostdata ) +static void falcon_release_lock_if_possible(struct NCR5380_hostdata *hostdata) { unsigned long flags; - - if (IS_A_TT()) return; - + + if (IS_A_TT()) + return; + local_irq_save(flags); - if (falcon_got_lock && - !hostdata->disconnected_queue && - !hostdata->issue_queue && - !hostdata->connected) { + if (falcon_got_lock && !hostdata->disconnected_queue && + !hostdata->issue_queue && !hostdata->connected) { if (falcon_dont_release) { #if 0 @@ -528,7 +523,7 @@ falcon_release_lock_if_possible( struct NCR5380_hostdata * hostdata ) } falcon_got_lock = 0; stdma_release(); - wake_up( &falcon_fairness_wait ); + wake_up(&falcon_fairness_wait); } local_irq_restore(flags); @@ -549,31 +544,31 @@ falcon_release_lock_if_possible( struct NCR5380_hostdata * hostdata ) * Complicated, complicated.... Sigh... */ -static void falcon_get_lock( void ) +static void falcon_get_lock(void) { unsigned long flags; - if (IS_A_TT()) return; + if (IS_A_TT()) + return; local_irq_save(flags); - while( !in_interrupt() && falcon_got_lock && stdma_others_waiting() ) - sleep_on( &falcon_fairness_wait ); + while (!in_irq() && falcon_got_lock && stdma_others_waiting()) + sleep_on(&falcon_fairness_wait); while (!falcon_got_lock) { - if (in_interrupt()) - panic( "Falcon SCSI hasn't ST-DMA lock in interrupt" ); + if (in_irq()) + panic("Falcon SCSI hasn't ST-DMA lock in interrupt"); if (!falcon_trying_lock) { falcon_trying_lock = 1; stdma_lock(scsi_falcon_intr, NULL); falcon_got_lock = 1; falcon_trying_lock = 0; - wake_up( &falcon_try_wait ); - } - else { - sleep_on( &falcon_try_wait ); + wake_up(&falcon_try_wait); + } else { + sleep_on(&falcon_try_wait); } - } + } local_irq_restore(flags); if (!falcon_got_lock) @@ -587,18 +582,18 @@ static void falcon_get_lock( void ) */ #if 0 -int atari_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) +int atari_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) { /* falcon_get_lock(); * ++guenther: moved to NCR5380_queue_command() to prevent * race condition, see there for an explanation. */ - return( NCR5380_queue_command( cmd, done ) ); + return NCR5380_queue_command(cmd, done); } #endif -int atari_scsi_detect (struct scsi_host_template *host) +int atari_scsi_detect(struct scsi_host_template *host) { static int called = 0; struct Scsi_Host *instance; @@ -606,7 +601,7 @@ int atari_scsi_detect (struct scsi_host_template *host) if (!MACH_IS_ATARI || (!ATARIHW_PRESENT(ST_SCSI) && !ATARIHW_PRESENT(TT_SCSI)) || called) - return( 0 ); + return 0; host->proc_name = "Atari"; @@ -655,32 +650,33 @@ int atari_scsi_detect (struct scsi_host_template *host) !ATARIHW_PRESENT(EXTD_DMA) && m68k_num_memory > 1) { atari_dma_buffer = atari_stram_alloc(STRAM_BUFFER_SIZE, "SCSI"); if (!atari_dma_buffer) { - printk( KERN_ERR "atari_scsi_detect: can't allocate ST-RAM " - "double buffer\n" ); - return( 0 ); + printk(KERN_ERR "atari_scsi_detect: can't allocate ST-RAM " + "double buffer\n"); + return 0; } - atari_dma_phys_buffer = virt_to_phys( atari_dma_buffer ); + atari_dma_phys_buffer = virt_to_phys(atari_dma_buffer); atari_dma_orig_addr = 0; } #endif - instance = scsi_register (host, sizeof (struct NCR5380_hostdata)); - if(instance == NULL) - { + instance = scsi_register(host, sizeof(struct NCR5380_hostdata)); + if (instance == NULL) { atari_stram_free(atari_dma_buffer); atari_dma_buffer = 0; return 0; } atari_scsi_host = instance; - /* Set irq to 0, to avoid that the mid-level code disables our interrupt - * during queue_command calls. This is completely unnecessary, and even - * worse causes bad problems on the Falcon, where the int is shared with - * IDE and floppy! */ + /* + * Set irq to 0, to avoid that the mid-level code disables our interrupt + * during queue_command calls. This is completely unnecessary, and even + * worse causes bad problems on the Falcon, where the int is shared with + * IDE and floppy! + */ instance->irq = 0; #ifdef CONFIG_ATARI_SCSI_RESET_BOOT atari_scsi_reset_boot(); #endif - NCR5380_init (instance, 0); + NCR5380_init(instance, 0); if (IS_A_TT()) { @@ -727,11 +723,10 @@ int atari_scsi_detect (struct scsi_host_template *host) * the rest data bug is fixed, this can be lowered to 1. */ atari_read_overruns = 4; - } + } #endif /*REAL_DMA*/ - } - else { /* ! IS_A_TT */ - + } else { /* ! IS_A_TT */ + /* Nothing to do for the interrupt: the ST-DMA is initialized * already by atari_init_INTS() */ @@ -756,23 +751,21 @@ int atari_scsi_detect (struct scsi_host_template *host) setup_use_tagged_queuing ? "yes" : "no", #endif instance->hostt->this_id ); - NCR5380_print_options (instance); - printk ("\n"); + NCR5380_print_options(instance); + printk("\n"); called = 1; - return( 1 ); + return 1; } -#ifdef MODULE -int atari_scsi_release (struct Scsi_Host *sh) +int atari_scsi_release(struct Scsi_Host *sh) { if (IS_A_TT()) free_irq(IRQ_TT_MFP_SCSI, scsi_tt_intr); if (atari_dma_buffer) - atari_stram_free (atari_dma_buffer); + atari_stram_free(atari_dma_buffer); return 1; } -#endif void __init atari_scsi_setup(char *str, int *ints) { @@ -781,9 +774,9 @@ void __init atari_scsi_setup(char *str, int *ints) * Defaults depend on TT or Falcon, hostid determined at run time. * Negative values mean don't change. */ - + if (ints[0] < 1) { - printk( "atari_scsi_setup: no arguments!\n" ); + printk("atari_scsi_setup: no arguments!\n"); return; } @@ -809,7 +802,7 @@ void __init atari_scsi_setup(char *str, int *ints) if (ints[4] >= 0 && ints[4] <= 7) setup_hostid = ints[4]; else if (ints[4] > 7) - printk( "atari_scsi_setup: invalid host ID %d !\n", ints[4] ); + printk("atari_scsi_setup: invalid host ID %d !\n", ints[4]); } #ifdef SUPPORT_TAGS if (ints[0] >= 5) { @@ -821,7 +814,7 @@ void __init atari_scsi_setup(char *str, int *ints) int atari_scsi_bus_reset(Scsi_Cmnd *cmd) { - int rv; + int rv; struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *)cmd->device->host->hostdata; @@ -831,13 +824,12 @@ int atari_scsi_bus_reset(Scsi_Cmnd *cmd) */ /* And abort a maybe active DMA transfer */ if (IS_A_TT()) { - atari_turnoff_irq( IRQ_TT_MFP_SCSI ); + atari_turnoff_irq(IRQ_TT_MFP_SCSI); #ifdef REAL_DMA tt_scsi_dma.dma_ctrl = 0; #endif /* REAL_DMA */ - } - else { - atari_turnoff_irq( IRQ_MFP_FSCSI ); + } else { + atari_turnoff_irq(IRQ_MFP_FSCSI); #ifdef REAL_DMA st_dma.dma_mode_status = 0x90; atari_dma_active = 0; @@ -849,52 +841,51 @@ int atari_scsi_bus_reset(Scsi_Cmnd *cmd) /* Re-enable ints */ if (IS_A_TT()) { - atari_turnon_irq( IRQ_TT_MFP_SCSI ); - } - else { - atari_turnon_irq( IRQ_MFP_FSCSI ); + atari_turnon_irq(IRQ_TT_MFP_SCSI); + } else { + atari_turnon_irq(IRQ_MFP_FSCSI); } if ((rv & SCSI_RESET_ACTION) == SCSI_RESET_SUCCESS) falcon_release_lock_if_possible(hostdata); - return( rv ); + return rv; } - + #ifdef CONFIG_ATARI_SCSI_RESET_BOOT static void __init atari_scsi_reset_boot(void) { unsigned long end; - + /* * Do a SCSI reset to clean up the bus during initialization. No messing * with the queues, interrupts, or locks necessary here. */ - printk( "Atari SCSI: resetting the SCSI bus..." ); + printk("Atari SCSI: resetting the SCSI bus..."); /* get in phase */ - NCR5380_write( TARGET_COMMAND_REG, - PHASE_SR_TO_TCR( NCR5380_read(STATUS_REG) )); + NCR5380_write(TARGET_COMMAND_REG, + PHASE_SR_TO_TCR(NCR5380_read(STATUS_REG))); /* assert RST */ - NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST ); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST); /* The min. reset hold time is 25us, so 40us should be enough */ - udelay( 50 ); + udelay(50); /* reset RST and interrupt */ - NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE ); - NCR5380_read( RESET_PARITY_INTERRUPT_REG ); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + NCR5380_read(RESET_PARITY_INTERRUPT_REG); end = jiffies + AFTER_RESET_DELAY; while (time_before(jiffies, end)) barrier(); - printk( " done\n" ); + printk(" done\n"); } #endif -const char * atari_scsi_info (struct Scsi_Host *host) +const char *atari_scsi_info(struct Scsi_Host *host) { /* atari_scsi_detect() is verbose enough... */ static const char string[] = "Atari native SCSI"; @@ -904,10 +895,10 @@ const char * atari_scsi_info (struct Scsi_Host *host) #if defined(REAL_DMA) -unsigned long atari_scsi_dma_setup( struct Scsi_Host *instance, void *data, - unsigned long count, int dir ) +unsigned long atari_scsi_dma_setup(struct Scsi_Host *instance, void *data, + unsigned long count, int dir) { - unsigned long addr = virt_to_phys( data ); + unsigned long addr = virt_to_phys(data); DMA_PRINTK("scsi%d: setting up dma, data = %p, phys = %lx, count = %ld, " "dir = %d\n", instance->host_no, data, addr, count, dir); @@ -919,38 +910,37 @@ unsigned long atari_scsi_dma_setup( struct Scsi_Host *instance, void *data, * wanted address. */ if (dir) - memcpy( atari_dma_buffer, data, count ); + memcpy(atari_dma_buffer, data, count); else atari_dma_orig_addr = data; addr = atari_dma_phys_buffer; } - + atari_dma_startaddr = addr; /* Needed for calculating residual later. */ - + /* Cache cleanup stuff: On writes, push any dirty cache out before sending * it to the peripheral. (Must be done before DMA setup, since at least * the ST-DMA begins to fill internal buffers right after setup. For * reads, invalidate any cache, may be altered after DMA without CPU * knowledge. - * + * * ++roman: For the Medusa, there's no need at all for that cache stuff, * because the hardware does bus snooping (fine!). */ - dma_cache_maintenance( addr, count, dir ); + dma_cache_maintenance(addr, count, dir); if (count == 0) printk(KERN_NOTICE "SCSI warning: DMA programmed for 0 bytes !\n"); if (IS_A_TT()) { tt_scsi_dma.dma_ctrl = dir; - SCSI_DMA_WRITE_P( dma_addr, addr ); - SCSI_DMA_WRITE_P( dma_cnt, count ); + SCSI_DMA_WRITE_P(dma_addr, addr); + SCSI_DMA_WRITE_P(dma_cnt, count); tt_scsi_dma.dma_ctrl = dir | 2; - } - else { /* ! IS_A_TT */ - + } else { /* ! IS_A_TT */ + /* set address */ - SCSI_DMA_SETADR( addr ); + SCSI_DMA_SETADR(addr); /* toggle direction bit to clear FIFO and set DMA direction */ dir <<= 8; @@ -968,13 +958,13 @@ unsigned long atari_scsi_dma_setup( struct Scsi_Host *instance, void *data, atari_dma_active = 1; } - return( count ); + return count; } -static long atari_scsi_dma_residual( struct Scsi_Host *instance ) +static long atari_scsi_dma_residual(struct Scsi_Host *instance) { - return( atari_dma_residual ); + return atari_dma_residual; } @@ -982,13 +972,13 @@ static long atari_scsi_dma_residual( struct Scsi_Host *instance ) #define CMD_SURELY_BYTE_MODE 1 #define CMD_MODE_UNKNOWN 2 -static int falcon_classify_cmd( Scsi_Cmnd *cmd ) +static int falcon_classify_cmd(Scsi_Cmnd *cmd) { unsigned char opcode = cmd->cmnd[0]; - + if (opcode == READ_DEFECT_DATA || opcode == READ_LONG || - opcode == READ_BUFFER) - return( CMD_SURELY_BYTE_MODE ); + opcode == READ_BUFFER) + return CMD_SURELY_BYTE_MODE; else if (opcode == READ_6 || opcode == READ_10 || opcode == 0xa8 /* READ_12 */ || opcode == READ_REVERSE || opcode == RECOVER_BUFFERED_DATA) { @@ -996,12 +986,11 @@ static int falcon_classify_cmd( Scsi_Cmnd *cmd ) * needed here: The transfer is block-mode only if the 'fixed' bit is * set! */ if (cmd->device->type == TYPE_TAPE && !(cmd->cmnd[1] & 1)) - return( CMD_SURELY_BYTE_MODE ); + return CMD_SURELY_BYTE_MODE; else - return( CMD_SURELY_BLOCK_MODE ); - } - else - return( CMD_MODE_UNKNOWN ); + return CMD_SURELY_BLOCK_MODE; + } else + return CMD_MODE_UNKNOWN; } @@ -1014,19 +1003,18 @@ static int falcon_classify_cmd( Scsi_Cmnd *cmd ) * the overrun problem, so this question is academic :-) */ -static unsigned long atari_dma_xfer_len( unsigned long wanted_len, - Scsi_Cmnd *cmd, - int write_flag ) +static unsigned long atari_dma_xfer_len(unsigned long wanted_len, + Scsi_Cmnd *cmd, int write_flag) { unsigned long possible_len, limit; #ifndef CONFIG_TT_DMA_EMUL if (MACH_IS_HADES) /* Hades has no SCSI DMA at all :-( Always force use of PIO */ - return( 0 ); -#endif + return 0; +#endif if (IS_A_TT()) /* TT SCSI DMA can transfer arbitrary #bytes */ - return( wanted_len ); + return wanted_len; /* ST DMA chip is stupid -- only multiples of 512 bytes! (and max. * 255*512 bytes, but this should be enough) @@ -1062,8 +1050,7 @@ static unsigned long atari_dma_xfer_len( unsigned long wanted_len, * this). */ possible_len = wanted_len; - } - else { + } else { /* Read operations: if the wanted transfer length is not a multiple of * 512, we cannot use DMA, since the ST-DMA cannot split transfers * (no interrupt on DMA finished!) @@ -1073,15 +1060,15 @@ static unsigned long atari_dma_xfer_len( unsigned long wanted_len, else { /* Now classify the command (see above) and decide whether it is * allowed to do DMA at all */ - switch( falcon_classify_cmd( cmd )) { - case CMD_SURELY_BLOCK_MODE: + switch (falcon_classify_cmd(cmd)) { + case CMD_SURELY_BLOCK_MODE: possible_len = wanted_len; break; - case CMD_SURELY_BYTE_MODE: + case CMD_SURELY_BYTE_MODE: possible_len = 0; /* DMA prohibited */ break; - case CMD_MODE_UNKNOWN: - default: + case CMD_MODE_UNKNOWN: + default: /* For unknown commands assume block transfers if the transfer * size/allocation length is >= 1024 */ possible_len = (wanted_len < 1024) ? 0 : wanted_len; @@ -1089,9 +1076,9 @@ static unsigned long atari_dma_xfer_len( unsigned long wanted_len, } } } - + /* Last step: apply the hard limit on DMA transfers */ - limit = (atari_dma_buffer && !STRAM_ADDR( virt_to_phys(cmd->SCp.ptr) )) ? + limit = (atari_dma_buffer && !STRAM_ADDR(virt_to_phys(cmd->SCp.ptr))) ? STRAM_BUFFER_SIZE : 255*512; if (possible_len > limit) possible_len = limit; @@ -1100,7 +1087,7 @@ static unsigned long atari_dma_xfer_len( unsigned long wanted_len, DMA_PRINTK("Sorry, must cut DMA transfer size to %ld bytes " "instead of %ld\n", possible_len, wanted_len); - return( possible_len ); + return possible_len; } @@ -1114,23 +1101,23 @@ static unsigned long atari_dma_xfer_len( unsigned long wanted_len, * NCR5380_write call these functions via function pointers. */ -static unsigned char atari_scsi_tt_reg_read( unsigned char reg ) +static unsigned char atari_scsi_tt_reg_read(unsigned char reg) { - return( tt_scsi_regp[reg * 2] ); + return tt_scsi_regp[reg * 2]; } -static void atari_scsi_tt_reg_write( unsigned char reg, unsigned char value ) +static void atari_scsi_tt_reg_write(unsigned char reg, unsigned char value) { tt_scsi_regp[reg * 2] = value; } -static unsigned char atari_scsi_falcon_reg_read( unsigned char reg ) +static unsigned char atari_scsi_falcon_reg_read(unsigned char reg) { dma_wd.dma_mode_status= (u_short)(0x88 + reg); - return( (u_char)dma_wd.fdc_acces_seccount ); + return (u_char)dma_wd.fdc_acces_seccount; } -static void atari_scsi_falcon_reg_write( unsigned char reg, unsigned char value ) +static void atari_scsi_falcon_reg_write(unsigned char reg, unsigned char value) { dma_wd.dma_mode_status = (u_short)(0x88 + reg); dma_wd.fdc_acces_seccount = (u_short)value; diff --git a/drivers/scsi/atari_scsi.h b/drivers/scsi/atari_scsi.h index f917bdd09b4..efadb8d567c 100644 --- a/drivers/scsi/atari_scsi.h +++ b/drivers/scsi/atari_scsi.h @@ -21,11 +21,7 @@ int atari_scsi_detect (struct scsi_host_template *); const char *atari_scsi_info (struct Scsi_Host *); int atari_scsi_reset (Scsi_Cmnd *, unsigned int); -#ifdef MODULE int atari_scsi_release (struct Scsi_Host *); -#else -#define atari_scsi_release NULL -#endif /* The values for CMD_PER_LUN and CAN_QUEUE are somehow arbitrary. Higher * values should work, too; try it! (but cmd_per_lun costs memory!) */ @@ -63,6 +59,32 @@ int atari_scsi_release (struct Scsi_Host *); #define NCR5380_dma_xfer_len(i,cmd,phase) \ atari_dma_xfer_len(cmd->SCp.this_residual,cmd,((phase) & SR_IO) ? 0 : 1) +/* former generic SCSI error handling stuff */ + +#define SCSI_ABORT_SNOOZE 0 +#define SCSI_ABORT_SUCCESS 1 +#define SCSI_ABORT_PENDING 2 +#define SCSI_ABORT_BUSY 3 +#define SCSI_ABORT_NOT_RUNNING 4 +#define SCSI_ABORT_ERROR 5 + +#define SCSI_RESET_SNOOZE 0 +#define SCSI_RESET_PUNT 1 +#define SCSI_RESET_SUCCESS 2 +#define SCSI_RESET_PENDING 3 +#define SCSI_RESET_WAKEUP 4 +#define SCSI_RESET_NOT_RUNNING 5 +#define SCSI_RESET_ERROR 6 + +#define SCSI_RESET_SYNCHRONOUS 0x01 +#define SCSI_RESET_ASYNCHRONOUS 0x02 +#define SCSI_RESET_SUGGEST_BUS_RESET 0x04 +#define SCSI_RESET_SUGGEST_HOST_RESET 0x08 + +#define SCSI_RESET_BUS_RESET 0x100 +#define SCSI_RESET_HOST_RESET 0x200 +#define SCSI_RESET_ACTION 0xff + /* Debugging printk definitions: * * ARB -> arbitration @@ -91,144 +113,58 @@ int atari_scsi_release (struct Scsi_Host *); * */ -#if NDEBUG & NDEBUG_ARBITRATION +#define dprint(flg, format...) \ +({ \ + if (NDEBUG & (flg)) \ + printk(KERN_DEBUG format); \ +}) + #define ARB_PRINTK(format, args...) \ - printk(KERN_DEBUG format , ## args) -#else -#define ARB_PRINTK(format, args...) -#endif -#if NDEBUG & NDEBUG_AUTOSENSE + dprint(NDEBUG_ARBITRATION, format , ## args) #define ASEN_PRINTK(format, args...) \ - printk(KERN_DEBUG format , ## args) -#else -#define ASEN_PRINTK(format, args...) -#endif -#if NDEBUG & NDEBUG_DMA + dprint(NDEBUG_AUTOSENSE, format , ## args) #define DMA_PRINTK(format, args...) \ - printk(KERN_DEBUG format , ## args) -#else -#define DMA_PRINTK(format, args...) -#endif -#if NDEBUG & NDEBUG_HANDSHAKE + dprint(NDEBUG_DMA, format , ## args) #define HSH_PRINTK(format, args...) \ - printk(KERN_DEBUG format , ## args) -#else -#define HSH_PRINTK(format, args...) -#endif -#if NDEBUG & NDEBUG_INFORMATION + dprint(NDEBUG_HANDSHAKE, format , ## args) #define INF_PRINTK(format, args...) \ - printk(KERN_DEBUG format , ## args) -#else -#define INF_PRINTK(format, args...) -#endif -#if NDEBUG & NDEBUG_INIT + dprint(NDEBUG_INFORMATION, format , ## args) #define INI_PRINTK(format, args...) \ - printk(KERN_DEBUG format , ## args) -#else -#define INI_PRINTK(format, args...) -#endif -#if NDEBUG & NDEBUG_INTR + dprint(NDEBUG_INIT, format , ## args) #define INT_PRINTK(format, args...) \ - printk(KERN_DEBUG format , ## args) -#else -#define INT_PRINTK(format, args...) -#endif -#if NDEBUG & NDEBUG_LINKED + dprint(NDEBUG_INTR, format , ## args) #define LNK_PRINTK(format, args...) \ - printk(KERN_DEBUG format , ## args) -#else -#define LNK_PRINTK(format, args...) -#endif -#if NDEBUG & NDEBUG_MAIN + dprint(NDEBUG_LINKED, format , ## args) #define MAIN_PRINTK(format, args...) \ - printk(KERN_DEBUG format , ## args) -#else -#define MAIN_PRINTK(format, args...) -#endif -#if NDEBUG & NDEBUG_NO_DATAOUT + dprint(NDEBUG_MAIN, format , ## args) #define NDAT_PRINTK(format, args...) \ - printk(KERN_DEBUG format , ## args) -#else -#define NDAT_PRINTK(format, args...) -#endif -#if NDEBUG & NDEBUG_NO_WRITE + dprint(NDEBUG_NO_DATAOUT, format , ## args) #define NWR_PRINTK(format, args...) \ - printk(KERN_DEBUG format , ## args) -#else -#define NWR_PRINTK(format, args...) -#endif -#if NDEBUG & NDEBUG_PIO + dprint(NDEBUG_NO_WRITE, format , ## args) #define PIO_PRINTK(format, args...) \ - printk(KERN_DEBUG format , ## args) -#else -#define PIO_PRINTK(format, args...) -#endif -#if NDEBUG & NDEBUG_PSEUDO_DMA + dprint(NDEBUG_PIO, format , ## args) #define PDMA_PRINTK(format, args...) \ - printk(KERN_DEBUG format , ## args) -#else -#define PDMA_PRINTK(format, args...) -#endif -#if NDEBUG & NDEBUG_QUEUES + dprint(NDEBUG_PSEUDO_DMA, format , ## args) #define QU_PRINTK(format, args...) \ - printk(KERN_DEBUG format , ## args) -#else -#define QU_PRINTK(format, args...) -#endif -#if NDEBUG & NDEBUG_RESELECTION + dprint(NDEBUG_QUEUES, format , ## args) #define RSL_PRINTK(format, args...) \ - printk(KERN_DEBUG format , ## args) -#else -#define RSL_PRINTK(format, args...) -#endif -#if NDEBUG & NDEBUG_SELECTION + dprint(NDEBUG_RESELECTION, format , ## args) #define SEL_PRINTK(format, args...) \ - printk(KERN_DEBUG format , ## args) -#else -#define SEL_PRINTK(format, args...) -#endif -#if NDEBUG & NDEBUG_USLEEP + dprint(NDEBUG_SELECTION, format , ## args) #define USL_PRINTK(format, args...) \ - printk(KERN_DEBUG format , ## args) -#else -#define USL_PRINTK(format, args...) -#endif -#if NDEBUG & NDEBUG_LAST_BYTE_SENT + dprint(NDEBUG_USLEEP, format , ## args) #define LBS_PRINTK(format, args...) \ - printk(KERN_DEBUG format , ## args) -#else -#define LBS_PRINTK(format, args...) -#endif -#if NDEBUG & NDEBUG_RESTART_SELECT + dprint(NDEBUG_LAST_BYTE_SENT, format , ## args) #define RSS_PRINTK(format, args...) \ - printk(KERN_DEBUG format , ## args) -#else -#define RSS_PRINTK(format, args...) -#endif -#if NDEBUG & NDEBUG_EXTENDED + dprint(NDEBUG_RESTART_SELECT, format , ## args) #define EXT_PRINTK(format, args...) \ - printk(KERN_DEBUG format , ## args) -#else -#define EXT_PRINTK(format, args...) -#endif -#if NDEBUG & NDEBUG_ABORT + dprint(NDEBUG_EXTENDED, format , ## args) #define ABRT_PRINTK(format, args...) \ - printk(KERN_DEBUG format , ## args) -#else -#define ABRT_PRINTK(format, args...) -#endif -#if NDEBUG & NDEBUG_TAGS + dprint(NDEBUG_ABORT, format , ## args) #define TAG_PRINTK(format, args...) \ - printk(KERN_DEBUG format , ## args) -#else -#define TAG_PRINTK(format, args...) -#endif -#if NDEBUG & NDEBUG_MERGING + dprint(NDEBUG_TAGS, format , ## args) #define MER_PRINTK(format, args...) \ - printk(KERN_DEBUG format , ## args) -#else -#define MER_PRINTK(format, args...) -#endif + dprint(NDEBUG_MERGING, format , ## args) /* conditional macros for NCR5380_print_{,phase,status} */ diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index b1cb72c3780..d18b51f989c 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -389,7 +389,10 @@ config FB_ARC config FB_ATARI bool "Atari native chipset support" - depends on (FB = y) && ATARI && BROKEN + depends on (FB = y) && ATARI + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT help This is the frame buffer device driver for the builtin graphics chipset found in Ataris. diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 760305c8a84..869351785ee 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -63,7 +63,8 @@ obj-$(CONFIG_FB_TCX) += tcx.o sbuslib.o obj-$(CONFIG_FB_LEO) += leo.o sbuslib.o obj-$(CONFIG_FB_SGIVW) += sgivwfb.o obj-$(CONFIG_FB_ACORN) += acornfb.o -obj-$(CONFIG_FB_ATARI) += atafb.o +obj-$(CONFIG_FB_ATARI) += atafb.o c2p.o atafb_mfb.o \ + atafb_iplan2p2.o atafb_iplan2p4.o atafb_iplan2p8.o obj-$(CONFIG_FB_MAC) += macfb.o obj-$(CONFIG_FB_HGA) += hgafb.o obj-$(CONFIG_FB_IGA) += igafb.o diff --git a/drivers/video/atafb.c b/drivers/video/atafb.c index bffe2b94634..0038a0541c7 100644 --- a/drivers/video/atafb.c +++ b/drivers/video/atafb.c @@ -2,7 +2,7 @@ * linux/drivers/video/atafb.c -- Atari builtin chipset frame buffer device * * Copyright (C) 1994 Martin Schaller & Roman Hodek - * + * * 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. @@ -70,14 +70,8 @@ #include <linux/fb.h> #include <asm/atarikb.h> -#include <video/fbcon.h> -#include <video/fbcon-cfb8.h> -#include <video/fbcon-cfb16.h> -#include <video/fbcon-iplan2p2.h> -#include <video/fbcon-iplan2p4.h> -#include <video/fbcon-iplan2p8.h> -#include <video/fbcon-mfb.h> - +#include "c2p.h" +#include "atafb.h" #define SWITCH_ACIA 0x01 /* modes for switch on OverScan */ #define SWITCH_SND6 0x40 @@ -87,22 +81,48 @@ #define up(x, r) (((x) + (r) - 1) & ~((r)-1)) + /* + * Interface to the world + */ + +static int atafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info); +static int atafb_set_par(struct fb_info *info); +static int atafb_setcolreg(unsigned int regno, unsigned int red, unsigned int green, + unsigned int blue, unsigned int transp, + struct fb_info *info); +static int atafb_blank(int blank, struct fb_info *info); +static int atafb_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info); +static void atafb_fillrect(struct fb_info *info, + const struct fb_fillrect *rect); +static void atafb_copyarea(struct fb_info *info, + const struct fb_copyarea *region); +static void atafb_imageblit(struct fb_info *info, const struct fb_image *image); +static int atafb_ioctl(struct fb_info *info, unsigned int cmd, + unsigned long arg); + -static int default_par=0; /* default resolution (0=none) */ +static int default_par; /* default resolution (0=none) */ -static unsigned long default_mem_req=0; +static unsigned long default_mem_req; -static int hwscroll=-1; +static int hwscroll = -1; static int use_hwscroll = 1; -static int sttt_xres=640,st_yres=400,tt_yres=480; -static int sttt_xres_virtual=640,sttt_yres_virtual=400; -static int ovsc_offset=0, ovsc_addlen=0; +static int sttt_xres = 640, st_yres = 400, tt_yres = 480; +static int sttt_xres_virtual = 640, sttt_yres_virtual = 400; +static int ovsc_offset, ovsc_addlen; + + /* + * Hardware parameters for current mode + */ static struct atafb_par { void *screen_base; int yres_virtual; + u_long next_line; + u_long next_plane; #if defined ATAFB_TT || defined ATAFB_STE union { struct { @@ -138,7 +158,7 @@ static struct atafb_par { /* Don't calculate an own resolution, and thus don't change the one found when * booting (currently used for the Falcon to keep settings for internal video * hardware extensions (e.g. ScreenBlaster) */ -static int DontCalcRes = 0; +static int DontCalcRes = 0; #ifdef ATAFB_FALCON #define HHT hw.falcon.hht @@ -163,83 +183,84 @@ static int DontCalcRes = 0; #define VMO_PREMASK 0x0c #endif -static struct fb_info fb_info; +static struct fb_info fb_info = { + .fix = { + .id = "Atari ", + .visual = FB_VISUAL_PSEUDOCOLOR, + .accel = FB_ACCEL_NONE, + } +}; static void *screen_base; /* base address of screen */ static void *real_screen_base; /* (only for Overscan) */ static int screen_len; -static int current_par_valid=0; +static int current_par_valid; -static int mono_moni=0; - -static struct display disp; +static int mono_moni; #ifdef ATAFB_EXT -/* external video handling */ -static unsigned external_xres; -static unsigned external_xres_virtual; -static unsigned external_yres; -/* not needed - atafb will never support panning/hardwarescroll with external - * static unsigned external_yres_virtual; -*/ +/* external video handling */ +static unsigned int external_xres; +static unsigned int external_xres_virtual; +static unsigned int external_yres; -static unsigned external_depth; -static int external_pmode; -static void *external_addr = 0; -static unsigned long external_len; -static unsigned long external_vgaiobase = 0; -static unsigned int external_bitspercol = 6; - -/* -JOE <joe@amber.dinoco.de>: -added card type for external driver, is only needed for -colormap handling. -*/ +/* + * not needed - atafb will never support panning/hardwarescroll with external + * static unsigned int external_yres_virtual; + */ +static unsigned int external_depth; +static int external_pmode; +static void *external_addr; +static unsigned long external_len; +static unsigned long external_vgaiobase; +static unsigned int external_bitspercol = 6; +/* + * JOE <joe@amber.dinoco.de>: + * added card type for external driver, is only needed for + * colormap handling. + */ enum cardtype { IS_VGA, IS_MV300 }; static enum cardtype external_card_type = IS_VGA; /* -The MV300 mixes the color registers. So we need an array of munged -indices in order to access the correct reg. -*/ -static int MV300_reg_1bit[2]={0,1}; -static int MV300_reg_4bit[16]={ -0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15 }; -static int MV300_reg_8bit[256]={ -0, 128, 64, 192, 32, 160, 96, 224, 16, 144, 80, 208, 48, 176, 112, 240, -8, 136, 72, 200, 40, 168, 104, 232, 24, 152, 88, 216, 56, 184, 120, 248, -4, 132, 68, 196, 36, 164, 100, 228, 20, 148, 84, 212, 52, 180, 116, 244, -12, 140, 76, 204, 44, 172, 108, 236, 28, 156, 92, 220, 60, 188, 124, 252, -2, 130, 66, 194, 34, 162, 98, 226, 18, 146, 82, 210, 50, 178, 114, 242, -10, 138, 74, 202, 42, 170, 106, 234, 26, 154, 90, 218, 58, 186, 122, 250, -6, 134, 70, 198, 38, 166, 102, 230, 22, 150, 86, 214, 54, 182, 118, 246, -14, 142, 78, 206, 46, 174, 110, 238, 30, 158, 94, 222, 62, 190, 126, 254, -1, 129, 65, 193, 33, 161, 97, 225, 17, 145, 81, 209, 49, 177, 113, 241, -9, 137, 73, 201, 41, 169, 105, 233, 25, 153, 89, 217, 57, 185, 121, 249, -5, 133, 69, 197, 37, 165, 101, 229, 21, 149, 85, 213, 53, 181, 117, 245, -13, 141, 77, 205, 45, 173, 109, 237, 29, 157, 93, 221, 61, 189, 125, 253, -3, 131, 67, 195, 35, 163, 99, 227, 19, 147, 83, 211, 51, 179, 115, 243, -11, 139, 75, 203, 43, 171, 107, 235, 27, 155, 91, 219, 59, 187, 123, 251, -7, 135, 71, 199, 39, 167, 103, 231, 23, 151, 87, 215, 55, 183, 119, 247, -15, 143, 79, 207, 47, 175, 111, 239, 31, 159, 95, 223, 63, 191, 127, 255 }; + * The MV300 mixes the color registers. So we need an array of munged + * indices in order to access the correct reg. + */ +static int MV300_reg_1bit[2] = { + 0, 1 +}; +static int MV300_reg_4bit[16] = { + 0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15 +}; +static int MV300_reg_8bit[256] = { + 0, 128, 64, 192, 32, 160, 96, 224, 16, 144, 80, 208, 48, 176, 112, 240, + 8, 136, 72, 200, 40, 168, 104, 232, 24, 152, 88, 216, 56, 184, 120, 248, + 4, 132, 68, 196, 36, 164, 100, 228, 20, 148, 84, 212, 52, 180, 116, 244, + 12, 140, 76, 204, 44, 172, 108, 236, 28, 156, 92, 220, 60, 188, 124, 252, + 2, 130, 66, 194, 34, 162, 98, 226, 18, 146, 82, 210, 50, 178, 114, 242, + 10, 138, 74, 202, 42, 170, 106, 234, 26, 154, 90, 218, 58, 186, 122, 250, + 6, 134, 70, 198, 38, 166, 102, 230, 22, 150, 86, 214, 54, 182, 118, 246, + 14, 142, 78, 206, 46, 174, 110, 238, 30, 158, 94, 222, 62, 190, 126, 254, + 1, 129, 65, 193, 33, 161, 97, 225, 17, 145, 81, 209, 49, 177, 113, 241, + 9, 137, 73, 201, 41, 169, 105, 233, 25, 153, 89, 217, 57, 185, 121, 249, + 5, 133, 69, 197, 37, 165, 101, 229, 21, 149, 85, 213, 53, 181, 117, 245, + 13, 141, 77, 205, 45, 173, 109, 237, 29, 157, 93, 221, 61, 189, 125, 253, + 3, 131, 67, 195, 35, 163, 99, 227, 19, 147, 83, 211, 51, 179, 115, 243, + 11, 139, 75, 203, 43, 171, 107, 235, 27, 155, 91, 219, 59, 187, 123, 251, + 7, 135, 71, 199, 39, 167, 103, 231, 23, 151, 87, 215, 55, 183, 119, 247, + 15, 143, 79, 207, 47, 175, 111, 239, 31, 159, 95, 223, 63, 191, 127, 255 +}; static int *MV300_reg = MV300_reg_8bit; - -/* -And on the MV300 it's difficult to read out the hardware palette. So we -just keep track of the set colors in our own array here, and use that! -*/ - -static struct { unsigned char red,green,blue,pad; } ext_color[256]; #endif /* ATAFB_EXT */ -static int inverse=0; +static int inverse; extern int fontheight_8x8; extern int fontwidth_8x8; @@ -249,96 +270,154 @@ extern int fontheight_8x16; extern int fontwidth_8x16; extern unsigned char fontdata_8x16[]; +/* + * struct fb_ops { + * * open/release and usage marking + * struct module *owner; + * int (*fb_open)(struct fb_info *info, int user); + * int (*fb_release)(struct fb_info *info, int user); + * + * * For framebuffers with strange non linear layouts or that do not + * * work with normal memory mapped access + * ssize_t (*fb_read)(struct file *file, char __user *buf, size_t count, loff_t *ppos); + * ssize_t (*fb_write)(struct file *file, const char __user *buf, size_t count, loff_t *ppos); + * + * * checks var and eventually tweaks it to something supported, + * * DOES NOT MODIFY PAR * + * int (*fb_check_var)(struct fb_var_screeninfo *var, struct fb_info *info); + * + * * set the video mode according to info->var * + * int (*fb_set_par)(struct fb_info *info); + * + * * set color register * + * int (*fb_setcolreg)(unsigned int regno, unsigned int red, unsigned int green, + * unsigned int blue, unsigned int transp, struct fb_info *info); + * + * * set color registers in batch * + * int (*fb_setcmap)(struct fb_cmap *cmap, struct fb_info *info); + * + * * blank display * + * int (*fb_blank)(int blank, struct fb_info *info); + * + * * pan display * + * int (*fb_pan_display)(struct fb_var_screeninfo *var, struct fb_info *info); + * + * *** The meat of the drawing engine *** + * * Draws a rectangle * + * void (*fb_fillrect) (struct fb_info *info, const struct fb_fillrect *rect); + * * Copy data from area to another * + * void (*fb_copyarea) (struct fb_info *info, const struct fb_copyarea *region); + * * Draws a image to the display * + * void (*fb_imageblit) (struct fb_info *info, const struct fb_image *image); + * + * * Draws cursor * + * int (*fb_cursor) (struct fb_info *info, struct fb_cursor *cursor); + * + * * Rotates the display * + * void (*fb_rotate)(struct fb_info *info, int angle); + * + * * wait for blit idle, optional * + * int (*fb_sync)(struct fb_info *info); + * + * * perform fb specific ioctl (optional) * + * int (*fb_ioctl)(struct fb_info *info, unsigned int cmd, + * unsigned long arg); + * + * * Handle 32bit compat ioctl (optional) * + * int (*fb_compat_ioctl)(struct fb_info *info, unsigned int cmd, + * unsigned long arg); + * + * * perform fb specific mmap * + * int (*fb_mmap)(struct fb_info *info, struct vm_area_struct *vma); + * + * * save current hardware state * + * void (*fb_save_state)(struct fb_info *info); + * + * * restore saved state * + * void (*fb_restore_state)(struct fb_info *info); + * } ; + */ + + /* ++roman: This structure abstracts from the underlying hardware (ST(e), * TT, or Falcon. * - * int (*detect)( void ) + * int (*detect)(void) * This function should detect the current video mode settings and * store them in atafb_predefined[0] for later reference by the * user. Return the index+1 of an equivalent predefined mode or 0 * if there is no such. - * - * int (*encode_fix)( struct fb_fix_screeninfo *fix, - * struct atafb_par *par ) + * + * int (*encode_fix)(struct fb_fix_screeninfo *fix, + * struct atafb_par *par) * This function should fill in the 'fix' structure based on the * values in the 'par' structure. - * - * int (*decode_var)( struct fb_var_screeninfo *var, - * struct atafb_par *par ) + * !!! Obsolete, perhaps !!! + * + * int (*decode_var)(struct fb_var_screeninfo *var, + * struct atafb_par *par) * Get the video params out of 'var'. If a value doesn't fit, round * it up, if it's too big, return EINVAL. - * Round up in the following order: bits_per_pixel, xres, yres, - * xres_virtual, yres_virtual, xoffset, yoffset, grayscale, bitfields, + * Round up in the following order: bits_per_pixel, xres, yres, + * xres_virtual, yres_virtual, xoffset, yoffset, grayscale, bitfields, * horizontal timing, vertical timing. * - * int (*encode_var)( struct fb_var_screeninfo *var, - * struct atafb_par *par ); + * int (*encode_var)(struct fb_var_screeninfo *var, + * struct atafb_par *par); * Fill the 'var' structure based on the values in 'par' and maybe * other values read out of the hardware. - * - * void (*get_par)( struct atafb_par *par ) + * + * void (*get_par)(struct atafb_par *par) * Fill the hardware's 'par' structure. - * - * void (*set_par)( struct atafb_par *par ) + * !!! Used only by detect() !!! + * + * void (*set_par)(struct atafb_par *par) * Set the hardware according to 'par'. - * - * int (*getcolreg)( unsigned regno, unsigned *red, - * unsigned *green, unsigned *blue, - * unsigned *transp, struct fb_info *info ) - * Read a single color register and split it into - * colors/transparent. Return != 0 for invalid regno. * * void (*set_screen_base)(void *s_base) * Set the base address of the displayed frame buffer. Only called * if yres_virtual > yres or xres_virtual > xres. * - * int (*blank)( int blank_mode ) - * Blank the screen if blank_mode!=0, else unblank. If blank==NULL then + * int (*blank)(int blank_mode) + * Blank the screen if blank_mode != 0, else unblank. If blank == NULL then * the caller blanks by setting the CLUT to all black. Return 0 if blanking * succeeded, !=0 if un-/blanking failed due to e.g. a video mode which * doesn't support it. Implements VESA suspend and powerdown modes on * hardware that supports disabling hsync/vsync: - * blank_mode==2: suspend vsync, 3:suspend hsync, 4: powerdown. + * blank_mode == 2: suspend vsync, 3:suspend hsync, 4: powerdown. */ static struct fb_hwswitch { - int (*detect)( void ); - int (*encode_fix)( struct fb_fix_screeninfo *fix, - struct atafb_par *par ); - int (*decode_var)( struct fb_var_screeninfo *var, - struct atafb_par *par ); - int (*encode_var)( struct fb_var_screeninfo *var, - struct atafb_par *par ); - void (*get_par)( struct atafb_par *par ); - void (*set_par)( struct atafb_par *par ); - int (*getcolreg)( unsigned regno, unsigned *red, - unsigned *green, unsigned *blue, - unsigned *transp, struct fb_info *info ); + int (*detect)(void); + int (*encode_fix)(struct fb_fix_screeninfo *fix, + struct atafb_par *par); + int (*decode_var)(struct fb_var_screeninfo *var, + struct atafb_par *par); + int (*encode_var)(struct fb_var_screeninfo *var, + struct atafb_par *par); + void (*get_par)(struct atafb_par *par); + void (*set_par)(struct atafb_par *par); void (*set_screen_base)(void *s_base); - int (*blank)( int blank_mode ); - int (*pan_display)( struct fb_var_screeninfo *var, - struct atafb_par *par); + int (*blank)(int blank_mode); + int (*pan_display)(struct fb_var_screeninfo *var, + struct fb_info *info); } *fbhw; -static char *autodetect_names[] = {"autodetect", NULL}; -static char *stlow_names[] = {"stlow", NULL}; -static char *stmid_names[] = {"stmid", "default5", NULL}; -static char *sthigh_names[] = {"sthigh", "default4", NULL}; -static char *ttlow_names[] = {"ttlow", NULL}; -static char *ttmid_names[]= {"ttmid", "default1", NULL}; -static char *tthigh_names[]= {"tthigh", "default2", NULL}; -static char *vga2_names[] = {"vga2", NULL}; -static char *vga4_names[] = {"vga4", NULL}; -static char *vga16_names[] = {"vga16", "default3", NULL}; -static char *vga256_names[] = {"vga256", NULL}; -static char *falh2_names[] = {"falh2", NULL}; -static char *falh16_names[] = {"falh16", NULL}; +static char *autodetect_names[] = { "autodetect", NULL }; +static char *stlow_names[] = { "stlow", NULL }; +static char *stmid_names[] = { "stmid", "default5", NULL }; +static char *sthigh_names[] = { "sthigh", "default4", NULL }; +static char *ttlow_names[] = { "ttlow", NULL }; +static char *ttmid_names[] = { "ttmid", "default1", NULL }; +static char *tthigh_names[] = { "tthigh", "default2", NULL }; +static char *vga2_names[] = { "vga2", NULL }; +static char *vga4_names[] = { "vga4", NULL }; +static char *vga16_names[] = { "vga16", "default3", NULL }; +static char *vga256_names[] = { "vga256", NULL }; +static char *falh2_names[] = { "falh2", NULL }; +static char *falh16_names[] = { "falh16", NULL }; static char **fb_var_names[] = { - /* Writing the name arrays directly in this array (via "(char *[]){...}") - * crashes gcc 2.5.8 (sigsegv) if the inner array - * contains more than two items. I've also seen that all elements - * were identical to the last (my cross-gcc) :-(*/ autodetect_names, stlow_names, stmid_names, @@ -353,18 +432,17 @@ static char **fb_var_names[] = { falh2_names, falh16_names, NULL - /* ,NULL */ /* this causes a sigsegv on my gcc-2.5.8 */ }; static struct fb_var_screeninfo atafb_predefined[] = { - /* - * yres_virtual==0 means use hw-scrolling if possible, else yres - */ - { /* autodetect */ - 0, 0, 0, 0, 0, 0, 0, 0, /* xres-grayscale */ - {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, /* red green blue tran*/ + /* + * yres_virtual == 0 means use hw-scrolling if possible, else yres + */ + { /* autodetect */ + 0, 0, 0, 0, 0, 0, 0, 0, /* xres-grayscale */ + {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, /* red green blue tran*/ 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, - { /* st low */ + { /* st low */ 320, 200, 320, 0, 0, 0, 4, 0, {0, 4, 0}, {0, 4, 0}, {0, 4, 0}, {0, 0, 0}, 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, @@ -414,27 +492,100 @@ static struct fb_var_screeninfo atafb_predefined[] = { 0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0 }, }; -static int num_atafb_predefined=ARRAY_SIZE(atafb_predefined); +static int num_atafb_predefined = ARRAY_SIZE(atafb_predefined); +static struct fb_videomode atafb_modedb[] __initdata = { + /* + * Atari Video Modes + * + * If you change these, make sure to update DEFMODE_* as well! + */ -static int -get_video_mode(char *vname) + /* + * ST/TT Video Modes + */ + + { + /* 320x200, 15 kHz, 60 Hz (ST low) */ + "st-low", 60, 320, 200, 32000, 32, 16, 31, 14, 96, 4, + 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, { + /* 640x200, 15 kHz, 60 Hz (ST medium) */ + "st-mid", 60, 640, 200, 32000, 32, 16, 31, 14, 96, 4, + 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, { + /* 640x400, 30.25 kHz, 63.5 Hz (ST high) */ + "st-high", 63, 640, 400, 32000, 128, 0, 40, 14, 128, 4, + 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, { + /* 320x480, 15 kHz, 60 Hz (TT low) */ + "tt-low", 60, 320, 480, 31041, 120, 100, 8, 16, 140, 30, + 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, { + /* 640x480, 29 kHz, 57 Hz (TT medium) */ + "tt-mid", 60, 640, 480, 31041, 120, 100, 8, 16, 140, 30, + 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, { + /* 1280x960, 29 kHz, 60 Hz (TT high) */ + "tt-high", 57, 640, 960, 31041, 120, 100, 8, 16, 140, 30, + 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, + + /* + * VGA Video Modes + */ + + { + /* 640x480, 31 kHz, 60 Hz (VGA) */ + "vga", 63.5, 640, 480, 32000, 18, 42, 31, 11, 96, 3, + 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, { + /* 640x400, 31 kHz, 70 Hz (VGA) */ + "vga70", 70, 640, 400, 32000, 18, 42, 31, 11, 96, 3, + FB_SYNC_VERT_HIGH_ACT | FB_SYNC_COMP_HIGH_ACT, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, + + /* + * Falcon HiRes Video Modes + */ + + { + /* 896x608, 31 kHz, 60 Hz (Falcon High) */ + "falh", 60, 896, 608, 32000, 18, 42, 31, 1, 96,3, + 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP + }, +}; + +#define NUM_TOTAL_MODES ARRAY_SIZE(atafb_modedb) + +static char *mode_option __initdata = NULL; + + /* default modes */ + +#define DEFMODE_TT 5 /* "tt-high" for TT */ +#define DEFMODE_F30 7 /* "vga70" for Falcon */ +#define DEFMODE_STE 2 /* "st-high" for ST/E */ +#define DEFMODE_EXT 6 /* "vga" for external */ + + +static int get_video_mode(char *vname) { - char ***name_list; - char **name; - int i; - name_list=fb_var_names; - for (i = 0 ; i < num_atafb_predefined ; i++) { - name=*(name_list++); - if (! name || ! *name) - break; - while (*name) { - if (! strcmp(vname, *name)) - return i+1; - name++; + char ***name_list; + char **name; + int i; + + name_list = fb_var_names; + for (i = 0; i < num_atafb_predefined; i++) { + name = *name_list++; + if (!name || !*name) + break; + while (*name) { + if (!strcmp(vname, *name)) + return i + 1; + name++; + } } - } - return 0; + return 0; } @@ -443,93 +594,84 @@ get_video_mode(char *vname) #ifdef ATAFB_TT -static int tt_encode_fix( struct fb_fix_screeninfo *fix, - struct atafb_par *par ) - +static int tt_encode_fix(struct fb_fix_screeninfo *fix, struct atafb_par *par) { int mode; - strcpy(fix->id,"Atari Builtin"); + strcpy(fix->id, "Atari Builtin"); fix->smem_start = (unsigned long)real_screen_base; fix->smem_len = screen_len; - fix->type=FB_TYPE_INTERLEAVED_PLANES; - fix->type_aux=2; - fix->visual=FB_VISUAL_PSEUDOCOLOR; + fix->type = FB_TYPE_INTERLEAVED_PLANES; + fix->type_aux = 2; + fix->visual = FB_VISUAL_PSEUDOCOLOR; mode = par->hw.tt.mode & TT_SHIFTER_MODEMASK; if (mode == TT_SHIFTER_TTHIGH || mode == TT_SHIFTER_STHIGH) { - fix->type=FB_TYPE_PACKED_PIXELS; - fix->type_aux=0; + fix->type = FB_TYPE_PACKED_PIXELS; + fix->type_aux = 0; if (mode == TT_SHIFTER_TTHIGH) - fix->visual=FB_VISUAL_MONO01; + fix->visual = FB_VISUAL_MONO01; } - fix->xpanstep=0; - fix->ypanstep=1; - fix->ywrapstep=0; + fix->xpanstep = 0; + fix->ypanstep = 1; + fix->ywrapstep = 0; fix->line_length = 0; fix->accel = FB_ACCEL_ATARIBLITT; return 0; } - -static int tt_decode_var( struct fb_var_screeninfo *var, - struct atafb_par *par ) +static int tt_decode_var(struct fb_var_screeninfo *var, struct atafb_par *par) { - int xres=var->xres; - int yres=var->yres; - int bpp=var->bits_per_pixel; + int xres = var->xres; + int yres = var->yres; + int bpp = var->bits_per_pixel; int linelen; int yres_virtual = var->yres_virtual; if (mono_moni) { - if (bpp > 1 || xres > sttt_xres*2 || yres >tt_yres*2) + if (bpp > 1 || xres > sttt_xres * 2 || yres > tt_yres * 2) return -EINVAL; - par->hw.tt.mode=TT_SHIFTER_TTHIGH; - xres=sttt_xres*2; - yres=tt_yres*2; - bpp=1; + par->hw.tt.mode = TT_SHIFTER_TTHIGH; + xres = sttt_xres * 2; + yres = tt_yres * 2; + bpp = 1; } else { if (bpp > 8 || xres > sttt_xres || yres > tt_yres) return -EINVAL; if (bpp > 4) { - if (xres > sttt_xres/2 || yres > tt_yres) + if (xres > sttt_xres / 2 || yres > tt_yres) return -EINVAL; - par->hw.tt.mode=TT_SHIFTER_TTLOW; - xres=sttt_xres/2; - yres=tt_yres; - bpp=8; - } - else if (bpp > 2) { + par->hw.tt.mode = TT_SHIFTER_TTLOW; + xres = sttt_xres / 2; + yres = tt_yres; + bpp = 8; + } else if (bpp > 2) { if (xres > sttt_xres || yres > tt_yres) return -EINVAL; - if (xres > sttt_xres/2 || yres > st_yres/2) { - par->hw.tt.mode=TT_SHIFTER_TTMID; - xres=sttt_xres; - yres=tt_yres; - bpp=4; - } - else { - par->hw.tt.mode=TT_SHIFTER_STLOW; - xres=sttt_xres/2; - yres=st_yres/2; - bpp=4; + if (xres > sttt_xres / 2 || yres > st_yres / 2) { + par->hw.tt.mode = TT_SHIFTER_TTMID; + xres = sttt_xres; + yres = tt_yres; + bpp = 4; + } else { + par->hw.tt.mode = TT_SHIFTER_STLOW; + xres = sttt_xres / 2; + yres = st_yres / 2; + bpp = 4; } - } - else if (bpp > 1) { - if (xres > sttt_xres || yres > st_yres/2) + } else if (bpp > 1) { + if (xres > sttt_xres || yres > st_yres / 2) return -EINVAL; - par->hw.tt.mode=TT_SHIFTER_STMID; - xres=sttt_xres; - yres=st_yres/2; - bpp=2; - } - else if (var->xres > sttt_xres || var->yres > st_yres) { + par->hw.tt.mode = TT_SHIFTER_STMID; + xres = sttt_xres; + yres = st_yres / 2; + bpp = 2; + } else if (var->xres > sttt_xres || var->yres > st_yres) { return -EINVAL; - } - else { - par->hw.tt.mode=TT_SHIFTER_STHIGH; - xres=sttt_xres; - yres=st_yres; - bpp=1; + } else { + par->hw.tt.mode = TT_SHIFTER_STHIGH; + xres = sttt_xres; + yres = st_yres; + bpp = 1; } } if (yres_virtual <= 0) @@ -537,10 +679,10 @@ static int tt_decode_var( struct fb_var_screeninfo *var, else if (yres_virtual < yres) yres_virtual = yres; if (var->sync & FB_SYNC_EXT) - par->hw.tt.sync=0; + par->hw.tt.sync = 0; else - par->hw.tt.sync=1; - linelen=xres*bpp/8; + par->hw.tt.sync = 1; + linelen = xres * bpp / 8; if (yres_virtual * linelen > screen_len && screen_len) return -EINVAL; if (yres * linelen > screen_len && screen_len) @@ -552,154 +694,123 @@ static int tt_decode_var( struct fb_var_screeninfo *var, return 0; } -static int tt_encode_var( struct fb_var_screeninfo *var, - struct atafb_par *par ) +static int tt_encode_var(struct fb_var_screeninfo *var, struct atafb_par *par) { int linelen; memset(var, 0, sizeof(struct fb_var_screeninfo)); - var->red.offset=0; - var->red.length=4; - var->red.msb_right=0; - var->grayscale=0; - - var->pixclock=31041; - var->left_margin=120; /* these may be incorrect */ - var->right_margin=100; - var->upper_margin=8; - var->lower_margin=16; - var->hsync_len=140; - var->vsync_len=30; - - var->height=-1; - var->width=-1; + var->red.offset = 0; + var->red.length = 4; + var->red.msb_right = 0; + var->grayscale = 0; + + var->pixclock = 31041; + var->left_margin = 120; /* these may be incorrect */ + var->right_margin = 100; + var->upper_margin = 8; + var->lower_margin = 16; + var->hsync_len = 140; + var->vsync_len = 30; + + var->height = -1; + var->width = -1; if (par->hw.tt.sync & 1) - var->sync=0; + var->sync = 0; else - var->sync=FB_SYNC_EXT; + var->sync = FB_SYNC_EXT; switch (par->hw.tt.mode & TT_SHIFTER_MODEMASK) { case TT_SHIFTER_STLOW: - var->xres=sttt_xres/2; - var->xres_virtual=sttt_xres_virtual/2; - var->yres=st_yres/2; - var->bits_per_pixel=4; + var->xres = sttt_xres / 2; + var->xres_virtual = sttt_xres_virtual / 2; + var->yres = st_yres / 2; + var->bits_per_pixel = 4; break; case TT_SHIFTER_STMID: - var->xres=sttt_xres; - var->xres_virtual=sttt_xres_virtual; - var->yres=st_yres/2; - var->bits_per_pixel=2; + var->xres = sttt_xres; + var->xres_virtual = sttt_xres_virtual; + var->yres = st_yres / 2; + var->bits_per_pixel = 2; break; case TT_SHIFTER_STHIGH: - var->xres=sttt_xres; - var->xres_virtual=sttt_xres_virtual; - var->yres=st_yres; - var->bits_per_pixel=1; + var->xres = sttt_xres; + var->xres_virtual = sttt_xres_virtual; + var->yres = st_yres; + var->bits_per_pixel = 1; break; case TT_SHIFTER_TTLOW: - var->xres=sttt_xres/2; - var->xres_virtual=sttt_xres_virtual/2; - var->yres=tt_yres; - var->bits_per_pixel=8; + var->xres = sttt_xres / 2; + var->xres_virtual = sttt_xres_virtual / 2; + var->yres = tt_yres; + var->bits_per_pixel = 8; break; case TT_SHIFTER_TTMID: - var->xres=sttt_xres; - var->xres_virtual=sttt_xres_virtual; - var->yres=tt_yres; - var->bits_per_pixel=4; + var->xres = sttt_xres; + var->xres_virtual = sttt_xres_virtual; + var->yres = tt_yres; + var->bits_per_pixel = 4; break; case TT_SHIFTER_TTHIGH: - var->red.length=0; - var->xres=sttt_xres*2; - var->xres_virtual=sttt_xres_virtual*2; - var->yres=tt_yres*2; - var->bits_per_pixel=1; + var->red.length = 0; + var->xres = sttt_xres * 2; + var->xres_virtual = sttt_xres_virtual * 2; + var->yres = tt_yres * 2; + var->bits_per_pixel = 1; break; - } - var->blue=var->green=var->red; - var->transp.offset=0; - var->transp.length=0; - var->transp.msb_right=0; - linelen=var->xres_virtual * var->bits_per_pixel / 8; - if (! use_hwscroll) - var->yres_virtual=var->yres; + } + var->blue = var->green = var->red; + var->transp.offset = 0; + var->transp.length = 0; + var->transp.msb_right = 0; + linelen = var->xres_virtual * var->bits_per_pixel / 8; + if (!use_hwscroll) + var->yres_virtual = var->yres; else if (screen_len) { if (par->yres_virtual) var->yres_virtual = par->yres_virtual; else - /* yres_virtual==0 means use maximum */ + /* yres_virtual == 0 means use maximum */ var->yres_virtual = screen_len / linelen; } else { if (hwscroll < 0) var->yres_virtual = 2 * var->yres; else - var->yres_virtual=var->yres+hwscroll * 16; + var->yres_virtual = var->yres + hwscroll * 16; } - var->xoffset=0; + var->xoffset = 0; if (screen_base) - var->yoffset=(par->screen_base - screen_base)/linelen; + var->yoffset = (par->screen_base - screen_base) / linelen; else - var->yoffset=0; - var->nonstd=0; - var->activate=0; - var->vmode=FB_VMODE_NONINTERLACED; + var->yoffset = 0; + var->nonstd = 0; + var->activate = 0; + var->vmode = FB_VMODE_NONINTERLACED; return 0; } - -static void tt_get_par( struct atafb_par *par ) +static void tt_get_par(struct atafb_par *par) { unsigned long addr; - par->hw.tt.mode=shifter_tt.tt_shiftmode; - par->hw.tt.sync=shifter.syncmode; + par->hw.tt.mode = shifter_tt.tt_shiftmode; + par->hw.tt.sync = shifter.syncmode; addr = ((shifter.bas_hi & 0xff) << 16) | ((shifter.bas_md & 0xff) << 8) | ((shifter.bas_lo & 0xff)); par->screen_base = phys_to_virt(addr); } -static void tt_set_par( struct atafb_par *par ) +static void tt_set_par(struct atafb_par *par) { - shifter_tt.tt_shiftmode=par->hw.tt.mode; - shifter.syncmode=par->hw.tt.sync; + shifter_tt.tt_shiftmode = par->hw.tt.mode; + shifter.syncmode = par->hw.tt.sync; /* only set screen_base if really necessary */ if (current_par.screen_base != par->screen_base) fbhw->set_screen_base(par->screen_base); } - -static int tt_getcolreg(unsigned regno, unsigned *red, - unsigned *green, unsigned *blue, - unsigned *transp, struct fb_info *info) -{ - int t, col; - - if ((shifter_tt.tt_shiftmode & TT_SHIFTER_MODEMASK) == TT_SHIFTER_STHIGH) - regno += 254; - if (regno > 255) - return 1; - t = tt_palette[regno]; - col = t & 15; - col |= col << 4; - col |= col << 8; - *blue = col; - col = (t >> 4) & 15; - col |= col << 4; - col |= col << 8; - *green = col; - col = (t >> 8) & 15; - col |= col << 4; - col |= col << 8; - *red = col; - *transp = 0; - return 0; -} - - -static int tt_setcolreg(unsigned regno, unsigned red, - unsigned green, unsigned blue, - unsigned transp, struct fb_info *info) +static int tt_setcolreg(unsigned int regno, unsigned int red, + unsigned int green, unsigned int blue, + unsigned int transp, struct fb_info *info) { if ((shifter_tt.tt_shiftmode & TT_SHIFTER_MODEMASK) == TT_SHIFTER_STHIGH) regno += 254; @@ -708,15 +819,14 @@ static int tt_setcolreg(unsigned regno, unsigned red, tt_palette[regno] = (((red >> 12) << 8) | ((green >> 12) << 4) | (blue >> 12)); if ((shifter_tt.tt_shiftmode & TT_SHIFTER_MODEMASK) == - TT_SHIFTER_STHIGH && regno == 254) + TT_SHIFTER_STHIGH && regno == 254) tt_palette[0] = 0; return 0; } - -static int tt_detect( void ) - -{ struct atafb_par par; +static int tt_detect(void) +{ + struct atafb_par par; /* Determine the connected monitor: The DMA sound must be * disabled before reading the MFP GPIP, because the Sound @@ -726,9 +836,9 @@ static int tt_detect( void ) * announced that the Eagle is TT compatible, but only the PCM is * missing... */ - if (ATARIHW_PRESENT(PCM_8BIT)) { + if (ATARIHW_PRESENT(PCM_8BIT)) { tt_dmasnd.ctrl = DMASND_CTRL_OFF; - udelay(20); /* wait a while for things to settle down */ + udelay(20); /* wait a while for things to settle down */ } mono_moni = (mfp.par_dt_reg & 0x80) == 0; @@ -755,19 +865,24 @@ static struct pixel_clock { unsigned long f; /* f/[Hz] */ unsigned long t; /* t/[ps] (=1/f) */ int right, hsync, left; /* standard timing in clock cycles, not pixel */ - /* hsync initialized in falcon_detect() */ + /* hsync initialized in falcon_detect() */ int sync_mask; /* or-mask for hw.falcon.sync to set this clock */ int control_mask; /* ditto, for hw.falcon.vid_control */ -} -f25 = {25175000, 39721, 18, 0, 42, 0x0, VCO_CLOCK25}, -f32 = {32000000, 31250, 18, 0, 42, 0x0, 0}, -fext = { 0, 0, 18, 0, 42, 0x1, 0}; +} f25 = { + 25175000, 39721, 18, 0, 42, 0x0, VCO_CLOCK25 +}, f32 = { + 32000000, 31250, 18, 0, 42, 0x0, 0 +}, fext = { + 0, 0, 18, 0, 42, 0x1, 0 +}; /* VIDEL-prescale values [mon_type][pixel_length from VCO] */ -static int vdl_prescale[4][3] = {{4,2,1}, {4,2,1}, {4,2,2}, {4,2,1}}; +static int vdl_prescale[4][3] = { + { 4,2,1 }, { 4,2,1 }, { 4,2,2 }, { 4,2,1 } +}; /* Default hsync timing [mon_type] in picoseconds */ -static long h_syncs[4] = {3000000, 4875000, 4000000, 4875000}; +static long h_syncs[4] = { 3000000, 4875000, 4000000, 4875000 }; #ifdef FBCON_HAS_CFB16 static u16 fbcon_cfb16_cmap[16]; @@ -775,12 +890,12 @@ static u16 fbcon_cfb16_cmap[16]; static inline int hxx_prescale(struct falcon_hw *hw) { - return hw->ste_mode ? 16 : - vdl_prescale[mon_type][hw->vid_mode >> 2 & 0x3]; + return hw->ste_mode ? 16 + : vdl_prescale[mon_type][hw->vid_mode >> 2 & 0x3]; } -static int falcon_encode_fix( struct fb_fix_screeninfo *fix, - struct atafb_par *par ) +static int falcon_encode_fix(struct fb_fix_screeninfo *fix, + struct atafb_par *par) { strcpy(fix->id, "Atari Builtin"); fix->smem_start = (unsigned long)real_screen_base; @@ -796,8 +911,7 @@ static int falcon_encode_fix( struct fb_fix_screeninfo *fix, fix->type_aux = 0; /* no smooth scrolling with longword aligned video mem */ fix->xpanstep = 32; - } - else if (par->hw.falcon.f_shift & 0x100) { + } else if (par->hw.falcon.f_shift & 0x100) { fix->type = FB_TYPE_PACKED_PIXELS; fix->type_aux = 0; /* Is this ok or should it be DIRECTCOLOR? */ @@ -809,9 +923,8 @@ static int falcon_encode_fix( struct fb_fix_screeninfo *fix, return 0; } - -static int falcon_decode_var( struct fb_var_screeninfo *var, - struct atafb_par *par ) +static int falcon_decode_var(struct fb_var_screeninfo *var, + struct atafb_par *par) { int bpp = var->bits_per_pixel; int xres = var->xres; @@ -823,17 +936,19 @@ static int falcon_decode_var( struct fb_var_screeninfo *var, int linelen; int interlace = 0, doubleline = 0; struct pixel_clock *pclock; - int plen; /* width of pixel in clock cycles */ + int plen; /* width of pixel in clock cycles */ int xstretch; int prescale; int longoffset = 0; int hfreq, vfreq; + int hdb_off, hde_off, base_off; + int gstart, gend1, gend2, align; /* Get the video params out of 'var'. If a value doesn't fit, round it up, if it's too big, return EINVAL. - Round up in the following order: bits_per_pixel, xres, yres, - xres_virtual, yres_virtual, xoffset, yoffset, grayscale, bitfields, + Round up in the following order: bits_per_pixel, xres, yres, + xres_virtual, yres_virtual, xoffset, yoffset, grayscale, bitfields, horizontal timing, vertical timing. There is a maximum of screen resolution determined by pixelclock @@ -843,11 +958,11 @@ static int falcon_decode_var( struct fb_var_screeninfo *var, Frequency range for multisync monitors is given via command line. For TV and SM124 both frequencies are fixed. - X % 16 == 0 to fit 8x?? font (except 1 bitplane modes must use X%32==0) + X % 16 == 0 to fit 8x?? font (except 1 bitplane modes must use X%32 == 0) Y % 16 == 0 to fit 8x16 font Y % 8 == 0 if Y<400 - Currently interlace and doubleline mode in var are ignored. + Currently interlace and doubleline mode in var are ignored. On SM124 and TV only the standard resolutions can be used. */ @@ -855,43 +970,38 @@ static int falcon_decode_var( struct fb_var_screeninfo *var, if (!xres || !yres || !bpp) return -EINVAL; - if (mon_type == F_MON_SM && bpp != 1) { + if (mon_type == F_MON_SM && bpp != 1) return -EINVAL; - } - else if (bpp <= 1) { + + if (bpp <= 1) { bpp = 1; par->hw.falcon.f_shift = 0x400; par->hw.falcon.st_shift = 0x200; - } - else if (bpp <= 2) { + } else if (bpp <= 2) { bpp = 2; par->hw.falcon.f_shift = 0x000; par->hw.falcon.st_shift = 0x100; - } - else if (bpp <= 4) { + } else if (bpp <= 4) { bpp = 4; par->hw.falcon.f_shift = 0x000; par->hw.falcon.st_shift = 0x000; - } - else if (bpp <= 8) { + } else if (bpp <= 8) { bpp = 8; par->hw.falcon.f_shift = 0x010; - } - else if (bpp <= 16) { - bpp = 16; /* packed pixel mode */ - par->hw.falcon.f_shift = 0x100; /* hicolor, no overlay */ - } - else + } else if (bpp <= 16) { + bpp = 16; /* packed pixel mode */ + par->hw.falcon.f_shift = 0x100; /* hicolor, no overlay */ + } else return -EINVAL; par->hw.falcon.bpp = bpp; if (mon_type == F_MON_SM || DontCalcRes) { /* Skip all calculations. VGA/TV/SC1224 only supported. */ struct fb_var_screeninfo *myvar = &atafb_predefined[0]; - + if (bpp > myvar->bits_per_pixel || - var->xres > myvar->xres || - var->yres > myvar->yres) + var->xres > myvar->xres || + var->yres > myvar->yres) return -EINVAL; fbhw->get_par(par); /* Current par will be new par */ goto set_screen_base; /* Don't forget this */ @@ -910,8 +1020,8 @@ static int falcon_decode_var( struct fb_var_screeninfo *var, yres = 400; /* 2 planes must use STE compatibility mode */ - par->hw.falcon.ste_mode = bpp==2; - par->hw.falcon.mono = bpp==1; + par->hw.falcon.ste_mode = bpp == 2; + par->hw.falcon.mono = bpp == 1; /* Total and visible scanline length must be a multiple of one longword, * this and the console fontwidth yields the alignment for xres and @@ -967,8 +1077,7 @@ static int falcon_decode_var( struct fb_var_screeninfo *var, left_margin = hsync_len = 128 / plen; right_margin = 0; /* TODO set all margins */ - } - else + } else #endif if (mon_type == F_MON_SC || mon_type == F_MON_TV) { plen = 2 * xstretch; @@ -1002,26 +1111,24 @@ static int falcon_decode_var( struct fb_var_screeninfo *var, vsync_len *= 2; } } - } - else - { /* F_MON_VGA */ + } else { /* F_MON_VGA */ if (bpp == 16) - xstretch = 2; /* Double pixel width only for hicolor */ + xstretch = 2; /* Double pixel width only for hicolor */ /* Default values are used for vert./hor. timing if no pixelclock given. */ if (var->pixclock == 0) { int linesize; /* Choose master pixelclock depending on hor. timing */ plen = 1 * xstretch; - if ((plen * xres + f25.right+f25.hsync+f25.left) * + if ((plen * xres + f25.right + f25.hsync + f25.left) * fb_info.monspecs.hfmin < f25.f) pclock = &f25; - else if ((plen * xres + f32.right+f32.hsync+f32.left) * - fb_info.monspecs.hfmin < f32.f) + else if ((plen * xres + f32.right + f32.hsync + + f32.left) * fb_info.monspecs.hfmin < f32.f) pclock = &f32; - else if ((plen * xres + fext.right+fext.hsync+fext.left) * - fb_info.monspecs.hfmin < fext.f - && fext.f) + else if ((plen * xres + fext.right + fext.hsync + + fext.left) * fb_info.monspecs.hfmin < fext.f && + fext.f) pclock = &fext; else return -EINVAL; @@ -1033,22 +1140,24 @@ static int falcon_decode_var( struct fb_var_screeninfo *var, upper_margin = 31; lower_margin = 11; vsync_len = 3; - } - else { + } else { /* Choose largest pixelclock <= wanted clock */ int i; unsigned long pcl = ULONG_MAX; pclock = 0; - for (i=1; i <= 4; i *= 2) { - if (f25.t*i >= var->pixclock && f25.t*i < pcl) { + for (i = 1; i <= 4; i *= 2) { + if (f25.t * i >= var->pixclock && + f25.t * i < pcl) { pcl = f25.t * i; pclock = &f25; } - if (f32.t*i >= var->pixclock && f32.t*i < pcl) { + if (f32.t * i >= var->pixclock && + f32.t * i < pcl) { pcl = f32.t * i; pclock = &f32; } - if (fext.t && fext.t*i >= var->pixclock && fext.t*i < pcl) { + if (fext.t && fext.t * i >= var->pixclock && + fext.t * i < pcl) { pcl = fext.t * i; pclock = &fext; } @@ -1070,8 +1179,7 @@ static int falcon_decode_var( struct fb_var_screeninfo *var, upper_margin = (upper_margin + 1) / 2; lower_margin = (lower_margin + 1) / 2; vsync_len = (vsync_len + 1) / 2; - } - else if (var->vmode & FB_VMODE_DOUBLE) { + } else if (var->vmode & FB_VMODE_DOUBLE) { /* External unit is [double lines per frame] */ upper_margin *= 2; lower_margin *= 2; @@ -1079,7 +1187,7 @@ static int falcon_decode_var( struct fb_var_screeninfo *var, } } if (pclock == &fext) - longoffset = 1; /* VIDEL doesn't synchronize on short offset */ + longoffset = 1; /* VIDEL doesn't synchronize on short offset */ } /* Is video bus bandwidth (32MB/s) too low for this resolution? */ /* this is definitely wrong if bus clock != 32MHz */ @@ -1098,7 +1206,7 @@ static int falcon_decode_var( struct fb_var_screeninfo *var, * between interlace and non-interlace without messing around * with these. */ - again: +again: /* Set base_offset 128 and video bus width */ par->hw.falcon.vid_control = mon_type | f030_bus_width; if (!longoffset) @@ -1112,37 +1220,34 @@ static int falcon_decode_var( struct fb_var_screeninfo *var, /* External or internal clock */ par->hw.falcon.sync = pclock->sync_mask | 0x2; /* Pixellength and prescale */ - par->hw.falcon.vid_mode = (2/plen) << 2; + par->hw.falcon.vid_mode = (2 / plen) << 2; if (doubleline) par->hw.falcon.vid_mode |= VMO_DOUBLE; if (interlace) par->hw.falcon.vid_mode |= VMO_INTER; /********************* - Horizontal timing: unit = [master clock cycles] - unit of hxx-registers: [master clock cycles * prescale] - Hxx-registers are 9 bit wide - - 1 line = ((hht + 2) * 2 * prescale) clock cycles - - graphic output = hdb & 0x200 ? - ((hht+2)*2 - hdb + hde) * prescale - hdboff + hdeoff: - ( hht + 2 - hdb + hde) * prescale - hdboff + hdeoff - (this must be a multiple of plen*128/bpp, on VGA pixels - to the right may be cut off with a bigger right margin) - - start of graphics relative to start of 1st halfline = hdb & 0x200 ? - (hdb - hht - 2) * prescale + hdboff : - hdb * prescale + hdboff - - end of graphics relative to start of 1st halfline = - (hde + hht + 2) * prescale + hdeoff - *********************/ + * Horizontal timing: unit = [master clock cycles] + * unit of hxx-registers: [master clock cycles * prescale] + * Hxx-registers are 9 bit wide + * + * 1 line = ((hht + 2) * 2 * prescale) clock cycles + * + * graphic output = hdb & 0x200 ? + * ((hht + 2) * 2 - hdb + hde) * prescale - hdboff + hdeoff: + * (hht + 2 - hdb + hde) * prescale - hdboff + hdeoff + * (this must be a multiple of plen*128/bpp, on VGA pixels + * to the right may be cut off with a bigger right margin) + * + * start of graphics relative to start of 1st halfline = hdb & 0x200 ? + * (hdb - hht - 2) * prescale + hdboff : + * hdb * prescale + hdboff + * + * end of graphics relative to start of 1st halfline = + * (hde + hht + 2) * prescale + hdeoff + *********************/ /* Calculate VIDEL registers */ - { - int hdb_off, hde_off, base_off; - int gstart, gend1, gend2, align; - +{ prescale = hxx_prescale(&par->hw.falcon); base_off = par->hw.falcon.vid_control & VCO_SHORTOFFS ? 64 : 128; @@ -1154,8 +1259,7 @@ static int falcon_decode_var( struct fb_var_screeninfo *var, align = 1; hde_off = 0; hdb_off = (base_off + 16 * plen) + prescale; - } - else { + } else { align = 128 / bpp; hde_off = ((128 / bpp + 2) * plen); if (par->hw.falcon.ste_mode) @@ -1164,23 +1268,24 @@ static int falcon_decode_var( struct fb_var_screeninfo *var, hdb_off = (base_off + (128 / bpp + 18) * plen) + prescale; } - gstart = (prescale/2 + plen * left_margin) / prescale; + gstart = (prescale / 2 + plen * left_margin) / prescale; /* gend1 is for hde (gend-gstart multiple of align), shifter's xres */ - gend1 = gstart + ((xres + align-1) / align)*align * plen / prescale; + gend1 = gstart + ((xres + align - 1) / align) * align * plen / prescale; /* gend2 is for hbb, visible xres (rest to gend1 is cut off by hblank) */ gend2 = gstart + xres * plen / prescale; par->HHT = plen * (left_margin + xres + right_margin) / (2 * prescale) - 2; /* par->HHT = (gend2 + plen * right_margin / prescale) / 2 - 2;*/ - par->HDB = gstart - hdb_off/prescale; + par->HDB = gstart - hdb_off / prescale; par->HBE = gstart; - if (par->HDB < 0) par->HDB += par->HHT + 2 + 0x200; - par->HDE = gend1 - par->HHT - 2 - hde_off/prescale; + if (par->HDB < 0) + par->HDB += par->HHT + 2 + 0x200; + par->HDE = gend1 - par->HHT - 2 - hde_off / prescale; par->HBB = gend2 - par->HHT - 2; #if 0 /* One more Videl constraint: data fetch of two lines must not overlap */ - if ((par->HDB & 0x200) && (par->HDB & ~0x200) - par->HDE <= 5) { + if ((par->HDB & 0x200) && (par->HDB & ~0x200) - par->HDE <= 5) { /* if this happens increase margins, decrease hfreq. */ } #endif @@ -1189,11 +1294,11 @@ static int falcon_decode_var( struct fb_var_screeninfo *var, par->HSS = par->HHT + 2 - plen * hsync_len / prescale; if (par->HSS < par->HBB) par->HSS = par->HBB; - } +} /* check hor. frequency */ - hfreq = pclock->f / ((par->HHT+2)*prescale*2); - if (hfreq > fb_info.monspecs.hfmax && mon_type!=F_MON_VGA) { + hfreq = pclock->f / ((par->HHT + 2) * prescale * 2); + if (hfreq > fb_info.monspecs.hfmax && mon_type != F_MON_VGA) { /* ++guenther: ^^^^^^^^^^^^^^^^^^^ can't remember why I did this */ /* Too high -> enlarge margin */ left_margin += 1; @@ -1213,12 +1318,14 @@ static int falcon_decode_var( struct fb_var_screeninfo *var, par->VBE = (upper_margin * 2 + 1); /* must begin on odd halfline */ par->VDB = par->VBE; par->VDE = yres; - if (!interlace) par->VDE <<= 1; - if (doubleline) par->VDE <<= 1; /* VDE now half lines per (half-)frame */ + if (!interlace) + par->VDE <<= 1; + if (doubleline) + par->VDE <<= 1; /* VDE now half lines per (half-)frame */ par->VDE += par->VDB; par->VBB = par->VDE; par->VFT = par->VBB + (lower_margin * 2 - 1) - 1; - par->VSS = par->VFT+1 - (vsync_len * 2 - 1); + par->VSS = par->VFT + 1 - (vsync_len * 2 - 1); /* vbb,vss,vft must be even in interlace mode */ if (interlace) { par->VBB++; @@ -1229,55 +1336,53 @@ static int falcon_decode_var( struct fb_var_screeninfo *var, /* V-frequency check, hope I didn't create any loop here. */ /* Interlace and doubleline are mutually exclusive. */ vfreq = (hfreq * 2) / (par->VFT + 1); - if (vfreq > fb_info.monspecs.vfmax && !doubleline && !interlace) { + if (vfreq > fb_info.monspecs.vfmax && !doubleline && !interlace) { /* Too high -> try again with doubleline */ doubleline = 1; goto again; - } - else if (vfreq < fb_info.monspecs.vfmin && !interlace && !doubleline) { + } else if (vfreq < fb_info.monspecs.vfmin && !interlace && !doubleline) { /* Too low -> try again with interlace */ interlace = 1; goto again; - } - else if (vfreq < fb_info.monspecs.vfmin && doubleline) { + } else if (vfreq < fb_info.monspecs.vfmin && doubleline) { /* Doubleline too low -> clear doubleline and enlarge margins */ int lines; doubleline = 0; - for (lines=0; - (hfreq*2)/(par->VFT+1+4*lines-2*yres)>fb_info.monspecs.vfmax; + for (lines = 0; + (hfreq * 2) / (par->VFT + 1 + 4 * lines - 2 * yres) > + fb_info.monspecs.vfmax; lines++) ; upper_margin += lines; lower_margin += lines; goto again; - } - else if (vfreq > fb_info.monspecs.vfmax && doubleline) { + } else if (vfreq > fb_info.monspecs.vfmax && doubleline) { /* Doubleline too high -> enlarge margins */ int lines; - for (lines=0; - (hfreq*2)/(par->VFT+1+4*lines)>fb_info.monspecs.vfmax; - lines+=2) + for (lines = 0; + (hfreq * 2) / (par->VFT + 1 + 4 * lines) > + fb_info.monspecs.vfmax; + lines += 2) ; upper_margin += lines; lower_margin += lines; goto again; - } - else if (vfreq > fb_info.monspecs.vfmax && interlace) { + } else if (vfreq > fb_info.monspecs.vfmax && interlace) { /* Interlace, too high -> enlarge margins */ int lines; - for (lines=0; - (hfreq*2)/(par->VFT+1+4*lines)>fb_info.monspecs.vfmax; + for (lines = 0; + (hfreq * 2) / (par->VFT + 1 + 4 * lines) > + fb_info.monspecs.vfmax; lines++) ; upper_margin += lines; lower_margin += lines; goto again; - } - else if (vfreq < fb_info.monspecs.vfmin || - vfreq > fb_info.monspecs.vfmax) + } else if (vfreq < fb_info.monspecs.vfmin || + vfreq > fb_info.monspecs.vfmax) return -EINVAL; - set_screen_base: +set_screen_base: linelen = xres_virtual * bpp / 8; if (yres_virtual * linelen > screen_len && screen_len) return -EINVAL; @@ -1289,11 +1394,20 @@ static int falcon_decode_var( struct fb_var_screeninfo *var, par->screen_base = screen_base + var->yoffset * linelen; par->hw.falcon.xoffset = 0; + // FIXME!!! sort of works, no crash + //par->next_line = linelen; + //par->next_plane = yres_virtual * linelen; + par->next_line = linelen; + par->next_plane = 2; + // crashes + //par->next_plane = linelen; + //par->next_line = yres_virtual * linelen; + return 0; } -static int falcon_encode_var( struct fb_var_screeninfo *var, - struct atafb_par *par ) +static int falcon_encode_var(struct fb_var_screeninfo *var, + struct atafb_par *par) { /* !!! only for VGA !!! */ int linelen; @@ -1306,10 +1420,10 @@ static int falcon_encode_var( struct fb_var_screeninfo *var, var->pixclock = hw->sync & 0x1 ? fext.t : hw->vid_control & VCO_CLOCK25 ? f25.t : f32.t; - var->height=-1; - var->width=-1; + var->height = -1; + var->width = -1; - var->sync=0; + var->sync = 0; if (hw->vid_control & VCO_HSYPOS) var->sync |= FB_SYNC_HOR_HIGH_ACT; if (hw->vid_control & VCO_VSYPOS) @@ -1320,7 +1434,7 @@ static int falcon_encode_var( struct fb_var_screeninfo *var, var->vmode |= FB_VMODE_INTERLACED; if (hw->vid_mode & VMO_DOUBLE) var->vmode |= FB_VMODE_DOUBLE; - + /* visible y resolution: * Graphics display starts at line VDB and ends at line * VDE. If interlace mode off unit of VC-registers is @@ -1332,14 +1446,15 @@ static int falcon_encode_var( struct fb_var_screeninfo *var, if (var->vmode & FB_VMODE_DOUBLE) var->yres >>= 1; - /* to get bpp, we must examine f_shift and st_shift. + /* + * to get bpp, we must examine f_shift and st_shift. * f_shift is valid if any of bits no. 10, 8 or 4 * is set. Priority in f_shift is: 10 ">" 8 ">" 4, i.e. * if bit 10 set then bit 8 and bit 4 don't care... * If all these bits are 0 get display depth from st_shift * (as for ST and STE) */ - if (hw->f_shift & 0x400) /* 2 colors */ + if (hw->f_shift & 0x400) /* 2 colors */ var->bits_per_pixel = 1; else if (hw->f_shift & 0x100) /* hicolor */ var->bits_per_pixel = 16; @@ -1349,7 +1464,7 @@ static int falcon_encode_var( struct fb_var_screeninfo *var, var->bits_per_pixel = 4; else if (hw->st_shift == 0x100) var->bits_per_pixel = 2; - else /* if (hw->st_shift == 0x200) */ + else /* if (hw->st_shift == 0x200) */ var->bits_per_pixel = 1; var->xres = hw->line_width * 16 / var->bits_per_pixel; @@ -1358,42 +1473,42 @@ static int falcon_encode_var( struct fb_var_screeninfo *var, var->xres_virtual += 16; if (var->bits_per_pixel == 16) { - var->red.offset=11; - var->red.length=5; - var->red.msb_right=0; - var->green.offset=5; - var->green.length=6; - var->green.msb_right=0; - var->blue.offset=0; - var->blue.length=5; - var->blue.msb_right=0; - } - else { - var->red.offset=0; + var->red.offset = 11; + var->red.length = 5; + var->red.msb_right = 0; + var->green.offset = 5; + var->green.length = 6; + var->green.msb_right = 0; + var->blue.offset = 0; + var->blue.length = 5; + var->blue.msb_right = 0; + } else { + var->red.offset = 0; var->red.length = hw->ste_mode ? 4 : 6; - var->red.msb_right=0; - var->grayscale=0; - var->blue=var->green=var->red; + if (var->red.length > var->bits_per_pixel) + var->red.length = var->bits_per_pixel; + var->red.msb_right = 0; + var->grayscale = 0; + var->blue = var->green = var->red; } - var->transp.offset=0; - var->transp.length=0; - var->transp.msb_right=0; + var->transp.offset = 0; + var->transp.length = 0; + var->transp.msb_right = 0; linelen = var->xres_virtual * var->bits_per_pixel / 8; if (screen_len) { if (par->yres_virtual) var->yres_virtual = par->yres_virtual; else - /* yres_virtual==0 means use maximum */ + /* yres_virtual == 0 means use maximum */ var->yres_virtual = screen_len / linelen; - } - else { + } else { if (hwscroll < 0) var->yres_virtual = 2 * var->yres; else - var->yres_virtual=var->yres+hwscroll * 16; + var->yres_virtual = var->yres + hwscroll * 16; } - var->xoffset=0; /* TODO change this */ + var->xoffset = 0; /* TODO change this */ /* hdX-offsets */ prescale = hxx_prescale(hw); @@ -1402,8 +1517,7 @@ static int falcon_encode_var( struct fb_var_screeninfo *var, if (hw->f_shift & 0x100) { hde_off = 0; hdb_off = (base_off + 16 * plen) + prescale; - } - else { + } else { hde_off = ((128 / var->bits_per_pixel + 2) * plen); if (hw->ste_mode) hdb_off = (64 + base_off + (128 / var->bits_per_pixel + 2) * plen) @@ -1415,8 +1529,8 @@ static int falcon_encode_var( struct fb_var_screeninfo *var, /* Right margin includes hsync */ var->left_margin = hdb_off + prescale * ((hw->hdb & 0x1ff) - - (hw->hdb & 0x200 ? 2+hw->hht : 0)); - if (hw->ste_mode || mon_type!=F_MON_VGA) + (hw->hdb & 0x200 ? 2 + hw->hht : 0)); + if (hw->ste_mode || mon_type != F_MON_VGA) var->right_margin = prescale * (hw->hht + 2 - hw->hde) - hde_off; else /* can't use this in ste_mode, because hbb is +1 off */ @@ -1424,15 +1538,14 @@ static int falcon_encode_var( struct fb_var_screeninfo *var, var->hsync_len = prescale * (hw->hht + 2 - hw->hss); /* Lower margin includes vsync */ - var->upper_margin = hw->vdb / 2 ; /* round down to full lines */ - var->lower_margin = (hw->vft+1 - hw->vde + 1) / 2; /* round up */ - var->vsync_len = (hw->vft+1 - hw->vss + 1) / 2; /* round up */ + var->upper_margin = hw->vdb / 2; /* round down to full lines */ + var->lower_margin = (hw->vft + 1 - hw->vde + 1) / 2; /* round up */ + var->vsync_len = (hw->vft + 1 - hw->vss + 1) / 2; /* round up */ if (var->vmode & FB_VMODE_INTERLACED) { var->upper_margin *= 2; var->lower_margin *= 2; var->vsync_len *= 2; - } - else if (var->vmode & FB_VMODE_DOUBLE) { + } else if (var->vmode & FB_VMODE_DOUBLE) { var->upper_margin = (var->upper_margin + 1) / 2; var->lower_margin = (var->lower_margin + 1) / 2; var->vsync_len = (var->vsync_len + 1) / 2; @@ -1447,20 +1560,19 @@ static int falcon_encode_var( struct fb_var_screeninfo *var, var->lower_margin -= var->vsync_len; if (screen_base) - var->yoffset=(par->screen_base - screen_base)/linelen; + var->yoffset = (par->screen_base - screen_base) / linelen; else - var->yoffset=0; - var->nonstd=0; /* what is this for? */ - var->activate=0; + var->yoffset = 0; + var->nonstd = 0; /* what is this for? */ + var->activate = 0; return 0; } - -static int f_change_mode = 0; +static int f_change_mode; static struct falcon_hw f_new_mode; -static int f_pan_display = 0; +static int f_pan_display; -static void falcon_get_par( struct atafb_par *par ) +static void falcon_get_par(struct atafb_par *par) { unsigned long addr; struct falcon_hw *hw = &par->hw.falcon; @@ -1492,12 +1604,12 @@ static void falcon_get_par( struct atafb_par *par ) par->screen_base = phys_to_virt(addr); /* derived parameters */ - hw->ste_mode = (hw->f_shift & 0x510)==0 && hw->st_shift==0x100; + hw->ste_mode = (hw->f_shift & 0x510) == 0 && hw->st_shift == 0x100; hw->mono = (hw->f_shift & 0x400) || - ((hw->f_shift & 0x510)==0 && hw->st_shift==0x200); + ((hw->f_shift & 0x510) == 0 && hw->st_shift == 0x200); } -static void falcon_set_par( struct atafb_par *par ) +static void falcon_set_par(struct atafb_par *par) { f_change_mode = 0; @@ -1519,8 +1631,7 @@ static void falcon_set_par( struct atafb_par *par ) f_change_mode = 1; } - -static irqreturn_t falcon_vbl_switcher( int irq, void *dummy ) +static irqreturn_t falcon_vbl_switcher(int irq, void *dummy) { struct falcon_hw *hw = &f_new_mode; @@ -1529,11 +1640,10 @@ static irqreturn_t falcon_vbl_switcher( int irq, void *dummy ) if (hw->sync & 0x1) { /* Enable external pixelclock. This code only for ScreenWonder */ - *(volatile unsigned short*)0xffff9202 = 0xffbf; - } - else { + *(volatile unsigned short *)0xffff9202 = 0xffbf; + } else { /* Turn off external clocks. Read sets all output bits to 1. */ - *(volatile unsigned short*)0xffff9202; + *(volatile unsigned short *)0xffff9202; } shifter.syncmode = hw->sync; @@ -1550,15 +1660,14 @@ static irqreturn_t falcon_vbl_switcher( int irq, void *dummy ) videl.vde = hw->vde; videl.vss = hw->vss; - videl.f_shift = 0; /* write enables Falcon palette, 0: 4 planes */ + videl.f_shift = 0; /* write enables Falcon palette, 0: 4 planes */ if (hw->ste_mode) { - videl.st_shift = hw->st_shift; /* write enables STE palette */ - } - else { + videl.st_shift = hw->st_shift; /* write enables STE palette */ + } else { /* IMPORTANT: - * set st_shift 0, so we can tell the screen-depth if f_shift==0. + * set st_shift 0, so we can tell the screen-depth if f_shift == 0. * Writing 0 to f_shift enables 4 plane Falcon mode but - * doesn't set st_shift. st_shift!=0 (!=4planes) is impossible + * doesn't set st_shift. st_shift != 0 (!= 4planes) is impossible * with Falcon palette. */ videl.st_shift = 0; @@ -1580,12 +1689,13 @@ static irqreturn_t falcon_vbl_switcher( int irq, void *dummy ) return IRQ_HANDLED; } - -static int falcon_pan_display( struct fb_var_screeninfo *var, - struct atafb_par *par ) +static int falcon_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) { + struct atafb_par *par = (struct atafb_par *)info->par; + int xoffset; - int bpp = fb_display[fb_info.currcon].var.bits_per_pixel; + int bpp = info->var.bits_per_pixel; if (bpp == 1) var->xoffset = up(var->xoffset, 32); @@ -1596,45 +1706,24 @@ static int falcon_pan_display( struct fb_var_screeninfo *var, var->xoffset = up(var->xoffset, 2); } par->hw.falcon.line_offset = bpp * - (fb_display[fb_info.currcon].var.xres_virtual - fb_display[fb_info.currcon].var.xres) / 16; + (info->var.xres_virtual - info->var.xres) / 16; if (par->hw.falcon.xoffset) par->hw.falcon.line_offset -= bpp; xoffset = var->xoffset - par->hw.falcon.xoffset; par->screen_base = screen_base + - (var->yoffset * fb_display[fb_info.currcon].var.xres_virtual + xoffset) * bpp / 8; + (var->yoffset * info->var.xres_virtual + xoffset) * bpp / 8; if (fbhw->set_screen_base) - fbhw->set_screen_base (par->screen_base); + fbhw->set_screen_base(par->screen_base); else - return -EINVAL; /* shouldn't happen */ + return -EINVAL; /* shouldn't happen */ f_pan_display = 1; return 0; } - -static int falcon_getcolreg( unsigned regno, unsigned *red, - unsigned *green, unsigned *blue, - unsigned *transp, struct fb_info *info ) -{ unsigned long col; - - if (regno > 255) - return 1; - /* This works in STE-mode (with 4bit/color) since f030_col-registers - * hold up to 6bit/color. - * Even with hicolor r/g/b=5/6/5 bit! - */ - col = f030_col[regno]; - *red = (col >> 16) & 0xff00; - *green = (col >> 8) & 0xff00; - *blue = (col << 8) & 0xff00; - *transp = 0; - return 0; -} - - -static int falcon_setcolreg( unsigned regno, unsigned red, - unsigned green, unsigned blue, - unsigned transp, struct fb_info *info ) +static int falcon_setcolreg(unsigned int regno, unsigned int red, + unsigned int green, unsigned int blue, + unsigned int transp, struct fb_info *info) { if (regno > 255) return 1; @@ -1655,13 +1744,12 @@ static int falcon_setcolreg( unsigned regno, unsigned red, return 0; } - -static int falcon_blank( int blank_mode ) +static int falcon_blank(int blank_mode) { -/* ++guenther: we can switch off graphics by changing VDB and VDE, - * so VIDEL doesn't hog the bus while saving. - * (this may affect usleep()). - */ + /* ++guenther: we can switch off graphics by changing VDB and VDE, + * so VIDEL doesn't hog the bus while saving. + * (this may affect usleep()). + */ int vdb, vss, hbe, hss; if (mon_type == F_MON_SM) /* this doesn't work on SM124 */ @@ -1694,14 +1782,13 @@ static int falcon_blank( int blank_mode ) return 0; } - -static int falcon_detect( void ) +static int falcon_detect(void) { struct atafb_par par; unsigned char fhw; /* Determine connected monitor and set monitor parameters */ - fhw = *(unsigned char*)0xffff8006; + fhw = *(unsigned char *)0xffff8006; mon_type = fhw >> 6 & 0x3; /* bit 1 of fhw: 1=32 bit ram bus, 0=16 bit */ f030_bus_width = fhw << 6 & 0x80; @@ -1715,7 +1802,7 @@ static int falcon_detect( void ) case F_MON_SC: case F_MON_TV: /* PAL...NTSC */ - fb_info.monspecs.vfmin = 49; /* not 50, since TOS defaults to 49.9x Hz */ + fb_info.monspecs.vfmin = 49; /* not 50, since TOS defaults to 49.9x Hz */ fb_info.monspecs.vfmax = 60; fb_info.monspecs.hfmin = 15620; fb_info.monspecs.hfmax = 15755; @@ -1740,13 +1827,12 @@ static int falcon_detect( void ) #ifdef ATAFB_STE -static int stste_encode_fix( struct fb_fix_screeninfo *fix, - struct atafb_par *par ) - +static int stste_encode_fix(struct fb_fix_screeninfo *fix, + struct atafb_par *par) { int mode; - strcpy(fix->id,"Atari Builtin"); + strcpy(fix->id, "Atari Builtin"); fix->smem_start = (unsigned long)real_screen_base; fix->smem_len = screen_len; fix->type = FB_TYPE_INTERLEAVED_PLANES; @@ -1771,43 +1857,40 @@ static int stste_encode_fix( struct fb_fix_screeninfo *fix, return 0; } - -static int stste_decode_var( struct fb_var_screeninfo *var, - struct atafb_par *par ) +static int stste_decode_var(struct fb_var_screeninfo *var, + struct atafb_par *par) { - int xres=var->xres; - int yres=var->yres; - int bpp=var->bits_per_pixel; + int xres = var->xres; + int yres = var->yres; + int bpp = var->bits_per_pixel; int linelen; int yres_virtual = var->yres_virtual; if (mono_moni) { if (bpp > 1 || xres > sttt_xres || yres > st_yres) return -EINVAL; - par->hw.st.mode=ST_HIGH; - xres=sttt_xres; - yres=st_yres; - bpp=1; + par->hw.st.mode = ST_HIGH; + xres = sttt_xres; + yres = st_yres; + bpp = 1; } else { if (bpp > 4 || xres > sttt_xres || yres > st_yres) return -EINVAL; if (bpp > 2) { - if (xres > sttt_xres/2 || yres > st_yres/2) + if (xres > sttt_xres / 2 || yres > st_yres / 2) return -EINVAL; - par->hw.st.mode=ST_LOW; - xres=sttt_xres/2; - yres=st_yres/2; - bpp=4; - } - else if (bpp > 1) { - if (xres > sttt_xres || yres > st_yres/2) + par->hw.st.mode = ST_LOW; + xres = sttt_xres / 2; + yres = st_yres / 2; + bpp = 4; + } else if (bpp > 1) { + if (xres > sttt_xres || yres > st_yres / 2) return -EINVAL; - par->hw.st.mode=ST_MID; - xres=sttt_xres; - yres=st_yres/2; - bpp=2; - } - else + par->hw.st.mode = ST_MID; + xres = sttt_xres; + yres = st_yres / 2; + bpp = 2; + } else return -EINVAL; } if (yres_virtual <= 0) @@ -1815,10 +1898,10 @@ static int stste_decode_var( struct fb_var_screeninfo *var, else if (yres_virtual < yres) yres_virtual = yres; if (var->sync & FB_SYNC_EXT) - par->hw.st.sync=(par->hw.st.sync & ~1) | 1; + par->hw.st.sync = (par->hw.st.sync & ~1) | 1; else - par->hw.st.sync=(par->hw.st.sync & ~1); - linelen=xres*bpp/8; + par->hw.st.sync = (par->hw.st.sync & ~1); + linelen = xres * bpp / 8; if (yres_virtual * linelen > screen_len && screen_len) return -EINVAL; if (yres * linelen > screen_len && screen_len) @@ -1826,93 +1909,91 @@ static int stste_decode_var( struct fb_var_screeninfo *var, if (var->yoffset + yres > yres_virtual && yres_virtual) return -EINVAL; par->yres_virtual = yres_virtual; - par->screen_base=screen_base+ var->yoffset*linelen; + par->screen_base = screen_base + var->yoffset * linelen; return 0; } -static int stste_encode_var( struct fb_var_screeninfo *var, - struct atafb_par *par ) +static int stste_encode_var(struct fb_var_screeninfo *var, + struct atafb_par *par) { int linelen; memset(var, 0, sizeof(struct fb_var_screeninfo)); - var->red.offset=0; + var->red.offset = 0; var->red.length = ATARIHW_PRESENT(EXTD_SHIFTER) ? 4 : 3; - var->red.msb_right=0; - var->grayscale=0; + var->red.msb_right = 0; + var->grayscale = 0; - var->pixclock=31041; - var->left_margin=120; /* these are incorrect */ - var->right_margin=100; - var->upper_margin=8; - var->lower_margin=16; - var->hsync_len=140; - var->vsync_len=30; + var->pixclock = 31041; + var->left_margin = 120; /* these are incorrect */ + var->right_margin = 100; + var->upper_margin = 8; + var->lower_margin = 16; + var->hsync_len = 140; + var->vsync_len = 30; - var->height=-1; - var->width=-1; + var->height = -1; + var->width = -1; if (!(par->hw.st.sync & 1)) - var->sync=0; + var->sync = 0; else - var->sync=FB_SYNC_EXT; + var->sync = FB_SYNC_EXT; switch (par->hw.st.mode & 3) { case ST_LOW: - var->xres=sttt_xres/2; - var->yres=st_yres/2; - var->bits_per_pixel=4; + var->xres = sttt_xres / 2; + var->yres = st_yres / 2; + var->bits_per_pixel = 4; break; case ST_MID: - var->xres=sttt_xres; - var->yres=st_yres/2; - var->bits_per_pixel=2; + var->xres = sttt_xres; + var->yres = st_yres / 2; + var->bits_per_pixel = 2; break; case ST_HIGH: - var->xres=sttt_xres; - var->yres=st_yres; - var->bits_per_pixel=1; + var->xres = sttt_xres; + var->yres = st_yres; + var->bits_per_pixel = 1; break; - } - var->blue=var->green=var->red; - var->transp.offset=0; - var->transp.length=0; - var->transp.msb_right=0; - var->xres_virtual=sttt_xres_virtual; - linelen=var->xres_virtual * var->bits_per_pixel / 8; - ovsc_addlen=linelen*(sttt_yres_virtual - st_yres); - - if (! use_hwscroll) - var->yres_virtual=var->yres; + } + var->blue = var->green = var->red; + var->transp.offset = 0; + var->transp.length = 0; + var->transp.msb_right = 0; + var->xres_virtual = sttt_xres_virtual; + linelen = var->xres_virtual * var->bits_per_pixel / 8; + ovsc_addlen = linelen * (sttt_yres_virtual - st_yres); + + if (!use_hwscroll) + var->yres_virtual = var->yres; else if (screen_len) { if (par->yres_virtual) var->yres_virtual = par->yres_virtual; else - /* yres_virtual==0 means use maximum */ + /* yres_virtual == 0 means use maximum */ var->yres_virtual = screen_len / linelen; - } - else { + } else { if (hwscroll < 0) var->yres_virtual = 2 * var->yres; else - var->yres_virtual=var->yres+hwscroll * 16; + var->yres_virtual = var->yres + hwscroll * 16; } - var->xoffset=0; + var->xoffset = 0; if (screen_base) - var->yoffset=(par->screen_base - screen_base)/linelen; + var->yoffset = (par->screen_base - screen_base) / linelen; else - var->yoffset=0; - var->nonstd=0; - var->activate=0; - var->vmode=FB_VMODE_NONINTERLACED; + var->yoffset = 0; + var->nonstd = 0; + var->activate = 0; + var->vmode = FB_VMODE_NONINTERLACED; return 0; } - -static void stste_get_par( struct atafb_par *par ) +static void stste_get_par(struct atafb_par *par) { unsigned long addr; - par->hw.st.mode=shifter_tt.st_shiftmode; - par->hw.st.sync=shifter.syncmode; + par->hw.st.mode = shifter_tt.st_shiftmode; + par->hw.st.sync = shifter.syncmode; addr = ((shifter.bas_hi & 0xff) << 16) | ((shifter.bas_md & 0xff) << 8); if (ATARIHW_PRESENT(EXTD_SHIFTER)) @@ -1920,55 +2001,18 @@ static void stste_get_par( struct atafb_par *par ) par->screen_base = phys_to_virt(addr); } -static void stste_set_par( struct atafb_par *par ) +static void stste_set_par(struct atafb_par *par) { - shifter_tt.st_shiftmode=par->hw.st.mode; - shifter.syncmode=par->hw.st.sync; + shifter_tt.st_shiftmode = par->hw.st.mode; + shifter.syncmode = par->hw.st.sync; /* only set screen_base if really necessary */ if (current_par.screen_base != par->screen_base) fbhw->set_screen_base(par->screen_base); } - -static int stste_getcolreg(unsigned regno, unsigned *red, - unsigned *green, unsigned *blue, - unsigned *transp, struct fb_info *info) -{ - unsigned col, t; - - if (regno > 15) - return 1; - col = shifter_tt.color_reg[regno]; - if (ATARIHW_PRESENT(EXTD_SHIFTER)) { - t = ((col >> 7) & 0xe) | ((col >> 11) & 1); - t |= t << 4; - *red = t | (t << 8); - t = ((col >> 3) & 0xe) | ((col >> 7) & 1); - t |= t << 4; - *green = t | (t << 8); - t = ((col << 1) & 0xe) | ((col >> 3) & 1); - t |= t << 4; - *blue = t | (t << 8); - } - else { - t = (col >> 7) & 0xe; - t |= t << 4; - *red = t | (t << 8); - t = (col >> 3) & 0xe; - t |= t << 4; - *green = t | (t << 8); - t = (col << 1) & 0xe; - t |= t << 4; - *blue = t | (t << 8); - } - *transp = 0; - return 0; -} - - -static int stste_setcolreg(unsigned regno, unsigned red, - unsigned green, unsigned blue, - unsigned transp, struct fb_info *info) +static int stste_setcolreg(unsigned int regno, unsigned int red, + unsigned int green, unsigned int blue, + unsigned int transp, struct fb_info *info) { if (regno > 15) return 1; @@ -1988,10 +2032,9 @@ static int stste_setcolreg(unsigned regno, unsigned red, return 0; } - -static int stste_detect( void ) - -{ struct atafb_par par; +static int stste_detect(void) +{ + struct atafb_par par; /* Determine the connected monitor: The DMA sound must be * disabled before reading the MFP GPIP, because the Sound @@ -1999,7 +2042,7 @@ static int stste_detect( void ) */ if (ATARIHW_PRESENT(PCM_8BIT)) { tt_dmasnd.ctrl = DMASND_CTRL_OFF; - udelay(20); /* wait a while for things to settle down */ + udelay(20); /* wait a while for things to settle down */ } mono_moni = (mfp.par_dt_reg & 0x80) == 0; @@ -2014,12 +2057,12 @@ static int stste_detect( void ) static void stste_set_screen_base(void *s_base) { unsigned long addr; - addr= virt_to_phys(s_base); + addr = virt_to_phys(s_base); /* Setup Screen Memory */ - shifter.bas_hi=(unsigned char) ((addr & 0xff0000) >> 16); - shifter.bas_md=(unsigned char) ((addr & 0x00ff00) >> 8); + shifter.bas_hi = (unsigned char)((addr & 0xff0000) >> 16); + shifter.bas_md = (unsigned char)((addr & 0x00ff00) >> 8); if (ATARIHW_PRESENT(EXTD_SHIFTER)) - shifter.bas_lo=(unsigned char) (addr & 0x0000ff); + shifter.bas_lo = (unsigned char)(addr & 0x0000ff); } #endif /* ATAFB_STE */ @@ -2045,51 +2088,49 @@ static void stste_set_screen_base(void *s_base) /* SWITCH_ACIA may be used for Falcon (ScreenBlaster III internal!) */ static void st_ovsc_switch(void) { - unsigned long flags; - register unsigned char old, new; + unsigned long flags; + register unsigned char old, new; - if (!(atari_switches & ATARI_SWITCH_OVSC_MASK)) - return; - local_irq_save(flags); - - mfp.tim_ct_b = 0x10; - mfp.active_edge |= 8; - mfp.tim_ct_b = 0; - mfp.tim_dt_b = 0xf0; - mfp.tim_ct_b = 8; - while (mfp.tim_dt_b > 1) /* TOS does it this way, don't ask why */ - ; - new = mfp.tim_dt_b; - do { - udelay(LINE_DELAY); - old = new; + if (!(atari_switches & ATARI_SWITCH_OVSC_MASK)) + return; + local_irq_save(flags); + + mfp.tim_ct_b = 0x10; + mfp.active_edge |= 8; + mfp.tim_ct_b = 0; + mfp.tim_dt_b = 0xf0; + mfp.tim_ct_b = 8; + while (mfp.tim_dt_b > 1) /* TOS does it this way, don't ask why */ + ; new = mfp.tim_dt_b; - } while (old != new); - mfp.tim_ct_b = 0x10; - udelay(SYNC_DELAY); - - if (atari_switches & ATARI_SWITCH_OVSC_IKBD) - acia.key_ctrl = ACIA_DIV64 | ACIA_D8N1S | ACIA_RHTID | ACIA_RIE; - if (atari_switches & ATARI_SWITCH_OVSC_MIDI) - acia.mid_ctrl = ACIA_DIV16 | ACIA_D8N1S | ACIA_RHTID; - if (atari_switches & (ATARI_SWITCH_OVSC_SND6|ATARI_SWITCH_OVSC_SND7)) { - sound_ym.rd_data_reg_sel = 14; - sound_ym.wd_data = sound_ym.rd_data_reg_sel | - ((atari_switches&ATARI_SWITCH_OVSC_SND6) ? 0x40:0) | - ((atari_switches&ATARI_SWITCH_OVSC_SND7) ? 0x80:0); - } - local_irq_restore(flags); + do { + udelay(LINE_DELAY); + old = new; + new = mfp.tim_dt_b; + } while (old != new); + mfp.tim_ct_b = 0x10; + udelay(SYNC_DELAY); + + if (atari_switches & ATARI_SWITCH_OVSC_IKBD) + acia.key_ctrl = ACIA_DIV64 | ACIA_D8N1S | ACIA_RHTID | ACIA_RIE; + if (atari_switches & ATARI_SWITCH_OVSC_MIDI) + acia.mid_ctrl = ACIA_DIV16 | ACIA_D8N1S | ACIA_RHTID; + if (atari_switches & (ATARI_SWITCH_OVSC_SND6|ATARI_SWITCH_OVSC_SND7)) { + sound_ym.rd_data_reg_sel = 14; + sound_ym.wd_data = sound_ym.rd_data_reg_sel | + ((atari_switches & ATARI_SWITCH_OVSC_SND6) ? 0x40:0) | + ((atari_switches & ATARI_SWITCH_OVSC_SND7) ? 0x80:0); + } + local_irq_restore(flags); } /* ------------------- External Video ---------------------- */ #ifdef ATAFB_EXT -static int ext_encode_fix( struct fb_fix_screeninfo *fix, - struct atafb_par *par ) - +static int ext_encode_fix(struct fb_fix_screeninfo *fix, struct atafb_par *par) { - strcpy(fix->id,"Unknown Extern"); + strcpy(fix->id, "Unknown Extern"); fix->smem_start = (unsigned long)external_addr; fix->smem_len = PAGE_ALIGN(external_len); if (external_depth == 1) { @@ -2099,31 +2140,29 @@ static int ext_encode_fix( struct fb_fix_screeninfo *fix, fix->visual = (external_pmode == FB_TYPE_INTERLEAVED_PLANES || external_pmode == FB_TYPE_PACKED_PIXELS) ? - FB_VISUAL_MONO10 : - FB_VISUAL_MONO01; - } - else { + FB_VISUAL_MONO10 : FB_VISUAL_MONO01; + } else { /* Use STATIC if we don't know how to access color registers */ int visual = external_vgaiobase ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_STATIC_PSEUDOCOLOR; switch (external_pmode) { - case -1: /* truecolor */ - fix->type=FB_TYPE_PACKED_PIXELS; - fix->visual=FB_VISUAL_TRUECOLOR; + case -1: /* truecolor */ + fix->type = FB_TYPE_PACKED_PIXELS; + fix->visual = FB_VISUAL_TRUECOLOR; break; - case FB_TYPE_PACKED_PIXELS: - fix->type=FB_TYPE_PACKED_PIXELS; - fix->visual=visual; + case FB_TYPE_PACKED_PIXELS: + fix->type = FB_TYPE_PACKED_PIXELS; + fix->visual = visual; break; - case FB_TYPE_PLANES: - fix->type=FB_TYPE_PLANES; - fix->visual=visual; + case FB_TYPE_PLANES: + fix->type = FB_TYPE_PLANES; + fix->visual = visual; break; - case FB_TYPE_INTERLEAVED_PLANES: - fix->type=FB_TYPE_INTERLEAVED_PLANES; - fix->type_aux=2; - fix->visual=visual; + case FB_TYPE_INTERLEAVED_PLANES: + fix->type = FB_TYPE_INTERLEAVED_PLANES; + fix->type_aux = 2; + fix->visual = visual; break; } } @@ -2134,137 +2173,112 @@ static int ext_encode_fix( struct fb_fix_screeninfo *fix, return 0; } - -static int ext_decode_var( struct fb_var_screeninfo *var, - struct atafb_par *par ) +static int ext_decode_var(struct fb_var_screeninfo *var, struct atafb_par *par) { struct fb_var_screeninfo *myvar = &atafb_predefined[0]; - + if (var->bits_per_pixel > myvar->bits_per_pixel || - var->xres > myvar->xres || - var->xres_virtual > myvar->xres_virtual || - var->yres > myvar->yres || - var->xoffset > 0 || - var->yoffset > 0) + var->xres > myvar->xres || + var->xres_virtual > myvar->xres_virtual || + var->yres > myvar->yres || + var->xoffset > 0 || + var->yoffset > 0) return -EINVAL; return 0; } - -static int ext_encode_var( struct fb_var_screeninfo *var, - struct atafb_par *par ) +static int ext_encode_var(struct fb_var_screeninfo *var, struct atafb_par *par) { memset(var, 0, sizeof(struct fb_var_screeninfo)); - var->red.offset=0; - var->red.length=(external_pmode == -1) ? external_depth/3 : + var->red.offset = 0; + var->red.length = (external_pmode == -1) ? external_depth / 3 : (external_vgaiobase ? external_bitspercol : 0); - var->red.msb_right=0; - var->grayscale=0; + var->red.msb_right = 0; + var->grayscale = 0; - var->pixclock=31041; - var->left_margin=120; /* these are surely incorrect */ - var->right_margin=100; - var->upper_margin=8; - var->lower_margin=16; - var->hsync_len=140; - var->vsync_len=30; + var->pixclock = 31041; + var->left_margin = 120; /* these are surely incorrect */ + var->right_margin = 100; + var->upper_margin = 8; + var->lower_margin = 16; + var->hsync_len = 140; + var->vsync_len = 30; - var->height=-1; - var->width=-1; + var->height = -1; + var->width = -1; - var->sync=0; + var->sync = 0; var->xres = external_xres; var->yres = external_yres; var->xres_virtual = external_xres_virtual; var->bits_per_pixel = external_depth; - - var->blue=var->green=var->red; - var->transp.offset=0; - var->transp.length=0; - var->transp.msb_right=0; - var->yres_virtual=var->yres; - var->xoffset=0; - var->yoffset=0; - var->nonstd=0; - var->activate=0; - var->vmode=FB_VMODE_NONINTERLACED; + + var->blue = var->green = var->red; + var->transp.offset = 0; + var->transp.length = 0; + var->transp.msb_right = 0; + var->yres_virtual = var->yres; + var->xoffset = 0; + var->yoffset = 0; + var->nonstd = 0; + var->activate = 0; + var->vmode = FB_VMODE_NONINTERLACED; return 0; } - -static void ext_get_par( struct atafb_par *par ) +static void ext_get_par(struct atafb_par *par) { par->screen_base = external_addr; } -static void ext_set_par( struct atafb_par *par ) +static void ext_set_par(struct atafb_par *par) { } #define OUTB(port,val) \ - *((unsigned volatile char *) ((port)+external_vgaiobase))=(val) + *((unsigned volatile char *) ((port)+external_vgaiobase)) = (val) #define INB(port) \ (*((unsigned volatile char *) ((port)+external_vgaiobase))) -#define DACDelay \ +#define DACDelay \ do { \ - unsigned char tmp=INB(0x3da); \ - tmp=INB(0x3da); \ + unsigned char tmp = INB(0x3da); \ + tmp = INB(0x3da); \ } while (0) -static int ext_getcolreg( unsigned regno, unsigned *red, - unsigned *green, unsigned *blue, - unsigned *transp, struct fb_info *info ) +static int ext_setcolreg(unsigned int regno, unsigned int red, + unsigned int green, unsigned int blue, + unsigned int transp, struct fb_info *info) { - if (! external_vgaiobase) + unsigned char colmask = (1 << external_bitspercol) - 1; + + if (!external_vgaiobase) return 1; - *red = ext_color[regno].red; - *green = ext_color[regno].green; - *blue = ext_color[regno].blue; - *transp=0; - return 0; -} - -static int ext_setcolreg( unsigned regno, unsigned red, - unsigned green, unsigned blue, - unsigned transp, struct fb_info *info ) + switch (external_card_type) { + case IS_VGA: + OUTB(0x3c8, regno); + DACDelay; + OUTB(0x3c9, red & colmask); + DACDelay; + OUTB(0x3c9, green & colmask); + DACDelay; + OUTB(0x3c9, blue & colmask); + DACDelay; + return 0; -{ unsigned char colmask = (1 << external_bitspercol) - 1; + case IS_MV300: + OUTB((MV300_reg[regno] << 2) + 1, red); + OUTB((MV300_reg[regno] << 2) + 1, green); + OUTB((MV300_reg[regno] << 2) + 1, blue); + return 0; - if (! external_vgaiobase) + default: return 1; - - ext_color[regno].red = red; - ext_color[regno].green = green; - ext_color[regno].blue = blue; - - switch (external_card_type) { - case IS_VGA: - OUTB(0x3c8, regno); - DACDelay; - OUTB(0x3c9, red & colmask); - DACDelay; - OUTB(0x3c9, green & colmask); - DACDelay; - OUTB(0x3c9, blue & colmask); - DACDelay; - return 0; - - case IS_MV300: - OUTB((MV300_reg[regno] << 2)+1, red); - OUTB((MV300_reg[regno] << 2)+1, green); - OUTB((MV300_reg[regno] << 2)+1, blue); - return 0; - - default: - return 1; - } + } } - - -static int ext_detect( void ) +static int ext_detect(void) { struct fb_var_screeninfo *myvar = &atafb_predefined[0]; struct atafb_par dummy_par; @@ -2284,213 +2298,182 @@ static int ext_detect( void ) static void set_screen_base(void *s_base) { unsigned long addr; - addr= virt_to_phys(s_base); + + addr = virt_to_phys(s_base); /* Setup Screen Memory */ - shifter.bas_hi=(unsigned char) ((addr & 0xff0000) >> 16); - shifter.bas_md=(unsigned char) ((addr & 0x00ff00) >> 8); - shifter.bas_lo=(unsigned char) (addr & 0x0000ff); + shifter.bas_hi = (unsigned char)((addr & 0xff0000) >> 16); + shifter.bas_md = (unsigned char)((addr & 0x00ff00) >> 8); + shifter.bas_lo = (unsigned char)(addr & 0x0000ff); } - -static int pan_display( struct fb_var_screeninfo *var, - struct atafb_par *par ) +static int pan_display(struct fb_var_screeninfo *var, struct fb_info *info) { + struct atafb_par *par = (struct atafb_par *)info->par; + if (!fbhw->set_screen_base || - (!ATARIHW_PRESENT(EXTD_SHIFTER) && var->xoffset)) + (!ATARIHW_PRESENT(EXTD_SHIFTER) && var->xoffset)) return -EINVAL; var->xoffset = up(var->xoffset, 16); par->screen_base = screen_base + - (var->yoffset * fb_display[fb_info.currcon].var.xres_virtual + var->xoffset) - * fb_display[fb_info.currcon].var.bits_per_pixel / 8; - fbhw->set_screen_base (par->screen_base); + (var->yoffset * info->var.xres_virtual + var->xoffset) + * info->var.bits_per_pixel / 8; + fbhw->set_screen_base(par->screen_base); return 0; } - /* ------------ Interfaces to hardware functions ------------ */ - #ifdef ATAFB_TT static struct fb_hwswitch tt_switch = { - tt_detect, tt_encode_fix, tt_decode_var, tt_encode_var, - tt_get_par, tt_set_par, tt_getcolreg, - set_screen_base, NULL, pan_display + .detect = tt_detect, + .encode_fix = tt_encode_fix, + .decode_var = tt_decode_var, + .encode_var = tt_encode_var, + .get_par = tt_get_par, + .set_par = tt_set_par, + .set_screen_base = set_screen_base, + .pan_display = pan_display, }; #endif #ifdef ATAFB_FALCON static struct fb_hwswitch falcon_switch = { - falcon_detect, falcon_encode_fix, falcon_decode_var, falcon_encode_var, - falcon_get_par, falcon_set_par, falcon_getcolreg, - set_screen_base, falcon_blank, falcon_pan_display + .detect = falcon_detect, + .encode_fix = falcon_encode_fix, + .decode_var = falcon_decode_var, + .encode_var = falcon_encode_var, + .get_par = falcon_get_par, + .set_par = falcon_set_par, + .set_screen_base = set_screen_base, + .blank = falcon_blank, + .pan_display = falcon_pan_display, }; #endif #ifdef ATAFB_STE static struct fb_hwswitch st_switch = { - stste_detect, stste_encode_fix, stste_decode_var, stste_encode_var, - stste_get_par, stste_set_par, stste_getcolreg, - stste_set_screen_base, NULL, pan_display + .detect = stste_detect, + .encode_fix = stste_encode_fix, + .decode_var = stste_decode_var, + .encode_var = stste_encode_var, + .get_par = stste_get_par, + .set_par = stste_set_par, + .set_screen_base = stste_set_screen_base, + .pan_display = pan_display }; #endif #ifdef ATAFB_EXT static struct fb_hwswitch ext_switch = { - ext_detect, ext_encode_fix, ext_decode_var, ext_encode_var, - ext_get_par, ext_set_par, ext_getcolreg, NULL, NULL, NULL + .detect = ext_detect, + .encode_fix = ext_encode_fix, + .decode_var = ext_decode_var, + .encode_var = ext_encode_var, + .get_par = ext_get_par, + .set_par = ext_set_par, }; #endif - - -static void atafb_get_par( struct atafb_par *par ) +static void ata_get_par(struct atafb_par *par) { - if (current_par_valid) { - *par=current_par; - } + if (current_par_valid) + *par = current_par; else fbhw->get_par(par); } - -static void atafb_set_par( struct atafb_par *par ) +static void ata_set_par(struct atafb_par *par) { fbhw->set_par(par); - current_par=*par; - current_par_valid=1; + current_par = *par; + current_par_valid = 1; } - /* =========================================================== */ /* ============== Hardware Independent Functions ============= */ /* =========================================================== */ - /* used for hardware scrolling */ -static int -fb_update_var(int con, struct fb_info *info) -{ - int off=fb_display[con].var.yoffset*fb_display[con].var.xres_virtual* - fb_display[con].var.bits_per_pixel>>3; - - current_par.screen_base=screen_base + off; - - if (fbhw->set_screen_base) - fbhw->set_screen_base(current_par.screen_base); - return 0; -} - -static int -do_fb_set_var(struct fb_var_screeninfo *var, int isactive) +static int do_fb_set_var(struct fb_var_screeninfo *var, int isactive) { - int err,activate; + int err, activate; struct atafb_par par; - if ((err=fbhw->decode_var(var, &par))) + + err = fbhw->decode_var(var, &par); + if (err) return err; - activate=var->activate; + activate = var->activate; if (((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) && isactive) - atafb_set_par(&par); + ata_set_par(&par); fbhw->encode_var(var, &par); - var->activate=activate; + var->activate = activate; return 0; } -static int -atafb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info) +static int atafb_get_fix(struct fb_fix_screeninfo *fix, struct fb_info *info) { struct atafb_par par; - if (con == -1) - atafb_get_par(&par); - else { - int err; - if ((err=fbhw->decode_var(&fb_display[con].var,&par))) - return err; - } + int err; + // Get fix directly (case con == -1 before)?? + err = fbhw->decode_var(&info->var, &par); + if (err) + return err; memset(fix, 0, sizeof(struct fb_fix_screeninfo)); return fbhw->encode_fix(fix, &par); } - -static int -atafb_get_var(struct fb_var_screeninfo *var, int con, struct fb_info *info) + +static int atafb_get_var(struct fb_var_screeninfo *var, struct fb_info *info) { struct atafb_par par; - if (con == -1) { - atafb_get_par(&par); - fbhw->encode_var(var, &par); - } - else - *var=fb_display[con].var; + + ata_get_par(&par); + fbhw->encode_var(var, &par); + return 0; } -static void -atafb_set_disp(int con, struct fb_info *info) +// No longer called by fbcon! +// Still called by set_var internally + +static void atafb_set_disp(struct fb_info *info) { - struct fb_fix_screeninfo fix; - struct fb_var_screeninfo var; - struct display *display; + atafb_get_var(&info->var, info); + atafb_get_fix(&info->fix, info); - if (con >= 0) - display = &fb_display[con]; - else - display = &disp; /* used during initialization */ - - atafb_get_fix(&fix, con, info); - atafb_get_var(&var, con, info); - if (con == -1) - con=0; - info->screen_base = (void *)fix.smem_start; - 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; - if (fix.visual != FB_VISUAL_PSEUDOCOLOR && - fix.visual != FB_VISUAL_DIRECTCOLOR) - display->can_soft_blank = 0; - else - display->can_soft_blank = 1; - display->inverse = - (fix.visual == FB_VISUAL_MONO01 ? !inverse : inverse); - switch (fix.type) { - case FB_TYPE_INTERLEAVED_PLANES: - switch (var.bits_per_pixel) { -#ifdef FBCON_HAS_IPLAN2P2 - case 2: - display->dispsw = &fbcon_iplan2p2; + info->screen_base = (void *)info->fix.smem_start; + + switch (info->fix.type) { + case FB_TYPE_INTERLEAVED_PLANES: + switch (info->var.bits_per_pixel) { + case 2: + // display->dispsw = &fbcon_iplan2p2; break; -#endif -#ifdef FBCON_HAS_IPLAN2P4 - case 4: - display->dispsw = &fbcon_iplan2p4; + case 4: + // display->dispsw = &fbcon_iplan2p4; break; -#endif -#ifdef FBCON_HAS_IPLAN2P8 - case 8: - display->dispsw = &fbcon_iplan2p8; + case 8: + // display->dispsw = &fbcon_iplan2p8; break; -#endif } break; - case FB_TYPE_PACKED_PIXELS: - switch (var.bits_per_pixel) { + case FB_TYPE_PACKED_PIXELS: + switch (info->var.bits_per_pixel) { #ifdef FBCON_HAS_MFB - case 1: - display->dispsw = &fbcon_mfb; + case 1: + // display->dispsw = &fbcon_mfb; break; #endif #ifdef FBCON_HAS_CFB8 - case 8: - display->dispsw = &fbcon_cfb8; + case 8: + // display->dispsw = &fbcon_cfb8; break; #endif #ifdef FBCON_HAS_CFB16 - case 16: - display->dispsw = &fbcon_cfb16; - display->dispsw_data = fbcon_cfb16_cmap; + case 16: + // display->dispsw = &fbcon_cfb16; + // display->dispsw_data = fbcon_cfb16_cmap; break; #endif } @@ -2498,74 +2481,203 @@ atafb_set_disp(int con, struct fb_info *info) } } +static int atafb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, + u_int transp, struct fb_info *info) +{ + red >>= 8; + green >>= 8; + blue >>= 8; + + return info->fbops->fb_setcolreg(regno, red, green, blue, transp, info); +} + static int -atafb_set_var(struct fb_var_screeninfo *var, int con, struct fb_info *info) +atafb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) { - int err,oldxres,oldyres,oldbpp,oldxres_virtual, - oldyres_virtual,oldyoffset; - if ((err=do_fb_set_var(var, con==info->currcon))) - return err; - if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) { - oldxres=fb_display[con].var.xres; - oldyres=fb_display[con].var.yres; - oldxres_virtual=fb_display[con].var.xres_virtual; - oldyres_virtual=fb_display[con].var.yres_virtual; - oldbpp=fb_display[con].var.bits_per_pixel; - oldyoffset=fb_display[con].var.yoffset; - fb_display[con].var=*var; - if (oldxres != var->xres || oldyres != var->yres - || oldxres_virtual != var->xres_virtual - || oldyres_virtual != var->yres_virtual - || oldbpp != var->bits_per_pixel - || oldyoffset != var->yoffset) { - atafb_set_disp(con, info); - (*fb_info.changevar)(con); - fb_alloc_cmap(&fb_display[con].cmap, 0, 0); - do_install_cmap(con, info); - } + int xoffset = var->xoffset; + int yoffset = var->yoffset; + int err; + + if (var->vmode & FB_VMODE_YWRAP) { + if (yoffset < 0 || yoffset >= info->var.yres_virtual || xoffset) + return -EINVAL; + } else { + if (xoffset + info->var.xres > info->var.xres_virtual || + yoffset + info->var.yres > info->var.yres_virtual) + return -EINVAL; } - var->activate=0; + + if (fbhw->pan_display) { + err = fbhw->pan_display(var, info); + if (err) + return err; + } else + return -EINVAL; + + info->var.xoffset = xoffset; + info->var.yoffset = yoffset; + + if (var->vmode & FB_VMODE_YWRAP) + info->var.vmode |= FB_VMODE_YWRAP; + else + info->var.vmode &= ~FB_VMODE_YWRAP; + return 0; } +/* + * generic drawing routines; imageblit needs updating for image depth > 1 + */ +#if BITS_PER_LONG == 32 +#define BYTES_PER_LONG 4 +#define SHIFT_PER_LONG 5 +#elif BITS_PER_LONG == 64 +#define BYTES_PER_LONG 8 +#define SHIFT_PER_LONG 6 +#else +#define Please update me +#endif -static int -atafb_get_cmap(struct fb_cmap *cmap, int kspc, int con, struct fb_info *info) + +static void atafb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) { - if (con == info->currcon) /* current console ? */ - return fb_get_cmap(cmap, kspc, fbhw->getcolreg, info); + struct atafb_par *par = (struct atafb_par *)info->par; + int x2, y2; + u32 width, height; + + if (!rect->width || !rect->height) + return; + + /* + * We could use hardware clipping but on many cards you get around + * hardware clipping by writing to framebuffer directly. + * */ + x2 = rect->dx + rect->width; + y2 = rect->dy + rect->height; + x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual; + y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual; + width = x2 - rect->dx; + height = y2 - rect->dy; + + if (info->var.bits_per_pixel == 1) + atafb_mfb_fillrect(info, par->next_line, rect->color, + rect->dy, rect->dx, height, width); + else if (info->var.bits_per_pixel == 2) + atafb_iplan2p2_fillrect(info, par->next_line, rect->color, + rect->dy, rect->dx, height, width); + else if (info->var.bits_per_pixel == 4) + atafb_iplan2p4_fillrect(info, par->next_line, rect->color, + rect->dy, rect->dx, height, width); 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; + atafb_iplan2p8_fillrect(info, par->next_line, rect->color, + rect->dy, rect->dx, height, width); + + return; } -static int -atafb_pan_display(struct fb_var_screeninfo *var, int con, struct fb_info *info) +static void atafb_copyarea(struct fb_info *info, const struct fb_copyarea *area) { - int xoffset = var->xoffset; - int yoffset = var->yoffset; - int err; + struct atafb_par *par = (struct atafb_par *)info->par; + int x2, y2; + u32 dx, dy, sx, sy, width, height; + int rev_copy = 0; + + /* clip the destination */ + x2 = area->dx + area->width; + y2 = area->dy + area->height; + dx = area->dx > 0 ? area->dx : 0; + dy = area->dy > 0 ? area->dy : 0; + x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual; + y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual; + width = x2 - dx; + height = y2 - dy; + + /* update sx,sy */ + sx = area->sx + (dx - area->dx); + sy = area->sy + (dy - area->dy); + + /* the source must be completely inside the virtual screen */ + if (sx < 0 || sy < 0 || (sx + width) > info->var.xres_virtual || + (sy + height) > info->var.yres_virtual) + return; - if ( xoffset < 0 || xoffset + fb_display[con].var.xres > fb_display[con].var.xres_virtual - || yoffset < 0 || yoffset + fb_display[con].var.yres > fb_display[con].var.yres_virtual) - return -EINVAL; + if (dy > sy || (dy == sy && dx > sx)) { + dy += height; + sy += height; + rev_copy = 1; + } + + if (info->var.bits_per_pixel == 1) + atafb_mfb_copyarea(info, par->next_line, sy, sx, dy, dx, height, width); + else if (info->var.bits_per_pixel == 2) + atafb_iplan2p2_copyarea(info, par->next_line, sy, sx, dy, dx, height, width); + else if (info->var.bits_per_pixel == 4) + atafb_iplan2p4_copyarea(info, par->next_line, sy, sx, dy, dx, height, width); + else + atafb_iplan2p8_copyarea(info, par->next_line, sy, sx, dy, dx, height, width); - if (con == info->currcon) { - if (fbhw->pan_display) { - if ((err = fbhw->pan_display(var, ¤t_par))) - return err; + return; +} + +static void atafb_imageblit(struct fb_info *info, const struct fb_image *image) +{ + struct atafb_par *par = (struct atafb_par *)info->par; + int x2, y2; + unsigned long *dst; + int dst_idx; + const char *src; + u32 dx, dy, width, height, pitch; + + /* + * We could use hardware clipping but on many cards you get around + * hardware clipping by writing to framebuffer directly like we are + * doing here. + */ + x2 = image->dx + image->width; + y2 = image->dy + image->height; + dx = image->dx; + dy = image->dy; + x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual; + y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual; + width = x2 - dx; + height = y2 - dy; + + if (image->depth == 1) { + // used for font data + dst = (unsigned long *) + ((unsigned long)info->screen_base & ~(BYTES_PER_LONG - 1)); + dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG - 1)) * 8; + dst_idx += dy * par->next_line * 8 + dx; + src = image->data; + pitch = (image->width + 7) / 8; + while (height--) { + + if (info->var.bits_per_pixel == 1) + atafb_mfb_linefill(info, par->next_line, + dy, dx, width, src, + image->bg_color, image->fg_color); + else if (info->var.bits_per_pixel == 2) + atafb_iplan2p2_linefill(info, par->next_line, + dy, dx, width, src, + image->bg_color, image->fg_color); + else if (info->var.bits_per_pixel == 4) + atafb_iplan2p4_linefill(info, par->next_line, + dy, dx, width, src, + image->bg_color, image->fg_color); + else + atafb_iplan2p8_linefill(info, par->next_line, + dy, dx, width, src, + image->bg_color, image->fg_color); + dy++; + src += pitch; } - else - return -EINVAL; + } else { + // only used for logo; broken + c2p(info->screen_base, image->data, dx, dy, width, height, + par->next_line, par->next_plane, image->width, + info->var.bits_per_pixel); } - fb_display[con].var.xoffset = var->xoffset; - fb_display[con].var.yoffset = var->yoffset; - return 0; } static int @@ -2584,7 +2696,7 @@ atafb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) if (copy_from_user((void *)¤t_par, (void *)arg, sizeof(struct atafb_par))) return -EFAULT; - atafb_set_par(¤t_par); + ata_set_par(¤t_par); return 0; #endif } @@ -2598,42 +2710,82 @@ atafb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) * 3 = suspend hsync * 4 = off */ -static int -atafb_blank(int blank, struct fb_info *info) +static int atafb_blank(int blank, struct fb_info *info) { unsigned short black[16]; struct fb_cmap cmap; if (fbhw->blank && !fbhw->blank(blank)) return 1; if (blank) { - memset(black, 0, 16*sizeof(unsigned short)); - cmap.red=black; - cmap.green=black; - cmap.blue=black; - cmap.transp=NULL; - cmap.start=0; - cmap.len=16; - fb_set_cmap(&cmap, 1, info); + memset(black, 0, 16 * sizeof(unsigned short)); + cmap.red = black; + cmap.green = black; + cmap.blue = black; + cmap.transp = NULL; + cmap.start = 0; + cmap.len = 16; + fb_set_cmap(&cmap, info); } +#if 0 else - do_install_cmap(info->currcon, info); + do_install_cmap(info); +#endif + return 0; +} + + /* + * New fbcon interface ... + */ + + /* check var by decoding var into hw par, rounding if necessary, + * then encoding hw par back into new, validated var */ +static int atafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + int err; + struct atafb_par par; + + /* Validate wanted screen parameters */ + // if ((err = ata_decode_var(var, &par))) + err = fbhw->decode_var(var, &par); + if (err) + return err; + + /* Encode (possibly rounded) screen parameters */ + fbhw->encode_var(var, &par); + return 0; +} + + /* actually set hw par by decoding var, then setting hardware from + * hw par just decoded */ +static int atafb_set_par(struct fb_info *info) +{ + struct atafb_par *par = (struct atafb_par *)info->par; + + /* Decode wanted screen parameters */ + fbhw->decode_var(&info->var, par); + fbhw->encode_fix(&info->fix, par); + + /* Set new videomode */ + ata_set_par(par); + return 0; } + static struct fb_ops atafb_ops = { .owner = THIS_MODULE, - .fb_get_fix = atafb_get_fix, - .fb_get_var = atafb_get_var, - .fb_set_var = atafb_set_var, - .fb_get_cmap = atafb_get_cmap, - .fb_set_cmap = gen_set_cmap, - .fb_pan_display =atafb_pan_display, + .fb_check_var = atafb_check_var, + .fb_set_par = atafb_set_par, + .fb_setcolreg = atafb_setcolreg, .fb_blank = atafb_blank, + .fb_pan_display = atafb_pan_display, + .fb_fillrect = atafb_fillrect, + .fb_copyarea = atafb_copyarea, + .fb_imageblit = atafb_imageblit, .fb_ioctl = atafb_ioctl, }; -static void -check_default_par( int detected_mode ) +static void check_default_par(int detected_mode) { char default_name[10]; int i; @@ -2642,199 +2794,41 @@ check_default_par( int detected_mode ) /* First try the user supplied mode */ if (default_par) { - var=atafb_predefined[default_par-1]; + var = atafb_predefined[default_par - 1]; var.activate = FB_ACTIVATE_TEST; - if (do_fb_set_var(&var,1)) - default_par=0; /* failed */ + if (do_fb_set_var(&var, 1)) + default_par = 0; /* failed */ } /* Next is the autodetected one */ - if (! default_par) { - var=atafb_predefined[detected_mode-1]; /* autodetect */ + if (!default_par) { + var = atafb_predefined[detected_mode - 1]; /* autodetect */ var.activate = FB_ACTIVATE_TEST; - if (!do_fb_set_var(&var,1)) - default_par=detected_mode; + if (!do_fb_set_var(&var, 1)) + default_par = detected_mode; } /* If that also failed, try some default modes... */ - if (! default_par) { + if (!default_par) { /* try default1, default2... */ - for (i=1 ; i < 10 ; i++) { - sprintf(default_name,"default%d",i); - default_par=get_video_mode(default_name); - if (! default_par) + for (i = 1; i < 10; i++) { + sprintf(default_name,"default%d", i); + default_par = get_video_mode(default_name); + if (!default_par) panic("can't set default video mode"); - var=atafb_predefined[default_par-1]; + var = atafb_predefined[default_par - 1]; var.activate = FB_ACTIVATE_TEST; - if (! do_fb_set_var(&var,1)) + if (!do_fb_set_var(&var,1)) break; /* ok */ } } - min_mem=var.xres_virtual * var.yres_virtual * var.bits_per_pixel/8; + min_mem = var.xres_virtual * var.yres_virtual * var.bits_per_pixel / 8; if (default_mem_req < min_mem) - default_mem_req=min_mem; -} - -static int -atafb_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, fbhw->getcolreg, - info); - do_fb_set_var(&fb_display[con].var,1); - info->currcon=con; - /* Install new colormap */ - do_install_cmap(con, info); - return 0; -} - -int __init atafb_init(void) -{ - int pad; - int detected_mode; - unsigned long mem_req; - - if (!MACH_IS_ATARI) - return -ENXIO; - - do { -#ifdef ATAFB_EXT - if (external_addr) { - fbhw = &ext_switch; - atafb_ops.fb_setcolreg = &ext_setcolreg; - break; - } -#endif -#ifdef ATAFB_TT - if (ATARIHW_PRESENT(TT_SHIFTER)) { - fbhw = &tt_switch; - atafb_ops.fb_setcolreg = &tt_setcolreg; - break; - } -#endif -#ifdef ATAFB_FALCON - if (ATARIHW_PRESENT(VIDEL_SHIFTER)) { - fbhw = &falcon_switch; - atafb_ops.fb_setcolreg = &falcon_setcolreg; - request_irq(IRQ_AUTO_4, falcon_vbl_switcher, IRQ_TYPE_PRIO, - "framebuffer/modeswitch", falcon_vbl_switcher); - break; - } -#endif -#ifdef ATAFB_STE - if (ATARIHW_PRESENT(STND_SHIFTER) || - ATARIHW_PRESENT(EXTD_SHIFTER)) { - fbhw = &st_switch; - atafb_ops.fb_setcolreg = &stste_setcolreg; - break; - } - fbhw = &st_switch; - atafb_ops.fb_setcolreg = &stste_setcolreg; - printk("Cannot determine video hardware; defaulting to ST(e)\n"); -#else /* ATAFB_STE */ - /* no default driver included */ - /* Nobody will ever see this message :-) */ - panic("Cannot initialize video hardware"); -#endif - } while (0); - - /* Multisync monitor capabilities */ - /* Atari-TOS defaults if no boot option present */ - if (fb_info.monspecs.hfmin == 0) { - fb_info.monspecs.hfmin = 31000; - fb_info.monspecs.hfmax = 32000; - fb_info.monspecs.vfmin = 58; - fb_info.monspecs.vfmax = 62; - } - - detected_mode = fbhw->detect(); - check_default_par(detected_mode); -#ifdef ATAFB_EXT - if (!external_addr) { -#endif /* ATAFB_EXT */ - mem_req = default_mem_req + ovsc_offset + ovsc_addlen; - mem_req = PAGE_ALIGN(mem_req) + PAGE_SIZE; - screen_base = atari_stram_alloc(mem_req, "atafb"); - if (!screen_base) - panic("Cannot allocate screen memory"); - memset(screen_base, 0, mem_req); - pad = -(unsigned long)screen_base & (PAGE_SIZE-1); - screen_base+=pad; - real_screen_base=screen_base+ovsc_offset; - screen_len = (mem_req - pad - ovsc_offset) & PAGE_MASK; - st_ovsc_switch(); - if (CPU_IS_040_OR_060) { - /* On a '040+, the cache mode of video RAM must be set to - * write-through also for internal video hardware! */ - cache_push(virt_to_phys(screen_base), screen_len); - kernel_set_cachemode(screen_base, screen_len, - IOMAP_WRITETHROUGH); - } -#ifdef ATAFB_EXT - } - else { - /* Map the video memory (physical address given) to somewhere - * in the kernel address space. - */ - external_addr = - ioremap_writethrough((unsigned long)external_addr, - external_len); - if (external_vgaiobase) - external_vgaiobase = - (unsigned long)ioremap(external_vgaiobase, 0x10000); - screen_base = - real_screen_base = external_addr; - screen_len = external_len & PAGE_MASK; - memset (screen_base, 0, external_len); - } -#endif /* ATAFB_EXT */ - - strcpy(fb_info.modename, "Atari Builtin "); - fb_info.changevar = NULL; - fb_info.fbops = &atafb_ops; - fb_info.disp = &disp; - fb_info.currcon = -1; - fb_info.switch_con = &atafb_switch; - fb_info.updatevar = &fb_update_var; - fb_info.flags = FBINFO_FLAG_DEFAULT; - do_fb_set_var(&atafb_predefined[default_par-1], 1); - strcat(fb_info.modename, fb_var_names[default_par-1][0]); - - atafb_get_var(&disp.var, -1, &fb_info); - atafb_set_disp(-1, &fb_info); - do_install_cmap(0, &fb_info); - - if (register_framebuffer(&fb_info) < 0) { -#ifdef ATAFB_EXT - if (external_addr) { - iounmap(external_addr); - external_addr = NULL; - } - if (external_vgaiobase) { - iounmap((void*)external_vgaiobase); - external_vgaiobase = 0; - } -#endif - return -EINVAL; - } - - printk("Determined %dx%d, depth %d\n", - disp.var.xres, disp.var.yres, disp.var.bits_per_pixel); - if ((disp.var.xres != disp.var.xres_virtual) || - (disp.var.yres != disp.var.yres_virtual)) - printk(" virtual %dx%d\n", - disp.var.xres_virtual, disp.var.yres_virtual); - printk("fb%d: %s frame buffer device, using %dK of video memory\n", - fb_info.node, fb_info.modename, screen_len>>10); - - /* TODO: This driver cannot be unloaded yet */ - return 0; + default_mem_req = min_mem; } - #ifdef ATAFB_EXT static void __init atafb_setup_ext(char *spec) { - int xres, xres_virtual, yres, depth, planes; + int xres, xres_virtual, yres, depth, planes; unsigned long addr, len; char *p; @@ -2848,27 +2842,31 @@ static void __init atafb_setup_ext(char *spec) * * Even xres_virtual is available, we neither support panning nor hw-scrolling! */ - if (!(p = strsep(&spec, ";")) || !*p) - return; + p = strsep(&spec, ";"); + if (!p || !*p) + return; xres_virtual = xres = simple_strtoul(p, NULL, 10); if (xres <= 0) - return; + return; - if (!(p = strsep(&spec, ";")) || !*p) - return; + p = strsep(&spec, ";"); + if (!p || !*p) + return; yres = simple_strtoul(p, NULL, 10); if (yres <= 0) - return; + return; - if (!(p = strsep(&spec, ";")) || !*p) - return; + p = strsep(&spec, ";"); + if (!p || !*p) + return; depth = simple_strtoul(p, NULL, 10); if (depth != 1 && depth != 2 && depth != 4 && depth != 8 && - depth != 16 && depth != 24) - return; + depth != 16 && depth != 24) + return; - if (!(p = strsep(&spec, ";")) || !*p) - return; + p = strsep(&spec, ";"); + if (!p || !*p) + return; if (*p == 'i') planes = FB_TYPE_INTERLEAVED_PLANES; else if (*p == 'p') @@ -2876,25 +2874,27 @@ static void __init atafb_setup_ext(char *spec) else if (*p == 'n') planes = FB_TYPE_PLANES; else if (*p == 't') - planes = -1; /* true color */ + planes = -1; /* true color */ else return; - - if (!(p = strsep(&spec, ";")) || !*p) + p = strsep(&spec, ";"); + if (!p || !*p) return; addr = simple_strtoul(p, NULL, 0); - if (!(p = strsep(&spec, ";")) || !*p) - len = xres*yres*depth/8; + p = strsep(&spec, ";"); + if (!p || !*p) + len = xres * yres * depth / 8; else len = simple_strtoul(p, NULL, 0); - if ((p = strsep(&spec, ";")) && *p) { - external_vgaiobase=simple_strtoul(p, NULL, 0); - } + p = strsep(&spec, ";"); + if (p && *p) + external_vgaiobase = simple_strtoul(p, NULL, 0); - if ((p = strsep(&spec, ";")) && *p) { + p = strsep(&spec, ";"); + if (p && *p) { external_bitspercol = simple_strtoul(p, NULL, 0); if (external_bitspercol > 8) external_bitspercol = 8; @@ -2902,59 +2902,61 @@ static void __init atafb_setup_ext(char *spec) external_bitspercol = 1; } - if ((p = strsep(&spec, ";")) && *p) { + p = strsep(&spec, ";"); + if (p && *p) { if (!strcmp(p, "vga")) external_card_type = IS_VGA; if (!strcmp(p, "mv300")) external_card_type = IS_MV300; } - if ((p = strsep(&spec, ";")) && *p) { + p = strsep(&spec, ";"); + if (p && *p) { xres_virtual = simple_strtoul(p, NULL, 10); if (xres_virtual < xres) xres_virtual = xres; - if (xres_virtual*yres*depth/8 > len) - len=xres_virtual*yres*depth/8; + if (xres_virtual * yres * depth / 8 > len) + len = xres_virtual * yres * depth / 8; } - external_xres = xres; - external_xres_virtual = xres_virtual; - external_yres = yres; + external_xres = xres; + external_xres_virtual = xres_virtual; + external_yres = yres; external_depth = depth; external_pmode = planes; - external_addr = (void *)addr; - external_len = len; - - if (external_card_type == IS_MV300) - switch (external_depth) { - case 1: - MV300_reg = MV300_reg_1bit; - break; - case 4: - MV300_reg = MV300_reg_4bit; - break; - case 8: - MV300_reg = MV300_reg_8bit; - break; - } + external_addr = (void *)addr; + external_len = len; + + if (external_card_type == IS_MV300) { + switch (external_depth) { + case 1: + MV300_reg = MV300_reg_1bit; + break; + case 4: + MV300_reg = MV300_reg_4bit; + break; + case 8: + MV300_reg = MV300_reg_8bit; + break; + } + } } #endif /* ATAFB_EXT */ - static void __init atafb_setup_int(char *spec) { /* Format to config extended internal video hardware like OverScan: - "internal:<xres>;<yres>;<xres_max>;<yres_max>;<offset>" - Explanation: - <xres>: x-resolution - <yres>: y-resolution - The following are only needed if you have an overscan which - needs a black border: - <xres_max>: max. length of a line in pixels your OverScan hardware would allow - <yres_max>: max. number of lines your OverScan hardware would allow - <offset>: Offset from physical beginning to visible beginning - of screen in bytes - */ + * "internal:<xres>;<yres>;<xres_max>;<yres_max>;<offset>" + * Explanation: + * <xres>: x-resolution + * <yres>: y-resolution + * The following are only needed if you have an overscan which + * needs a black border: + * <xres_max>: max. length of a line in pixels your OverScan hardware would allow + * <yres_max>: max. number of lines your OverScan hardware would allow + * <offset>: Offset from physical beginning to visible beginning + * of screen in bytes + */ int xres; char *p; @@ -2963,23 +2965,19 @@ static void __init atafb_setup_int(char *spec) xres = simple_strtoul(p, NULL, 10); if (!(p = strsep(&spec, ";")) || !*p) return; - sttt_xres=xres; - tt_yres=st_yres=simple_strtoul(p, NULL, 10); - if ((p=strsep(&spec, ";")) && *p) { - sttt_xres_virtual=simple_strtoul(p, NULL, 10); - } - if ((p=strsep(&spec, ";")) && *p) { - sttt_yres_virtual=simple_strtoul(p, NULL, 0); - } - if ((p=strsep(&spec, ";")) && *p) { - ovsc_offset=simple_strtoul(p, NULL, 0); - } + sttt_xres = xres; + tt_yres = st_yres = simple_strtoul(p, NULL, 10); + if ((p = strsep(&spec, ";")) && *p) + sttt_xres_virtual = simple_strtoul(p, NULL, 10); + if ((p = strsep(&spec, ";")) && *p) + sttt_yres_virtual = simple_strtoul(p, NULL, 0); + if ((p = strsep(&spec, ";")) && *p) + ovsc_offset = simple_strtoul(p, NULL, 0); if (ovsc_offset || (sttt_yres_virtual != st_yres)) - use_hwscroll=0; + use_hwscroll = 0; } - #ifdef ATAFB_FALCON static void __init atafb_setup_mcap(char *spec) { @@ -3018,7 +3016,6 @@ static void __init atafb_setup_mcap(char *spec) } #endif /* ATAFB_FALCON */ - static void __init atafb_setup_user(char *spec) { /* Format of user defined video mode is: <xres>;<yres>;<depth> @@ -3026,81 +3023,257 @@ static void __init atafb_setup_user(char *spec) char *p; int xres, yres, depth, temp; - if (!(p = strsep(&spec, ";")) || !*p) + p = strsep(&spec, ";"); + if (!p || !*p) return; xres = simple_strtoul(p, NULL, 10); - if (!(p = strsep(&spec, ";")) || !*p) + p = strsep(&spec, ";"); + if (!p || !*p) return; yres = simple_strtoul(p, NULL, 10); - if (!(p = strsep(&spec, "")) || !*p) + p = strsep(&spec, ""); + if (!p || !*p) return; depth = simple_strtoul(p, NULL, 10); - if ((temp=get_video_mode("user0"))) { - default_par=temp; - atafb_predefined[default_par-1].xres = xres; - atafb_predefined[default_par-1].yres = yres; - atafb_predefined[default_par-1].bits_per_pixel = depth; + temp = get_video_mode("user0"); + if (temp) { + default_par = temp; + atafb_predefined[default_par - 1].xres = xres; + atafb_predefined[default_par - 1].yres = yres; + atafb_predefined[default_par - 1].bits_per_pixel = depth; } } -int __init atafb_setup( char *options ) +int __init atafb_setup(char *options) { - char *this_opt; - int temp; - - fb_info.fontname[0] = '\0'; + char *this_opt; + int temp; - if (!options || !*options) + if (!options || !*options) return 0; - - while ((this_opt = strsep(&options, ",")) != NULL) { - if (!*this_opt) continue; - if ((temp=get_video_mode(this_opt))) - default_par=temp; - else if (! strcmp(this_opt, "inverse")) - inverse=1; - else if (!strncmp(this_opt, "font:", 5)) - strcpy(fb_info.fontname, this_opt+5); - else if (! strncmp(this_opt, "hwscroll_",9)) { - hwscroll=simple_strtoul(this_opt+9, NULL, 10); - if (hwscroll < 0) - hwscroll = 0; - if (hwscroll > 200) - hwscroll = 200; - } + + while ((this_opt = strsep(&options, ",")) != NULL) { + if (!*this_opt) + continue; + if ((temp = get_video_mode(this_opt))) { + default_par = temp; + mode_option = this_opt; + } else if (!strcmp(this_opt, "inverse")) + inverse = 1; + else if (!strncmp(this_opt, "hwscroll_", 9)) { + hwscroll = simple_strtoul(this_opt + 9, NULL, 10); + if (hwscroll < 0) + hwscroll = 0; + if (hwscroll > 200) + hwscroll = 200; + } #ifdef ATAFB_EXT - else if (!strcmp(this_opt,"mv300")) { - external_bitspercol = 8; - external_card_type = IS_MV300; + else if (!strcmp(this_opt, "mv300")) { + external_bitspercol = 8; + external_card_type = IS_MV300; + } else if (!strncmp(this_opt, "external:", 9)) + atafb_setup_ext(this_opt + 9); +#endif + else if (!strncmp(this_opt, "internal:", 9)) + atafb_setup_int(this_opt + 9); +#ifdef ATAFB_FALCON + else if (!strncmp(this_opt, "eclock:", 7)) { + fext.f = simple_strtoul(this_opt + 7, NULL, 10); + /* external pixelclock in kHz --> ps */ + fext.t = 1000000000 / fext.f; + fext.f *= 1000; + } else if (!strncmp(this_opt, "monitorcap:", 11)) + atafb_setup_mcap(this_opt + 11); +#endif + else if (!strcmp(this_opt, "keep")) + DontCalcRes = 1; + else if (!strncmp(this_opt, "R", 1)) + atafb_setup_user(this_opt + 1); } - else if (!strncmp(this_opt,"external:",9)) - atafb_setup_ext(this_opt+9); + return 0; +} + +int __init atafb_init(void) +{ + int pad; + int detected_mode; + unsigned int defmode = 0; + unsigned long mem_req; + +#ifndef MODULE + char *option = NULL; + + if (fb_get_options("atafb", &option)) + return -ENODEV; + atafb_setup(option); +#endif + printk("atafb_init: start\n"); + + if (!MACH_IS_ATARI) + return -ENXIO; + + do { +#ifdef ATAFB_EXT + if (external_addr) { + printk("atafb_init: initializing external hw\n"); + fbhw = &ext_switch; + atafb_ops.fb_setcolreg = &ext_setcolreg; + defmode = DEFMODE_EXT; + break; + } +#endif +#ifdef ATAFB_TT + if (ATARIHW_PRESENT(TT_SHIFTER)) { + printk("atafb_init: initializing TT hw\n"); + fbhw = &tt_switch; + atafb_ops.fb_setcolreg = &tt_setcolreg; + defmode = DEFMODE_TT; + break; + } #endif - else if (!strncmp(this_opt,"internal:",9)) - atafb_setup_int(this_opt+9); #ifdef ATAFB_FALCON - else if (!strncmp(this_opt, "eclock:", 7)) { - fext.f = simple_strtoul(this_opt+7, NULL, 10); - /* external pixelclock in kHz --> ps */ - fext.t = 1000000000/fext.f; - fext.f *= 1000; + if (ATARIHW_PRESENT(VIDEL_SHIFTER)) { + printk("atafb_init: initializing Falcon hw\n"); + fbhw = &falcon_switch; + atafb_ops.fb_setcolreg = &falcon_setcolreg; + request_irq(IRQ_AUTO_4, falcon_vbl_switcher, IRQ_TYPE_PRIO, + "framebuffer/modeswitch", falcon_vbl_switcher); + defmode = DEFMODE_F30; + break; + } +#endif +#ifdef ATAFB_STE + if (ATARIHW_PRESENT(STND_SHIFTER) || + ATARIHW_PRESENT(EXTD_SHIFTER)) { + printk("atafb_init: initializing ST/E hw\n"); + fbhw = &st_switch; + atafb_ops.fb_setcolreg = &stste_setcolreg; + defmode = DEFMODE_STE; + break; + } + fbhw = &st_switch; + atafb_ops.fb_setcolreg = &stste_setcolreg; + printk("Cannot determine video hardware; defaulting to ST(e)\n"); +#else /* ATAFB_STE */ + /* no default driver included */ + /* Nobody will ever see this message :-) */ + panic("Cannot initialize video hardware"); +#endif + } while (0); + + /* Multisync monitor capabilities */ + /* Atari-TOS defaults if no boot option present */ + if (fb_info.monspecs.hfmin == 0) { + fb_info.monspecs.hfmin = 31000; + fb_info.monspecs.hfmax = 32000; + fb_info.monspecs.vfmin = 58; + fb_info.monspecs.vfmax = 62; } - else if (!strncmp(this_opt, "monitorcap:", 11)) - atafb_setup_mcap(this_opt+11); + + detected_mode = fbhw->detect(); + check_default_par(detected_mode); +#ifdef ATAFB_EXT + if (!external_addr) { +#endif /* ATAFB_EXT */ + mem_req = default_mem_req + ovsc_offset + ovsc_addlen; + mem_req = PAGE_ALIGN(mem_req) + PAGE_SIZE; + screen_base = atari_stram_alloc(mem_req, "atafb"); + if (!screen_base) + panic("Cannot allocate screen memory"); + memset(screen_base, 0, mem_req); + pad = -(unsigned long)screen_base & (PAGE_SIZE - 1); + screen_base += pad; + real_screen_base = screen_base + ovsc_offset; + screen_len = (mem_req - pad - ovsc_offset) & PAGE_MASK; + st_ovsc_switch(); + if (CPU_IS_040_OR_060) { + /* On a '040+, the cache mode of video RAM must be set to + * write-through also for internal video hardware! */ + cache_push(virt_to_phys(screen_base), screen_len); + kernel_set_cachemode(screen_base, screen_len, + IOMAP_WRITETHROUGH); + } + printk("atafb: screen_base %p real_screen_base %p screen_len %d\n", + screen_base, real_screen_base, screen_len); +#ifdef ATAFB_EXT + } else { + /* Map the video memory (physical address given) to somewhere + * in the kernel address space. + */ + external_addr = ioremap_writethrough((unsigned long)external_addr, + external_len); + if (external_vgaiobase) + external_vgaiobase = + (unsigned long)ioremap(external_vgaiobase, 0x10000); + screen_base = + real_screen_base = external_addr; + screen_len = external_len & PAGE_MASK; + memset (screen_base, 0, external_len); + } +#endif /* ATAFB_EXT */ + +// strcpy(fb_info.mode->name, "Atari Builtin "); + fb_info.fbops = &atafb_ops; + // try to set default (detected; requested) var + do_fb_set_var(&atafb_predefined[default_par - 1], 1); + // reads hw state into current par, which may not be sane yet + ata_get_par(¤t_par); + fb_info.par = ¤t_par; + // tries to read from HW which may not be initialized yet + // so set sane var first, then call atafb_set_par + atafb_get_var(&fb_info.var, &fb_info); + fb_info.flags = FBINFO_FLAG_DEFAULT; + + if (!fb_find_mode(&fb_info.var, &fb_info, mode_option, atafb_modedb, + NUM_TOTAL_MODES, &atafb_modedb[defmode], + fb_info.var.bits_per_pixel)) { + return -EINVAL; + } + + atafb_set_disp(&fb_info); + + fb_alloc_cmap(&(fb_info.cmap), 1 << fb_info.var.bits_per_pixel, 0); + + + printk("Determined %dx%d, depth %d\n", + fb_info.var.xres, fb_info.var.yres, fb_info.var.bits_per_pixel); + if ((fb_info.var.xres != fb_info.var.xres_virtual) || + (fb_info.var.yres != fb_info.var.yres_virtual)) + printk(" virtual %dx%d\n", fb_info.var.xres_virtual, + fb_info.var.yres_virtual); + + if (register_framebuffer(&fb_info) < 0) { +#ifdef ATAFB_EXT + if (external_addr) { + iounmap(external_addr); + external_addr = NULL; + } + if (external_vgaiobase) { + iounmap((void*)external_vgaiobase); + external_vgaiobase = 0; + } #endif - else if (!strcmp(this_opt, "keep")) - DontCalcRes = 1; - else if (!strncmp(this_opt, "R", 1)) - atafb_setup_user(this_opt+1); - } - return 0; + return -EINVAL; + } + + // FIXME: mode needs setting! + //printk("fb%d: %s frame buffer device, using %dK of video memory\n", + // fb_info.node, fb_info.mode->name, screen_len>>10); + printk("fb%d: frame buffer device, using %dK of video memory\n", + fb_info.node, screen_len >> 10); + + /* TODO: This driver cannot be unloaded yet */ + return 0; } +module_init(atafb_init); + #ifdef MODULE MODULE_LICENSE("GPL"); -int init_module(void) +int cleanup_module(void) { - return atafb_init(); + unregister_framebuffer(&fb_info); + return atafb_deinit(); } #endif /* MODULE */ diff --git a/drivers/video/atafb.h b/drivers/video/atafb.h new file mode 100644 index 00000000000..014e05906cb --- /dev/null +++ b/drivers/video/atafb.h @@ -0,0 +1,36 @@ +#ifndef _VIDEO_ATAFB_H +#define _VIDEO_ATAFB_H + +void atafb_mfb_copyarea(struct fb_info *info, u_long next_line, int sy, int sx, int dy, + int dx, int height, int width); +void atafb_mfb_fillrect(struct fb_info *info, u_long next_line, u32 color, + int sy, int sx, int height, int width); +void atafb_mfb_linefill(struct fb_info *info, u_long next_line, + int dy, int dx, u32 width, + const u8 *data, u32 bgcolor, u32 fgcolor); + +void atafb_iplan2p2_copyarea(struct fb_info *info, u_long next_line, int sy, int sx, int dy, + int dx, int height, int width); +void atafb_iplan2p2_fillrect(struct fb_info *info, u_long next_line, u32 color, + int sy, int sx, int height, int width); +void atafb_iplan2p2_linefill(struct fb_info *info, u_long next_line, + int dy, int dx, u32 width, + const u8 *data, u32 bgcolor, u32 fgcolor); + +void atafb_iplan2p4_copyarea(struct fb_info *info, u_long next_line, int sy, int sx, int dy, + int dx, int height, int width); +void atafb_iplan2p4_fillrect(struct fb_info *info, u_long next_line, u32 color, + int sy, int sx, int height, int width); +void atafb_iplan2p4_linefill(struct fb_info *info, u_long next_line, + int dy, int dx, u32 width, + const u8 *data, u32 bgcolor, u32 fgcolor); + +void atafb_iplan2p8_copyarea(struct fb_info *info, u_long next_line, int sy, int sx, int dy, + int dx, int height, int width); +void atafb_iplan2p8_fillrect(struct fb_info *info, u_long next_line, u32 color, + int sy, int sx, int height, int width); +void atafb_iplan2p8_linefill(struct fb_info *info, u_long next_line, + int dy, int dx, u32 width, + const u8 *data, u32 bgcolor, u32 fgcolor); + +#endif /* _VIDEO_ATAFB_H */ diff --git a/drivers/video/atafb_iplan2p2.c b/drivers/video/atafb_iplan2p2.c new file mode 100644 index 00000000000..8cc9c50379d --- /dev/null +++ b/drivers/video/atafb_iplan2p2.c @@ -0,0 +1,293 @@ +/* + * linux/drivers/video/iplan2p2.c -- Low level frame buffer operations for + * interleaved bitplanes à la Atari (2 + * planes, 2 bytes interleave) + * + * Created 5 Apr 1997 by Geert Uytterhoeven + * + * 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/module.h> +#include <linux/string.h> +#include <linux/fb.h> + +#include <asm/setup.h> + +#include "atafb.h" + +#define BPL 2 +#include "atafb_utils.h" + +void atafb_iplan2p2_copyarea(struct fb_info *info, u_long next_line, + int sy, int sx, int dy, int dx, + int height, int width) +{ + /* bmove() has to distinguish two major cases: If both, source and + * destination, start at even addresses or both are at odd + * addresses, just the first odd and last even column (if present) + * require special treatment (memmove_col()). The rest between + * then can be copied by normal operations, because all adjacent + * bytes are affected and are to be stored in the same order. + * The pathological case is when the move should go from an odd + * address to an even or vice versa. Since the bytes in the plane + * words must be assembled in new order, it seems wisest to make + * all movements by memmove_col(). + */ + + u8 *src, *dst; + u32 *s, *d; + int w, l , i, j; + u_int colsize; + u_int upwards = (dy < sy) || (dy == sy && dx < sx); + + colsize = height; + if (!((sx ^ dx) & 15)) { + /* odd->odd or even->even */ + + if (upwards) { + src = (u8 *)info->screen_base + sy * next_line + (sx & ~15) / (8 / BPL); + dst = (u8 *)info->screen_base + dy * next_line + (dx & ~15) / (8 / BPL); + if (sx & 15) { + memmove32_col(dst, src, 0xff00ff, height, next_line - BPL * 2); + src += BPL * 2; + dst += BPL * 2; + width -= 8; + } + w = width >> 4; + if (w) { + s = (u32 *)src; + d = (u32 *)dst; + w *= BPL / 2; + l = next_line - w * 4; + for (j = height; j > 0; j--) { + for (i = w; i > 0; i--) + *d++ = *s++; + s = (u32 *)((u8 *)s + l); + d = (u32 *)((u8 *)d + l); + } + } + if (width & 15) + memmove32_col(dst + width / (8 / BPL), src + width / (8 / BPL), + 0xff00ff00, height, next_line - BPL * 2); + } else { + src = (u8 *)info->screen_base + (sy - 1) * next_line + ((sx + width + 8) & ~15) / (8 / BPL); + dst = (u8 *)info->screen_base + (dy - 1) * next_line + ((dx + width + 8) & ~15) / (8 / BPL); + + if ((sx + width) & 15) { + src -= BPL * 2; + dst -= BPL * 2; + memmove32_col(dst, src, 0xff00ff00, colsize, -next_line - BPL * 2); + width -= 8; + } + w = width >> 4; + if (w) { + s = (u32 *)src; + d = (u32 *)dst; + w *= BPL / 2; + l = next_line - w * 4; + for (j = height; j > 0; j--) { + for (i = w; i > 0; i--) + *--d = *--s; + s = (u32 *)((u8 *)s - l); + d = (u32 *)((u8 *)d - l); + } + } + if (sx & 15) + memmove32_col(dst - (width - 16) / (8 / BPL), + src - (width - 16) / (8 / BPL), + 0xff00ff, colsize, -next_line - BPL * 2); + } + } else { + /* odd->even or even->odd */ + if (upwards) { + u32 *src32, *dst32; + u32 pval[4], v, v1, mask; + int i, j, w, f; + + src = (u8 *)info->screen_base + sy * next_line + (sx & ~15) / (8 / BPL); + dst = (u8 *)info->screen_base + dy * next_line + (dx & ~15) / (8 / BPL); + + mask = 0xff00ff00; + f = 0; + w = width; + if (sx & 15) { + f = 1; + w += 8; + } + if ((sx + width) & 15) + f |= 2; + w >>= 4; + for (i = height; i; i--) { + src32 = (u32 *)src; + dst32 = (u32 *)dst; + + if (f & 1) { + pval[0] = (*src32++ << 8) & mask; + } else { + pval[0] = dst32[0] & mask; + } + + for (j = w; j > 0; j--) { + v = *src32++; + v1 = v & mask; + *dst32++ = pval[0] | (v1 >> 8); + pval[0] = (v ^ v1) << 8; + } + + if (f & 2) { + dst32[0] = (dst32[0] & mask) | pval[0]; + } + + src += next_line; + dst += next_line; + } + } else { + u32 *src32, *dst32; + u32 pval[4], v, v1, mask; + int i, j, w, f; + + src = (u8 *)info->screen_base + (sy - 1) * next_line + ((sx + width + 8) & ~15) / (8 / BPL); + dst = (u8 *)info->screen_base + (dy - 1) * next_line + ((dx + width + 8) & ~15) / (8 / BPL); + + mask = 0xff00ff; + f = 0; + w = width; + if ((dx + width) & 15) + f = 1; + if (sx & 15) { + f |= 2; + w += 8; + } + w >>= 4; + for (i = height; i; i--) { + src32 = (u32 *)src; + dst32 = (u32 *)dst; + + if (f & 1) { + pval[0] = dst32[-1] & mask; + } else { + pval[0] = (*--src32 >> 8) & mask; + } + + for (j = w; j > 0; j--) { + v = *--src32; + v1 = v & mask; + *--dst32 = pval[0] | (v1 << 8); + pval[0] = (v ^ v1) >> 8; + } + + if (!(f & 2)) { + dst32[-1] = (dst32[-1] & mask) | pval[0]; + } + + src -= next_line; + dst -= next_line; + } + } + } +} + +void atafb_iplan2p2_fillrect(struct fb_info *info, u_long next_line, u32 color, + int sy, int sx, int height, int width) +{ + u32 *dest; + int rows, i; + u32 cval[4]; + + dest = (u32 *)(info->screen_base + sy * next_line + (sx & ~15) / (8 / BPL)); + if (sx & 15) { + u8 *dest8 = (u8 *)dest + 1; + + expand8_col2mask(color, cval); + + for (i = height; i; i--) { + fill8_col(dest8, cval); + dest8 += next_line; + } + dest += BPL / 2; + width -= 8; + } + + expand16_col2mask(color, cval); + rows = width >> 4; + if (rows) { + u32 *d = dest; + u32 off = next_line - rows * BPL * 2; + for (i = height; i; i--) { + d = fill16_col(d, rows, cval); + d = (u32 *)((long)d + off); + } + dest += rows * BPL / 2; + width &= 15; + } + + if (width) { + u8 *dest8 = (u8 *)dest; + + expand8_col2mask(color, cval); + + for (i = height; i; i--) { + fill8_col(dest8, cval); + dest8 += next_line; + } + } +} + +void atafb_iplan2p2_linefill(struct fb_info *info, u_long next_line, + int dy, int dx, u32 width, + const u8 *data, u32 bgcolor, u32 fgcolor) +{ + u32 *dest; + const u16 *data16; + int rows; + u32 fgm[4], bgm[4], m; + + dest = (u32 *)(info->screen_base + dy * next_line + (dx & ~15) / (8 / BPL)); + if (dx & 15) { + fill8_2col((u8 *)dest + 1, fgcolor, bgcolor, *data++); + dest += BPL / 2; + width -= 8; + } + + if (width >= 16) { + data16 = (const u16 *)data; + expand16_2col2mask(fgcolor, bgcolor, fgm, bgm); + + for (rows = width / 16; rows; rows--) { + u16 d = *data16++; + m = d | ((u32)d << 16); + *dest++ = (m & fgm[0]) ^ bgm[0]; + } + + data = (const u8 *)data16; + width &= 15; + } + + if (width) + fill8_2col((u8 *)dest, fgcolor, bgcolor, *data); +} + +#ifdef MODULE +MODULE_LICENSE("GPL"); + +int init_module(void) +{ + return 0; +} + +void cleanup_module(void) +{ +} +#endif /* MODULE */ + + + /* + * Visible symbols for modules + */ + +EXPORT_SYMBOL(atafb_iplan2p2_copyarea); +EXPORT_SYMBOL(atafb_iplan2p2_fillrect); +EXPORT_SYMBOL(atafb_iplan2p2_linefill); diff --git a/drivers/video/atafb_iplan2p4.c b/drivers/video/atafb_iplan2p4.c new file mode 100644 index 00000000000..bee0d89463f --- /dev/null +++ b/drivers/video/atafb_iplan2p4.c @@ -0,0 +1,308 @@ +/* + * linux/drivers/video/iplan2p4.c -- Low level frame buffer operations for + * interleaved bitplanes à la Atari (4 + * planes, 2 bytes interleave) + * + * Created 5 Apr 1997 by Geert Uytterhoeven + * + * 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/module.h> +#include <linux/string.h> +#include <linux/fb.h> + +#include <asm/setup.h> + +#include "atafb.h" + +#define BPL 4 +#include "atafb_utils.h" + +void atafb_iplan2p4_copyarea(struct fb_info *info, u_long next_line, + int sy, int sx, int dy, int dx, + int height, int width) +{ + /* bmove() has to distinguish two major cases: If both, source and + * destination, start at even addresses or both are at odd + * addresses, just the first odd and last even column (if present) + * require special treatment (memmove_col()). The rest between + * then can be copied by normal operations, because all adjacent + * bytes are affected and are to be stored in the same order. + * The pathological case is when the move should go from an odd + * address to an even or vice versa. Since the bytes in the plane + * words must be assembled in new order, it seems wisest to make + * all movements by memmove_col(). + */ + + u8 *src, *dst; + u32 *s, *d; + int w, l , i, j; + u_int colsize; + u_int upwards = (dy < sy) || (dy == sy && dx < sx); + + colsize = height; + if (!((sx ^ dx) & 15)) { + /* odd->odd or even->even */ + + if (upwards) { + src = (u8 *)info->screen_base + sy * next_line + (sx & ~15) / (8 / BPL); + dst = (u8 *)info->screen_base + dy * next_line + (dx & ~15) / (8 / BPL); + if (sx & 15) { + memmove32_col(dst, src, 0xff00ff, height, next_line - BPL * 2); + src += BPL * 2; + dst += BPL * 2; + width -= 8; + } + w = width >> 4; + if (w) { + s = (u32 *)src; + d = (u32 *)dst; + w *= BPL / 2; + l = next_line - w * 4; + for (j = height; j > 0; j--) { + for (i = w; i > 0; i--) + *d++ = *s++; + s = (u32 *)((u8 *)s + l); + d = (u32 *)((u8 *)d + l); + } + } + if (width & 15) + memmove32_col(dst + width / (8 / BPL), src + width / (8 / BPL), + 0xff00ff00, height, next_line - BPL * 2); + } else { + src = (u8 *)info->screen_base + (sy - 1) * next_line + ((sx + width + 8) & ~15) / (8 / BPL); + dst = (u8 *)info->screen_base + (dy - 1) * next_line + ((dx + width + 8) & ~15) / (8 / BPL); + + if ((sx + width) & 15) { + src -= BPL * 2; + dst -= BPL * 2; + memmove32_col(dst, src, 0xff00ff00, colsize, -next_line - BPL * 2); + width -= 8; + } + w = width >> 4; + if (w) { + s = (u32 *)src; + d = (u32 *)dst; + w *= BPL / 2; + l = next_line - w * 4; + for (j = height; j > 0; j--) { + for (i = w; i > 0; i--) + *--d = *--s; + s = (u32 *)((u8 *)s - l); + d = (u32 *)((u8 *)d - l); + } + } + if (sx & 15) + memmove32_col(dst - (width - 16) / (8 / BPL), + src - (width - 16) / (8 / BPL), + 0xff00ff, colsize, -next_line - BPL * 2); + } + } else { + /* odd->even or even->odd */ + if (upwards) { + u32 *src32, *dst32; + u32 pval[4], v, v1, mask; + int i, j, w, f; + + src = (u8 *)info->screen_base + sy * next_line + (sx & ~15) / (8 / BPL); + dst = (u8 *)info->screen_base + dy * next_line + (dx & ~15) / (8 / BPL); + + mask = 0xff00ff00; + f = 0; + w = width; + if (sx & 15) { + f = 1; + w += 8; + } + if ((sx + width) & 15) + f |= 2; + w >>= 4; + for (i = height; i; i--) { + src32 = (u32 *)src; + dst32 = (u32 *)dst; + + if (f & 1) { + pval[0] = (*src32++ << 8) & mask; + pval[1] = (*src32++ << 8) & mask; + } else { + pval[0] = dst32[0] & mask; + pval[1] = dst32[1] & mask; + } + + for (j = w; j > 0; j--) { + v = *src32++; + v1 = v & mask; + *dst32++ = pval[0] | (v1 >> 8); + pval[0] = (v ^ v1) << 8; + v = *src32++; + v1 = v & mask; + *dst32++ = pval[1] | (v1 >> 8); + pval[1] = (v ^ v1) << 8; + } + + if (f & 2) { + dst32[0] = (dst32[0] & mask) | pval[0]; + dst32[1] = (dst32[1] & mask) | pval[1]; + } + + src += next_line; + dst += next_line; + } + } else { + u32 *src32, *dst32; + u32 pval[4], v, v1, mask; + int i, j, w, f; + + src = (u8 *)info->screen_base + (sy - 1) * next_line + ((sx + width + 8) & ~15) / (8 / BPL); + dst = (u8 *)info->screen_base + (dy - 1) * next_line + ((dx + width + 8) & ~15) / (8 / BPL); + + mask = 0xff00ff; + f = 0; + w = width; + if ((dx + width) & 15) + f = 1; + if (sx & 15) { + f |= 2; + w += 8; + } + w >>= 4; + for (i = height; i; i--) { + src32 = (u32 *)src; + dst32 = (u32 *)dst; + + if (f & 1) { + pval[0] = dst32[-1] & mask; + pval[1] = dst32[-2] & mask; + } else { + pval[0] = (*--src32 >> 8) & mask; + pval[1] = (*--src32 >> 8) & mask; + } + + for (j = w; j > 0; j--) { + v = *--src32; + v1 = v & mask; + *--dst32 = pval[0] | (v1 << 8); + pval[0] = (v ^ v1) >> 8; + v = *--src32; + v1 = v & mask; + *--dst32 = pval[1] | (v1 << 8); + pval[1] = (v ^ v1) >> 8; + } + + if (!(f & 2)) { + dst32[-1] = (dst32[-1] & mask) | pval[0]; + dst32[-2] = (dst32[-2] & mask) | pval[1]; + } + + src -= next_line; + dst -= next_line; + } + } + } +} + +void atafb_iplan2p4_fillrect(struct fb_info *info, u_long next_line, u32 color, + int sy, int sx, int height, int width) +{ + u32 *dest; + int rows, i; + u32 cval[4]; + + dest = (u32 *)(info->screen_base + sy * next_line + (sx & ~15) / (8 / BPL)); + if (sx & 15) { + u8 *dest8 = (u8 *)dest + 1; + + expand8_col2mask(color, cval); + + for (i = height; i; i--) { + fill8_col(dest8, cval); + dest8 += next_line; + } + dest += BPL / 2; + width -= 8; + } + + expand16_col2mask(color, cval); + rows = width >> 4; + if (rows) { + u32 *d = dest; + u32 off = next_line - rows * BPL * 2; + for (i = height; i; i--) { + d = fill16_col(d, rows, cval); + d = (u32 *)((long)d + off); + } + dest += rows * BPL / 2; + width &= 15; + } + + if (width) { + u8 *dest8 = (u8 *)dest; + + expand8_col2mask(color, cval); + + for (i = height; i; i--) { + fill8_col(dest8, cval); + dest8 += next_line; + } + } +} + +void atafb_iplan2p4_linefill(struct fb_info *info, u_long next_line, + int dy, int dx, u32 width, + const u8 *data, u32 bgcolor, u32 fgcolor) +{ + u32 *dest; + const u16 *data16; + int rows; + u32 fgm[4], bgm[4], m; + + dest = (u32 *)(info->screen_base + dy * next_line + (dx & ~15) / (8 / BPL)); + if (dx & 15) { + fill8_2col((u8 *)dest + 1, fgcolor, bgcolor, *data++); + dest += BPL / 2; + width -= 8; + } + + if (width >= 16) { + data16 = (const u16 *)data; + expand16_2col2mask(fgcolor, bgcolor, fgm, bgm); + + for (rows = width / 16; rows; rows--) { + u16 d = *data16++; + m = d | ((u32)d << 16); + *dest++ = (m & fgm[0]) ^ bgm[0]; + *dest++ = (m & fgm[1]) ^ bgm[1]; + } + + data = (const u8 *)data16; + width &= 15; + } + + if (width) + fill8_2col((u8 *)dest, fgcolor, bgcolor, *data); +} + +#ifdef MODULE +MODULE_LICENSE("GPL"); + +int init_module(void) +{ + return 0; +} + +void cleanup_module(void) +{ +} +#endif /* MODULE */ + + + /* + * Visible symbols for modules + */ + +EXPORT_SYMBOL(atafb_iplan2p4_copyarea); +EXPORT_SYMBOL(atafb_iplan2p4_fillrect); +EXPORT_SYMBOL(atafb_iplan2p4_linefill); diff --git a/drivers/video/atafb_iplan2p8.c b/drivers/video/atafb_iplan2p8.c new file mode 100644 index 00000000000..356fb52ce44 --- /dev/null +++ b/drivers/video/atafb_iplan2p8.c @@ -0,0 +1,345 @@ +/* + * linux/drivers/video/iplan2p8.c -- Low level frame buffer operations for + * interleaved bitplanes à la Atari (8 + * planes, 2 bytes interleave) + * + * Created 5 Apr 1997 by Geert Uytterhoeven + * + * 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/module.h> +#include <linux/string.h> +#include <linux/fb.h> + +#include <asm/setup.h> + +#include "atafb.h" + +#define BPL 8 +#include "atafb_utils.h" + + +/* Copies a 8 plane column from 's', height 'h', to 'd'. */ + +/* This expands a 8 bit color into two longs for two movepl (8 plane) + * operations. + */ + +void atafb_iplan2p8_copyarea(struct fb_info *info, u_long next_line, + int sy, int sx, int dy, int dx, + int height, int width) +{ + /* bmove() has to distinguish two major cases: If both, source and + * destination, start at even addresses or both are at odd + * addresses, just the first odd and last even column (if present) + * require special treatment (memmove_col()). The rest between + * then can be copied by normal operations, because all adjacent + * bytes are affected and are to be stored in the same order. + * The pathological case is when the move should go from an odd + * address to an even or vice versa. Since the bytes in the plane + * words must be assembled in new order, it seems wisest to make + * all movements by memmove_col(). + */ + + u8 *src, *dst; + u32 *s, *d; + int w, l , i, j; + u_int colsize; + u_int upwards = (dy < sy) || (dy == sy && dx < sx); + + colsize = height; + if (!((sx ^ dx) & 15)) { + /* odd->odd or even->even */ + + if (upwards) { + src = (u8 *)info->screen_base + sy * next_line + (sx & ~15) / (8 / BPL); + dst = (u8 *)info->screen_base + dy * next_line + (dx & ~15) / (8 / BPL); + if (sx & 15) { + memmove32_col(dst, src, 0xff00ff, height, next_line - BPL * 2); + src += BPL * 2; + dst += BPL * 2; + width -= 8; + } + w = width >> 4; + if (w) { + s = (u32 *)src; + d = (u32 *)dst; + w *= BPL / 2; + l = next_line - w * 4; + for (j = height; j > 0; j--) { + for (i = w; i > 0; i--) + *d++ = *s++; + s = (u32 *)((u8 *)s + l); + d = (u32 *)((u8 *)d + l); + } + } + if (width & 15) + memmove32_col(dst + width / (8 / BPL), src + width / (8 / BPL), + 0xff00ff00, height, next_line - BPL * 2); + } else { + src = (u8 *)info->screen_base + (sy - 1) * next_line + ((sx + width + 8) & ~15) / (8 / BPL); + dst = (u8 *)info->screen_base + (dy - 1) * next_line + ((dx + width + 8) & ~15) / (8 / BPL); + + if ((sx + width) & 15) { + src -= BPL * 2; + dst -= BPL * 2; + memmove32_col(dst, src, 0xff00ff00, colsize, -next_line - BPL * 2); + width -= 8; + } + w = width >> 4; + if (w) { + s = (u32 *)src; + d = (u32 *)dst; + w *= BPL / 2; + l = next_line - w * 4; + for (j = height; j > 0; j--) { + for (i = w; i > 0; i--) + *--d = *--s; + s = (u32 *)((u8 *)s - l); + d = (u32 *)((u8 *)d - l); + } + } + if (sx & 15) + memmove32_col(dst - (width - 16) / (8 / BPL), + src - (width - 16) / (8 / BPL), + 0xff00ff, colsize, -next_line - BPL * 2); + } + } else { + /* odd->even or even->odd */ + if (upwards) { + u32 *src32, *dst32; + u32 pval[4], v, v1, mask; + int i, j, w, f; + + src = (u8 *)info->screen_base + sy * next_line + (sx & ~15) / (8 / BPL); + dst = (u8 *)info->screen_base + dy * next_line + (dx & ~15) / (8 / BPL); + + mask = 0xff00ff00; + f = 0; + w = width; + if (sx & 15) { + f = 1; + w += 8; + } + if ((sx + width) & 15) + f |= 2; + w >>= 4; + for (i = height; i; i--) { + src32 = (u32 *)src; + dst32 = (u32 *)dst; + + if (f & 1) { + pval[0] = (*src32++ << 8) & mask; + pval[1] = (*src32++ << 8) & mask; + pval[2] = (*src32++ << 8) & mask; + pval[3] = (*src32++ << 8) & mask; + } else { + pval[0] = dst32[0] & mask; + pval[1] = dst32[1] & mask; + pval[2] = dst32[2] & mask; + pval[3] = dst32[3] & mask; + } + + for (j = w; j > 0; j--) { + v = *src32++; + v1 = v & mask; + *dst32++ = pval[0] | (v1 >> 8); + pval[0] = (v ^ v1) << 8; + v = *src32++; + v1 = v & mask; + *dst32++ = pval[1] | (v1 >> 8); + pval[1] = (v ^ v1) << 8; + v = *src32++; + v1 = v & mask; + *dst32++ = pval[2] | (v1 >> 8); + pval[2] = (v ^ v1) << 8; + v = *src32++; + v1 = v & mask; + *dst32++ = pval[3] | (v1 >> 8); + pval[3] = (v ^ v1) << 8; + } + + if (f & 2) { + dst32[0] = (dst32[0] & mask) | pval[0]; + dst32[1] = (dst32[1] & mask) | pval[1]; + dst32[2] = (dst32[2] & mask) | pval[2]; + dst32[3] = (dst32[3] & mask) | pval[3]; + } + + src += next_line; + dst += next_line; + } + } else { + u32 *src32, *dst32; + u32 pval[4], v, v1, mask; + int i, j, w, f; + + src = (u8 *)info->screen_base + (sy - 1) * next_line + ((sx + width + 8) & ~15) / (8 / BPL); + dst = (u8 *)info->screen_base + (dy - 1) * next_line + ((dx + width + 8) & ~15) / (8 / BPL); + + mask = 0xff00ff; + f = 0; + w = width; + if ((dx + width) & 15) + f = 1; + if (sx & 15) { + f |= 2; + w += 8; + } + w >>= 4; + for (i = height; i; i--) { + src32 = (u32 *)src; + dst32 = (u32 *)dst; + + if (f & 1) { + pval[0] = dst32[-1] & mask; + pval[1] = dst32[-2] & mask; + pval[2] = dst32[-3] & mask; + pval[3] = dst32[-4] & mask; + } else { + pval[0] = (*--src32 >> 8) & mask; + pval[1] = (*--src32 >> 8) & mask; + pval[2] = (*--src32 >> 8) & mask; + pval[3] = (*--src32 >> 8) & mask; + } + + for (j = w; j > 0; j--) { + v = *--src32; + v1 = v & mask; + *--dst32 = pval[0] | (v1 << 8); + pval[0] = (v ^ v1) >> 8; + v = *--src32; + v1 = v & mask; + *--dst32 = pval[1] | (v1 << 8); + pval[1] = (v ^ v1) >> 8; + v = *--src32; + v1 = v & mask; + *--dst32 = pval[2] | (v1 << 8); + pval[2] = (v ^ v1) >> 8; + v = *--src32; + v1 = v & mask; + *--dst32 = pval[3] | (v1 << 8); + pval[3] = (v ^ v1) >> 8; + } + + if (!(f & 2)) { + dst32[-1] = (dst32[-1] & mask) | pval[0]; + dst32[-2] = (dst32[-2] & mask) | pval[1]; + dst32[-3] = (dst32[-3] & mask) | pval[2]; + dst32[-4] = (dst32[-4] & mask) | pval[3]; + } + + src -= next_line; + dst -= next_line; + } + } + } +} + +void atafb_iplan2p8_fillrect(struct fb_info *info, u_long next_line, u32 color, + int sy, int sx, int height, int width) +{ + u32 *dest; + int rows, i; + u32 cval[4]; + + dest = (u32 *)(info->screen_base + sy * next_line + (sx & ~15) / (8 / BPL)); + if (sx & 15) { + u8 *dest8 = (u8 *)dest + 1; + + expand8_col2mask(color, cval); + + for (i = height; i; i--) { + fill8_col(dest8, cval); + dest8 += next_line; + } + dest += BPL / 2; + width -= 8; + } + + expand16_col2mask(color, cval); + rows = width >> 4; + if (rows) { + u32 *d = dest; + u32 off = next_line - rows * BPL * 2; + for (i = height; i; i--) { + d = fill16_col(d, rows, cval); + d = (u32 *)((long)d + off); + } + dest += rows * BPL / 2; + width &= 15; + } + + if (width) { + u8 *dest8 = (u8 *)dest; + + expand8_col2mask(color, cval); + + for (i = height; i; i--) { + fill8_col(dest8, cval); + dest8 += next_line; + } + } +} + +void atafb_iplan2p8_linefill(struct fb_info *info, u_long next_line, + int dy, int dx, u32 width, + const u8 *data, u32 bgcolor, u32 fgcolor) +{ + u32 *dest; + const u16 *data16; + int rows; + u32 fgm[4], bgm[4], m; + + dest = (u32 *)(info->screen_base + dy * next_line + (dx & ~15) / (8 / BPL)); + if (dx & 15) { + fill8_2col((u8 *)dest + 1, fgcolor, bgcolor, *data++); + dest += BPL / 2; + width -= 8; + } + + if (width >= 16) { + data16 = (const u16 *)data; + expand16_2col2mask(fgcolor, bgcolor, fgm, bgm); + + for (rows = width / 16; rows; rows--) { + u16 d = *data16++; + m = d | ((u32)d << 16); + *dest++ = (m & fgm[0]) ^ bgm[0]; + *dest++ = (m & fgm[1]) ^ bgm[1]; + *dest++ = (m & fgm[2]) ^ bgm[2]; + *dest++ = (m & fgm[3]) ^ bgm[3]; + } + + data = (const u8 *)data16; + width &= 15; + } + + if (width) + fill8_2col((u8 *)dest, fgcolor, bgcolor, *data); +} + +#ifdef MODULE +MODULE_LICENSE("GPL"); + +int init_module(void) +{ + return 0; +} + +void cleanup_module(void) +{ +} +#endif /* MODULE */ + + + /* + * Visible symbols for modules + */ + +EXPORT_SYMBOL(atafb_iplan2p8_copyarea); +EXPORT_SYMBOL(atafb_iplan2p8_fillrect); +EXPORT_SYMBOL(atafb_iplan2p8_linefill); diff --git a/drivers/video/atafb_mfb.c b/drivers/video/atafb_mfb.c new file mode 100644 index 00000000000..6a352d62eec --- /dev/null +++ b/drivers/video/atafb_mfb.c @@ -0,0 +1,112 @@ +/* + * linux/drivers/video/mfb.c -- Low level frame buffer operations for + * monochrome + * + * Created 5 Apr 1997 by Geert Uytterhoeven + * + * 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/module.h> +#include <linux/string.h> +#include <linux/fb.h> + +#include "atafb.h" +#include "atafb_utils.h" + + + /* + * Monochrome + */ + +void atafb_mfb_copyarea(struct fb_info *info, u_long next_line, + int sy, int sx, int dy, int dx, + int height, int width) +{ + u8 *src, *dest; + u_int rows; + + if (sx == 0 && dx == 0 && width == next_line) { + src = (u8 *)info->screen_base + sy * (width >> 3); + dest = (u8 *)info->screen_base + dy * (width >> 3); + fb_memmove(dest, src, height * (width >> 3)); + } else if (dy <= sy) { + src = (u8 *)info->screen_base + sy * next_line + (sx >> 3); + dest = (u8 *)info->screen_base + dy * next_line + (dx >> 3); + for (rows = height; rows--;) { + fb_memmove(dest, src, width >> 3); + src += next_line; + dest += next_line; + } + } else { + src = (u8 *)info->screen_base + (sy + height - 1) * next_line + (sx >> 3); + dest = (u8 *)info->screen_base + (dy + height - 1) * next_line + (dx >> 3); + for (rows = height; rows--;) { + fb_memmove(dest, src, width >> 3); + src -= next_line; + dest -= next_line; + } + } +} + +void atafb_mfb_fillrect(struct fb_info *info, u_long next_line, u32 color, + int sy, int sx, int height, int width) +{ + u8 *dest; + u_int rows; + + dest = (u8 *)info->screen_base + sy * next_line + (sx >> 3); + + if (sx == 0 && width == next_line) { + if (color) + fb_memset255(dest, height * (width >> 3)); + else + fb_memclear(dest, height * (width >> 3)); + } else { + for (rows = height; rows--; dest += next_line) { + if (color) + fb_memset255(dest, width >> 3); + else + fb_memclear_small(dest, width >> 3); + } + } +} + +void atafb_mfb_linefill(struct fb_info *info, u_long next_line, + int dy, int dx, u32 width, + const u8 *data, u32 bgcolor, u32 fgcolor) +{ + u8 *dest; + u_int rows; + + dest = (u8 *)info->screen_base + dy * next_line + (dx >> 3); + + for (rows = width / 8; rows--; /* check margins */ ) { + // use fast_memmove or fb_memmove + *dest++ = *data++; + } +} + +#ifdef MODULE +MODULE_LICENSE("GPL"); + +int init_module(void) +{ + return 0; +} + +void cleanup_module(void) +{ +} +#endif /* MODULE */ + + + /* + * Visible symbols for modules + */ + +EXPORT_SYMBOL(atafb_mfb_copyarea); +EXPORT_SYMBOL(atafb_mfb_fillrect); +EXPORT_SYMBOL(atafb_mfb_linefill); diff --git a/drivers/video/atafb_utils.h b/drivers/video/atafb_utils.h new file mode 100644 index 00000000000..ac9e19dc505 --- /dev/null +++ b/drivers/video/atafb_utils.h @@ -0,0 +1,400 @@ +#ifndef _VIDEO_ATAFB_UTILS_H +#define _VIDEO_ATAFB_UTILS_H + +/* ================================================================= */ +/* Utility Assembler Functions */ +/* ================================================================= */ + +/* ====================================================================== */ + +/* Those of a delicate disposition might like to skip the next couple of + * pages. + * + * These functions are drop in replacements for memmove and + * memset(_, 0, _). However their five instances add at least a kilobyte + * to the object file. You have been warned. + * + * Not a great fan of assembler for the sake of it, but I think + * that these routines are at least 10 times faster than their C + * equivalents for large blits, and that's important to the lowest level of + * a graphics driver. Question is whether some scheme with the blitter + * would be faster. I suspect not for simple text system - not much + * asynchrony. + * + * Code is very simple, just gruesome expansion. Basic strategy is to + * increase data moved/cleared at each step to 16 bytes to reduce + * instruction per data move overhead. movem might be faster still + * For more than 15 bytes, we try to align the write direction on a + * longword boundary to get maximum speed. This is even more gruesome. + * Unaligned read/write used requires 68020+ - think this is a problem? + * + * Sorry! + */ + + +/* ++roman: I've optimized Robert's original versions in some minor + * aspects, e.g. moveq instead of movel, let gcc choose the registers, + * use movem in some places... + * For other modes than 1 plane, lots of more such assembler functions + * were needed (e.g. the ones using movep or expanding color values). + */ + +/* ++andreas: more optimizations: + subl #65536,d0 replaced by clrw d0; subql #1,d0 for dbcc + addal is faster than addaw + movep is rather expensive compared to ordinary move's + some functions rewritten in C for clarity, no speed loss */ + +static inline void *fb_memclear_small(void *s, size_t count) +{ + if (!count) + return 0; + + asm volatile ("\n" + " lsr.l #1,%1 ; jcc 1f ; move.b %2,-(%0)\n" + "1: lsr.l #1,%1 ; jcc 1f ; move.w %2,-(%0)\n" + "1: lsr.l #1,%1 ; jcc 1f ; move.l %2,-(%0)\n" + "1: lsr.l #1,%1 ; jcc 1f ; move.l %2,-(%0) ; move.l %2,-(%0)\n" + "1:" + : "=a" (s), "=d" (count) + : "d" (0), "0" ((char *)s + count), "1" (count)); + asm volatile ("\n" + " subq.l #1,%1\n" + " jcs 3f\n" + " move.l %2,%%d4; move.l %2,%%d5; move.l %2,%%d6\n" + "2: movem.l %2/%%d4/%%d5/%%d6,-(%0)\n" + " dbra %1,2b\n" + "3:" + : "=a" (s), "=d" (count) + : "d" (0), "0" (s), "1" (count) + : "d4", "d5", "d6" + ); + + return 0; +} + + +static inline void *fb_memclear(void *s, size_t count) +{ + if (!count) + return 0; + + if (count < 16) { + asm volatile ("\n" + " lsr.l #1,%1 ; jcc 1f ; clr.b (%0)+\n" + "1: lsr.l #1,%1 ; jcc 1f ; clr.w (%0)+\n" + "1: lsr.l #1,%1 ; jcc 1f ; clr.l (%0)+\n" + "1: lsr.l #1,%1 ; jcc 1f ; clr.l (%0)+ ; clr.l (%0)+\n" + "1:" + : "=a" (s), "=d" (count) + : "0" (s), "1" (count)); + } else { + long tmp; + asm volatile ("\n" + " move.l %1,%2\n" + " lsr.l #1,%2 ; jcc 1f ; clr.b (%0)+ ; subq.w #1,%1\n" + " lsr.l #1,%2 ; jcs 2f\n" /* %0 increased=>bit 2 switched*/ + " clr.w (%0)+ ; subq.w #2,%1 ; jra 2f\n" + "1: lsr.l #1,%2 ; jcc 2f\n" + " clr.w (%0)+ ; subq.w #2,%1\n" + "2: move.w %1,%2; lsr.l #2,%1 ; jeq 6f\n" + " lsr.l #1,%1 ; jcc 3f ; clr.l (%0)+\n" + "3: lsr.l #1,%1 ; jcc 4f ; clr.l (%0)+ ; clr.l (%0)+\n" + "4: subq.l #1,%1 ; jcs 6f\n" + "5: clr.l (%0)+; clr.l (%0)+ ; clr.l (%0)+ ; clr.l (%0)+\n" + " dbra %1,5b ; clr.w %1; subq.l #1,%1; jcc 5b\n" + "6: move.w %2,%1; btst #1,%1 ; jeq 7f ; clr.w (%0)+\n" + "7: btst #0,%1 ; jeq 8f ; clr.b (%0)+\n" + "8:" + : "=a" (s), "=d" (count), "=d" (tmp) + : "0" (s), "1" (count)); + } + + return 0; +} + + +static inline void *fb_memset255(void *s, size_t count) +{ + if (!count) + return 0; + + asm volatile ("\n" + " lsr.l #1,%1 ; jcc 1f ; move.b %2,-(%0)\n" + "1: lsr.l #1,%1 ; jcc 1f ; move.w %2,-(%0)\n" + "1: lsr.l #1,%1 ; jcc 1f ; move.l %2,-(%0)\n" + "1: lsr.l #1,%1 ; jcc 1f ; move.l %2,-(%0) ; move.l %2,-(%0)\n" + "1:" + : "=a" (s), "=d" (count) + : "d" (-1), "0" ((char *)s+count), "1" (count)); + asm volatile ("\n" + " subq.l #1,%1 ; jcs 3f\n" + " move.l %2,%%d4; move.l %2,%%d5; move.l %2,%%d6\n" + "2: movem.l %2/%%d4/%%d5/%%d6,-(%0)\n" + " dbra %1,2b\n" + "3:" + : "=a" (s), "=d" (count) + : "d" (-1), "0" (s), "1" (count) + : "d4", "d5", "d6"); + + return 0; +} + + +static inline void *fb_memmove(void *d, const void *s, size_t count) +{ + if (d < s) { + if (count < 16) { + asm volatile ("\n" + " lsr.l #1,%2 ; jcc 1f ; move.b (%1)+,(%0)+\n" + "1: lsr.l #1,%2 ; jcc 1f ; move.w (%1)+,(%0)+\n" + "1: lsr.l #1,%2 ; jcc 1f ; move.l (%1)+,(%0)+\n" + "1: lsr.l #1,%2 ; jcc 1f ; move.l (%1)+,(%0)+ ; move.l (%1)+,(%0)+\n" + "1:" + : "=a" (d), "=a" (s), "=d" (count) + : "0" (d), "1" (s), "2" (count)); + } else { + long tmp; + asm volatile ("\n" + " move.l %0,%3\n" + " lsr.l #1,%3 ; jcc 1f ; move.b (%1)+,(%0)+ ; subqw #1,%2\n" + " lsr.l #1,%3 ; jcs 2f\n" /* %0 increased=>bit 2 switched*/ + " move.w (%1)+,(%0)+ ; subqw #2,%2 ; jra 2f\n" + "1: lsr.l #1,%3 ; jcc 2f\n" + " move.w (%1)+,(%0)+ ; subqw #2,%2\n" + "2: move.w %2,%-; lsr.l #2,%2 ; jeq 6f\n" + " lsr.l #1,%2 ; jcc 3f ; move.l (%1)+,(%0)+\n" + "3: lsr.l #1,%2 ; jcc 4f ; move.l (%1)+,(%0)+ ; move.l (%1)+,(%0)+\n" + "4: subq.l #1,%2 ; jcs 6f\n" + "5: move.l (%1)+,(%0)+; move.l (%1)+,(%0)+\n" + " move.l (%1)+,(%0)+; move.l (%1)+,(%0)+\n" + " dbra %2,5b ; clr.w %2; subq.l #1,%2; jcc 5b\n" + "6: move.w %+,%2; btst #1,%2 ; jeq 7f ; move.w (%1)+,(%0)+\n" + "7: btst #0,%2 ; jeq 8f ; move.b (%1)+,(%0)+\n" + "8:" + : "=a" (d), "=a" (s), "=d" (count), "=d" (tmp) + : "0" (d), "1" (s), "2" (count)); + } + } else { + if (count < 16) { + asm volatile ("\n" + " lsr.l #1,%2 ; jcc 1f ; move.b -(%1),-(%0)\n" + "1: lsr.l #1,%2 ; jcc 1f ; move.w -(%1),-(%0)\n" + "1: lsr.l #1,%2 ; jcc 1f ; move.l -(%1),-(%0)\n" + "1: lsr.l #1,%2 ; jcc 1f ; move.l -(%1),-(%0) ; move.l -(%1),-(%0)\n" + "1:" + : "=a" (d), "=a" (s), "=d" (count) + : "0" ((char *) d + count), "1" ((char *) s + count), "2" (count)); + } else { + long tmp; + + asm volatile ("\n" + " move.l %0,%3\n" + " lsr.l #1,%3 ; jcc 1f ; move.b -(%1),-(%0) ; subqw #1,%2\n" + " lsr.l #1,%3 ; jcs 2f\n" /* %0 increased=>bit 2 switched*/ + " move.w -(%1),-(%0) ; subqw #2,%2 ; jra 2f\n" + "1: lsr.l #1,%3 ; jcc 2f\n" + " move.w -(%1),-(%0) ; subqw #2,%2\n" + "2: move.w %2,%-; lsr.l #2,%2 ; jeq 6f\n" + " lsr.l #1,%2 ; jcc 3f ; move.l -(%1),-(%0)\n" + "3: lsr.l #1,%2 ; jcc 4f ; move.l -(%1),-(%0) ; move.l -(%1),-(%0)\n" + "4: subq.l #1,%2 ; jcs 6f\n" + "5: move.l -(%1),-(%0); move.l -(%1),-(%0)\n" + " move.l -(%1),-(%0); move.l -(%1),-(%0)\n" + " dbra %2,5b ; clr.w %2; subq.l #1,%2; jcc 5b\n" + "6: move.w %+,%2; btst #1,%2 ; jeq 7f ; move.w -(%1),-(%0)\n" + "7: btst #0,%2 ; jeq 8f ; move.b -(%1),-(%0)\n" + "8:" + : "=a" (d), "=a" (s), "=d" (count), "=d" (tmp) + : "0" ((char *) d + count), "1" ((char *) s + count), "2" (count)); + } + } + + return 0; +} + + +/* ++andreas: Simple and fast version of memmove, assumes size is + divisible by 16, suitable for moving the whole screen bitplane */ +static inline void fast_memmove(char *dst, const char *src, size_t size) +{ + if (!size) + return; + if (dst < src) + asm volatile ("\n" + "1: movem.l (%0)+,%%d0/%%d1/%%a0/%%a1\n" + " movem.l %%d0/%%d1/%%a0/%%a1,%1@\n" + " addq.l #8,%1; addq.l #8,%1\n" + " dbra %2,1b\n" + " clr.w %2; subq.l #1,%2\n" + " jcc 1b" + : "=a" (src), "=a" (dst), "=d" (size) + : "0" (src), "1" (dst), "2" (size / 16 - 1) + : "d0", "d1", "a0", "a1", "memory"); + else + asm volatile ("\n" + "1: subq.l #8,%0; subq.l #8,%0\n" + " movem.l %0@,%%d0/%%d1/%%a0/%%a1\n" + " movem.l %%d0/%%d1/%%a0/%%a1,-(%1)\n" + " dbra %2,1b\n" + " clr.w %2; subq.l #1,%2\n" + " jcc 1b" + : "=a" (src), "=a" (dst), "=d" (size) + : "0" (src + size), "1" (dst + size), "2" (size / 16 - 1) + : "d0", "d1", "a0", "a1", "memory"); +} + +#ifdef BPL + +/* + * This expands a up to 8 bit color into two longs + * for movel operations. + */ +static const u32 four2long[] = { + 0x00000000, 0x000000ff, 0x0000ff00, 0x0000ffff, + 0x00ff0000, 0x00ff00ff, 0x00ffff00, 0x00ffffff, + 0xff000000, 0xff0000ff, 0xff00ff00, 0xff00ffff, + 0xffff0000, 0xffff00ff, 0xffffff00, 0xffffffff, +}; + +static inline void expand8_col2mask(u8 c, u32 m[]) +{ + m[0] = four2long[c & 15]; +#if BPL > 4 + m[1] = four2long[c >> 4]; +#endif +} + +static inline void expand8_2col2mask(u8 fg, u8 bg, u32 fgm[], u32 bgm[]) +{ + fgm[0] = four2long[fg & 15] ^ (bgm[0] = four2long[bg & 15]); +#if BPL > 4 + fgm[1] = four2long[fg >> 4] ^ (bgm[1] = four2long[bg >> 4]); +#endif +} + +/* + * set an 8bit value to a color + */ +static inline void fill8_col(u8 *dst, u32 m[]) +{ + u32 tmp = m[0]; + dst[0] = tmp; + dst[2] = (tmp >>= 8); +#if BPL > 2 + dst[4] = (tmp >>= 8); + dst[6] = tmp >> 8; +#endif +#if BPL > 4 + tmp = m[1]; + dst[8] = tmp; + dst[10] = (tmp >>= 8); + dst[12] = (tmp >>= 8); + dst[14] = tmp >> 8; +#endif +} + +/* + * set an 8bit value according to foreground/background color + */ +static inline void fill8_2col(u8 *dst, u8 fg, u8 bg, u32 mask) +{ + u32 fgm[2], bgm[2], tmp; + + expand8_2col2mask(fg, bg, fgm, bgm); + + mask |= mask << 8; +#if BPL > 2 + mask |= mask << 16; +#endif + tmp = (mask & fgm[0]) ^ bgm[0]; + dst[0] = tmp; + dst[2] = (tmp >>= 8); +#if BPL > 2 + dst[4] = (tmp >>= 8); + dst[6] = tmp >> 8; +#endif +#if BPL > 4 + tmp = (mask & fgm[1]) ^ bgm[1]; + dst[8] = tmp; + dst[10] = (tmp >>= 8); + dst[12] = (tmp >>= 8); + dst[14] = tmp >> 8; +#endif +} + +static const u32 two2word[] = { + 0x00000000, 0xffff0000, 0x0000ffff, 0xffffffff +}; + +static inline void expand16_col2mask(u8 c, u32 m[]) +{ + m[0] = two2word[c & 3]; +#if BPL > 2 + m[1] = two2word[(c >> 2) & 3]; +#endif +#if BPL > 4 + m[2] = two2word[(c >> 4) & 3]; + m[3] = two2word[c >> 6]; +#endif +} + +static inline void expand16_2col2mask(u8 fg, u8 bg, u32 fgm[], u32 bgm[]) +{ + bgm[0] = two2word[bg & 3]; + fgm[0] = two2word[fg & 3] ^ bgm[0]; +#if BPL > 2 + bgm[1] = two2word[(bg >> 2) & 3]; + fgm[1] = two2word[(fg >> 2) & 3] ^ bgm[1]; +#endif +#if BPL > 4 + bgm[2] = two2word[(bg >> 4) & 3]; + fgm[2] = two2word[(fg >> 4) & 3] ^ bgm[2]; + bgm[3] = two2word[bg >> 6]; + fgm[3] = two2word[fg >> 6] ^ bgm[3]; +#endif +} + +static inline u32 *fill16_col(u32 *dst, int rows, u32 m[]) +{ + while (rows) { + *dst++ = m[0]; +#if BPL > 2 + *dst++ = m[1]; +#endif +#if BPL > 4 + *dst++ = m[2]; + *dst++ = m[3]; +#endif + rows--; + } + return dst; +} + +static inline void memmove32_col(void *dst, void *src, u32 mask, u32 h, u32 bytes) +{ + u32 *s, *d, v; + + s = src; + d = dst; + do { + v = (*s++ & mask) | (*d & ~mask); + *d++ = v; +#if BPL > 2 + v = (*s++ & mask) | (*d & ~mask); + *d++ = v; +#endif +#if BPL > 4 + v = (*s++ & mask) | (*d & ~mask); + *d++ = v; + v = (*s++ & mask) | (*d & ~mask); + *d++ = v; +#endif + d = (u32 *)((u8 *)d + bytes); + s = (u32 *)((u8 *)s + bytes); + } while (--h); +} + +#endif + +#endif /* _VIDEO_ATAFB_UTILS_H */ diff --git a/drivers/video/intelfb/intelfb_i2c.c b/drivers/video/intelfb/intelfb_i2c.c index f4ede5f6b58..61e4c8759b2 100644 --- a/drivers/video/intelfb/intelfb_i2c.c +++ b/drivers/video/intelfb/intelfb_i2c.c @@ -104,7 +104,8 @@ static int intelfb_setup_i2c_bus(struct intelfb_info *dinfo, chan->dinfo = dinfo; chan->reg = reg; - snprintf(chan->adapter.name, I2C_NAME_SIZE, "intelfb %s", name); + snprintf(chan->adapter.name, sizeof(chan->adapter.name), + "intelfb %s", name); chan->adapter.owner = THIS_MODULE; chan->adapter.id = I2C_HW_B_INTELFB; chan->adapter.algo_data = &chan->algo; diff --git a/drivers/video/matrox/i2c-matroxfb.c b/drivers/video/matrox/i2c-matroxfb.c index 5ec718a5fe2..4baab7be58d 100644 --- a/drivers/video/matrox/i2c-matroxfb.c +++ b/drivers/video/matrox/i2c-matroxfb.c @@ -111,7 +111,7 @@ static int i2c_bus_reg(struct i2c_bit_adapter* b, struct matrox_fb_info* minfo, b->mask.data = data; b->mask.clock = clock; b->adapter = matrox_i2c_adapter_template; - snprintf(b->adapter.name, I2C_NAME_SIZE, name, + snprintf(b->adapter.name, sizeof(b->adapter.name), name, minfo->fbcon.node); i2c_set_adapdata(&b->adapter, b); b->adapter.algo_data = &b->bac; diff --git a/drivers/video/ps3fb.c b/drivers/video/ps3fb.c index 81e43cda7d8..07d1979bc23 100644 --- a/drivers/video/ps3fb.c +++ b/drivers/video/ps3fb.c @@ -32,6 +32,8 @@ #include <linux/ioctl.h> #include <linux/notifier.h> #include <linux/reboot.h> +#include <linux/kthread.h> +#include <linux/freezer.h> #include <asm/uaccess.h> #include <linux/fb.h> @@ -45,7 +47,7 @@ #include <asm/ps3.h> #ifdef PS3FB_DEBUG -#define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ##args) +#define DPRINTK(fmt, args...) printk("%s: " fmt, __func__ , ##args) #else #define DPRINTK(fmt, args...) #endif @@ -129,7 +131,6 @@ struct ps3fb_priv { u64 context_handle, memory_handle; void *xdr_ea; struct gpu_driver_info *dinfo; - struct semaphore sem; u32 res_index; u64 vblank_count; /* frame count */ @@ -139,6 +140,8 @@ struct ps3fb_priv { atomic_t ext_flip; /* on/off flip with vsync */ atomic_t f_count; /* fb_open count */ int is_blanked; + int is_kicked; + struct task_struct *task; }; static struct ps3fb_priv ps3fb; @@ -294,10 +297,10 @@ static const struct fb_videomode ps3fb_modedb[] = { #define VP_OFF(i) (WIDTH(i) * Y_OFF(i) * BPP + X_OFF(i) * BPP) #define FB_OFF(i) (GPU_OFFSET - VP_OFF(i) % GPU_OFFSET) -static int ps3fb_mode = 0; +static int ps3fb_mode; module_param(ps3fb_mode, bool, 0); -static char *mode_option __initdata = NULL; +static char *mode_option __initdata; static int ps3fb_get_res_table(u32 xres, u32 yres) @@ -393,7 +396,7 @@ static int ps3fb_sync(u32 frame) if (frame > ps3fb.num_frames - 1) { printk(KERN_WARNING "%s: invalid frame number (%u)\n", - __FUNCTION__, frame); + __func__, frame); return -EINVAL; } offset = xres * yres * BPP * frame; @@ -406,23 +409,26 @@ static int ps3fb_sync(u32 frame) (xres << 16) | yres, xres * BPP); /* line_length */ if (status) - printk(KERN_ERR "%s: lv1_gpu_context_attribute FB_BLIT failed: %d\n", - __FUNCTION__, status); + printk(KERN_ERR + "%s: lv1_gpu_context_attribute FB_BLIT failed: %d\n", + __func__, status); #ifdef HEAD_A status = lv1_gpu_context_attribute(ps3fb.context_handle, L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP, 0, offset, 0, 0); if (status) - printk(KERN_ERR "%s: lv1_gpu_context_attribute FLIP failed: %d\n", - __FUNCTION__, status); + printk(KERN_ERR + "%s: lv1_gpu_context_attribute FLIP failed: %d\n", + __func__, status); #endif #ifdef HEAD_B status = lv1_gpu_context_attribute(ps3fb.context_handle, L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP, 1, offset, 0, 0); if (status) - printk(KERN_ERR "%s: lv1_gpu_context_attribute FLIP failed: %d\n", - __FUNCTION__, status); + printk(KERN_ERR + "%s: lv1_gpu_context_attribute FLIP failed: %d\n", + __func__, status); #endif return 0; } @@ -631,7 +637,7 @@ static int ps3fb_blank(int blank, struct fb_info *info) { int retval; - DPRINTK("%s: blank:%d\n", __FUNCTION__, blank); + DPRINTK("%s: blank:%d\n", __func__, blank); switch (blank) { case FB_BLANK_POWERDOWN: case FB_BLANK_HSYNC_SUSPEND: @@ -677,13 +683,10 @@ EXPORT_SYMBOL_GPL(ps3fb_wait_for_vsync); void ps3fb_flip_ctl(int on) { - if (on) { - if (atomic_read(&ps3fb.ext_flip) > 0) { - atomic_dec(&ps3fb.ext_flip); - } - } else { + if (on) + atomic_dec_if_positive(&ps3fb.ext_flip); + else atomic_inc(&ps3fb.ext_flip); - } } EXPORT_SYMBOL_GPL(ps3fb_flip_ctl); @@ -732,6 +735,11 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd, if (copy_from_user(&val, argp, sizeof(val))) break; + if (!(val & PS3AV_MODE_MASK)) { + u32 id = ps3av_get_auto_mode(0); + if (id > 0) + val = (val & ~PS3AV_MODE_MASK) | id; + } DPRINTK("PS3FB_IOCTL_SETMODE:%x\n", val); retval = -EINVAL; old_mode = ps3fb_mode; @@ -783,8 +791,7 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd, case PS3FB_IOCTL_OFF: DPRINTK("PS3FB_IOCTL_OFF:\n"); - if (atomic_read(&ps3fb.ext_flip) > 0) - atomic_dec(&ps3fb.ext_flip); + atomic_dec_if_positive(&ps3fb.ext_flip); retval = 0; break; @@ -805,11 +812,14 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd, static int ps3fbd(void *arg) { - daemonize("ps3fbd"); - for (;;) { - down(&ps3fb.sem); - if (atomic_read(&ps3fb.ext_flip) == 0) + while (!kthread_should_stop()) { + try_to_freeze(); + set_current_state(TASK_INTERRUPTIBLE); + if (ps3fb.is_kicked) { + ps3fb.is_kicked = 0; ps3fb_sync(0); /* single buffer */ + } + schedule(); } return 0; } @@ -823,15 +833,18 @@ static irqreturn_t ps3fb_vsync_interrupt(int irq, void *ptr) status = lv1_gpu_context_intr(ps3fb.context_handle, &v1); if (status) { printk(KERN_ERR "%s: lv1_gpu_context_intr failed: %d\n", - __FUNCTION__, status); + __func__, status); return IRQ_NONE; } if (v1 & (1 << GPU_INTR_STATUS_VSYNC_1)) { /* VSYNC */ ps3fb.vblank_count = head->vblank_count; - if (!ps3fb.is_blanked) - up(&ps3fb.sem); + if (ps3fb.task && !ps3fb.is_blanked && + !atomic_read(&ps3fb.ext_flip)) { + ps3fb.is_kicked = 1; + wake_up_process(ps3fb.task); + } wake_up_interruptible(&ps3fb.wait_vsync); } @@ -879,7 +892,7 @@ static int ps3fb_vsync_settings(struct gpu_driver_info *dinfo, void *dev) dinfo->nvcore_frequency/1000000, dinfo->memory_frequency/1000000); if (dinfo->version_driver != GPU_DRIVER_INFO_VERSION) { - printk(KERN_ERR "%s: version_driver err:%x\n", __FUNCTION__, + printk(KERN_ERR "%s: version_driver err:%x\n", __func__, dinfo->version_driver); return -EINVAL; } @@ -888,7 +901,7 @@ static int ps3fb_vsync_settings(struct gpu_driver_info *dinfo, void *dev) error = ps3_alloc_irq(PS3_BINDING_CPU_ANY, dinfo->irq.irq_outlet, &ps3fb.irq_no); if (error) { - printk(KERN_ERR "%s: ps3_alloc_irq failed %d\n", __FUNCTION__, + printk(KERN_ERR "%s: ps3_alloc_irq failed %d\n", __func__, error); return error; } @@ -896,7 +909,7 @@ static int ps3fb_vsync_settings(struct gpu_driver_info *dinfo, void *dev) error = request_irq(ps3fb.irq_no, ps3fb_vsync_interrupt, IRQF_DISABLED, "ps3fb vsync", ps3fb.dev); if (error) { - printk(KERN_ERR "%s: request_irq failed %d\n", __FUNCTION__, + printk(KERN_ERR "%s: request_irq failed %d\n", __func__, error); ps3_free_irq(ps3fb.irq_no); return error; @@ -915,7 +928,7 @@ static int ps3fb_xdr_settings(u64 xdr_lpar) xdr_lpar, ps3fb_videomemory.size, 0); if (status) { printk(KERN_ERR "%s: lv1_gpu_context_iomap failed: %d\n", - __FUNCTION__, status); + __func__, status); return -ENXIO; } DPRINTK("video:%p xdr_ea:%p ioif:%lx lpar:%lx phys:%lx size:%lx\n", @@ -927,8 +940,9 @@ static int ps3fb_xdr_settings(u64 xdr_lpar) xdr_lpar, ps3fb_videomemory.size, GPU_IOIF, 0); if (status) { - printk(KERN_ERR "%s: lv1_gpu_context_attribute FB_SETUP failed: %d\n", - __FUNCTION__, status); + printk(KERN_ERR + "%s: lv1_gpu_context_attribute FB_SETUP failed: %d\n", + __func__, status); return -ENXIO; } return 0; @@ -968,13 +982,14 @@ static int __init ps3fb_probe(struct platform_device *dev) u64 xdr_lpar; int status; unsigned long offset; + struct task_struct *task; /* get gpu context handle */ status = lv1_gpu_memory_allocate(DDR_SIZE, 0, 0, 0, 0, &ps3fb.memory_handle, &ddr_lpar); if (status) { printk(KERN_ERR "%s: lv1_gpu_memory_allocate failed: %d\n", - __FUNCTION__, status); + __func__, status); goto err; } DPRINTK("ddr:lpar:0x%lx\n", ddr_lpar); @@ -985,14 +1000,14 @@ static int __init ps3fb_probe(struct platform_device *dev) &lpar_reports, &lpar_reports_size); if (status) { printk(KERN_ERR "%s: lv1_gpu_context_attribute failed: %d\n", - __FUNCTION__, status); + __func__, status); goto err_gpu_memory_free; } /* vsync interrupt */ ps3fb.dinfo = ioremap(lpar_driver_info, 128 * 1024); if (!ps3fb.dinfo) { - printk(KERN_ERR "%s: ioremap failed\n", __FUNCTION__); + printk(KERN_ERR "%s: ioremap failed\n", __func__); goto err_gpu_context_free; } @@ -1050,9 +1065,18 @@ static int __init ps3fb_probe(struct platform_device *dev) "fb%d: PS3 frame buffer device, using %ld KiB of video memory\n", info->node, ps3fb_videomemory.size >> 10); - kernel_thread(ps3fbd, info, CLONE_KERNEL); + task = kthread_run(ps3fbd, info, "ps3fbd"); + if (IS_ERR(task)) { + retval = PTR_ERR(task); + goto err_unregister_framebuffer; + } + + ps3fb.task = task; + return 0; +err_unregister_framebuffer: + unregister_framebuffer(info); err_fb_dealloc: fb_dealloc_cmap(&info->cmap); err_framebuffer_release: @@ -1083,6 +1107,11 @@ void ps3fb_cleanup(void) { int status; + if (ps3fb.task) { + struct task_struct *task = ps3fb.task; + ps3fb.task = NULL; + kthread_stop(task); + } if (ps3fb.irq_no) { free_irq(ps3fb.irq_no, ps3fb.dev); ps3_free_irq(ps3fb.irq_no); @@ -1137,8 +1166,9 @@ int ps3fb_set_sync(void) L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC, 0, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0); if (status) { - printk(KERN_ERR "%s: lv1_gpu_context_attribute DISPLAY_SYNC failed: %d\n", - __FUNCTION__, status); + printk(KERN_ERR + "%s: lv1_gpu_context_attribute DISPLAY_SYNC failed: %d\n", + __func__, status); return -1; } #endif @@ -1148,8 +1178,9 @@ int ps3fb_set_sync(void) 1, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0); if (status) { - printk(KERN_ERR "%s: lv1_gpu_context_attribute DISPLAY_MODE failed: %d\n", - __FUNCTION__, status); + printk(KERN_ERR + "%s: lv1_gpu_context_attribute DISPLAY_MODE failed: %d\n", + __func__, status); return -1; } #endif @@ -1174,7 +1205,7 @@ static int __init ps3fb_init(void) error = ps3av_dev_open(); if (error) { - printk(KERN_ERR "%s: ps3av_dev_open failed\n", __FUNCTION__); + printk(KERN_ERR "%s: ps3av_dev_open failed\n", __func__); goto err; } @@ -1195,7 +1226,6 @@ static int __init ps3fb_init(void) atomic_set(&ps3fb.f_count, -1); /* fbcon opens ps3fb */ atomic_set(&ps3fb.ext_flip, 0); /* for flip with vsync */ - init_MUTEX(&ps3fb.sem); init_waitqueue_head(&ps3fb.wait_vsync); ps3fb.num_frames = 1; diff --git a/drivers/zorro/proc.c b/drivers/zorro/proc.c index b3ce8859a58..2ce4cebc31d 100644 --- a/drivers/zorro/proc.c +++ b/drivers/zorro/proc.c @@ -90,8 +90,9 @@ get_zorro_dev_info(char *buf, char **start, off_t pos, int count) for (slot = cnt = 0; slot < zorro_num_autocon && count > cnt; slot++) { struct zorro_dev *z = &zorro_autocon[slot]; len = sprintf(buf, "%02x\t%08x\t%08lx\t%08lx\t%02x\n", slot, - z->id, zorro_resource_start(z), - zorro_resource_len(z), z->rom.er_Type); + z->id, (unsigned long)zorro_resource_start(z), + (unsigned long)zorro_resource_len(z), + z->rom.er_Type); at += len; if (at >= pos) { if (!*start) { diff --git a/drivers/zorro/zorro-sysfs.c b/drivers/zorro/zorro-sysfs.c index 87c29d7b6c1..c3ba0ec334c 100644 --- a/drivers/zorro/zorro-sysfs.c +++ b/drivers/zorro/zorro-sysfs.c @@ -42,7 +42,8 @@ static ssize_t zorro_show_resource(struct device *dev, struct device_attribute * struct zorro_dev *z = to_zorro_dev(dev); return sprintf(buf, "0x%08lx 0x%08lx 0x%08lx\n", - zorro_resource_start(z), zorro_resource_end(z), + (unsigned long)zorro_resource_start(z), + (unsigned long)zorro_resource_end(z), zorro_resource_flags(z)); } diff --git a/drivers/zorro/zorro.c b/drivers/zorro/zorro.c index 0f2b40605b0..4cc42b64820 100644 --- a/drivers/zorro/zorro.c +++ b/drivers/zorro/zorro.c @@ -164,7 +164,8 @@ static int __init zorro_init(void) if (request_resource(zorro_find_parent_resource(z), &z->resource)) printk(KERN_ERR "Zorro: Address space collision on device %s " "[%lx:%lx]\n", - z->name, zorro_resource_start(z), zorro_resource_end(z)); + z->name, (unsigned long)zorro_resource_start(z), + (unsigned long)zorro_resource_end(z)); sprintf(z->dev.bus_id, "%02x", i); z->dev.parent = &zorro_bus.dev; z->dev.bus = &zorro_bus_type; diff --git a/include/asm-i386/agp.h b/include/asm-i386/agp.h index 9075083bab7..6af173dbf12 100644 --- a/include/asm-i386/agp.h +++ b/include/asm-i386/agp.h @@ -12,8 +12,10 @@ * data corruption on some CPUs. */ -int map_page_into_agp(struct page *page); -int unmap_page_from_agp(struct page *page); +/* Caller's responsibility to call global_flush_tlb() for + * performance reasons */ +#define map_page_into_agp(page) change_page_attr(page, 1, PAGE_KERNEL_NOCACHE) +#define unmap_page_from_agp(page) change_page_attr(page, 1, PAGE_KERNEL) #define flush_agp_mappings() global_flush_tlb() /* Could use CLFLUSH here if the cpu supports it. But then it would diff --git a/include/asm-m68k/adb.h b/include/asm-m68k/adb.h deleted file mode 100644 index 9176b55185b..00000000000 --- a/include/asm-m68k/adb.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Definitions for talking to ADB and CUDA. The CUDA is a microcontroller - * which controls the ADB, system power, RTC, and various other things on - * later Macintoshes - * - * Copyright (C) 1996 Paul Mackerras. - */ - -/* First byte sent to or received from CUDA */ -#define ADB_PACKET 0 -#define CUDA_PACKET 1 -#define ERROR_PACKET 2 -#define TIMER_PACKET 3 -#define POWER_PACKET 4 -#define MACIIC_PACKET 5 - -/* ADB commands (2nd byte) */ -#define ADB_BUSRESET 0 -#define ADB_FLUSH(id) (1 + ((id) << 4)) -#define ADB_WRITEREG(id, reg) (8 + (reg) + ((id) << 4)) -#define ADB_READREG(id, reg) (0xc + (reg) + ((id) << 4)) - -/* ADB default device IDs (upper 4 bits of 2nd byte) */ -#define ADB_DONGLE 1 /* "software execution control" devices */ -#define ADB_KEYBOARD 2 -#define ADB_MOUSE 3 -#define ADB_TABLET 4 -#define ADB_MODEM 5 -#define ADB_MISC 7 /* maybe a monitor */ - -/* CUDA commands (2nd byte) */ -#define CUDA_WARM_START 0 -#define CUDA_AUTOPOLL 1 -#define CUDA_GET_6805_ADDR 2 -#define CUDA_GET_TIME 3 -#define CUDA_GET_PRAM 7 -#define CUDA_SET_6805_ADDR 8 -#define CUDA_SET_TIME 9 -#define CUDA_POWERDOWN 0xa -#define CUDA_POWERUP_TIME 0xb -#define CUDA_SET_PRAM 0xc -#define CUDA_MS_RESET 0xd -#define CUDA_SEND_DFAC 0xe -#define CUDA_RESET_SYSTEM 0x11 -#define CUDA_SET_IPL 0x12 -#define CUDA_SET_AUTO_RATE 0x14 -#define CUDA_GET_AUTO_RATE 0x16 -#define CUDA_SET_DEVICE_LIST 0x19 -#define CUDA_GET_DEVICE_LIST 0x1a -#define CUDA_GET_SET_IIC 0x22 - -#ifdef __KERNEL__ - -struct adb_request { - unsigned char data[16]; - int nbytes; - unsigned char reply[16]; - int reply_len; - unsigned char reply_expected; - unsigned char sent; - unsigned char got_reply; - void (*done)(struct adb_request *); - void *arg; - struct adb_request *next; -}; - -void via_adb_init(void); -int adb_request(struct adb_request *req, - void (*done)(struct adb_request *), int nbytes, ...); -int adb_send_request(struct adb_request *req); -void adb_poll(void); -int adb_register(int default_id, - void (*handler)(unsigned char *, int, struct pt_regs *)); - -#endif /* __KERNEL */ diff --git a/include/asm-m68k/atarikb.h b/include/asm-m68k/atarikb.h index 18926058fde..546e7da5804 100644 --- a/include/asm-m68k/atarikb.h +++ b/include/asm-m68k/atarikb.h @@ -36,5 +36,11 @@ void ikbd_joystick_disable(void); extern void (*atari_MIDI_interrupt_hook) (void); /* Hook for mouse driver */ extern void (*atari_mouse_interrupt_hook) (char *); +/* Hook for keyboard inputdev driver */ +extern void (*atari_input_keyboard_interrupt_hook) (unsigned char, char); +/* Hook for mouse inputdev driver */ +extern void (*atari_input_mouse_interrupt_hook) (char *); + +int atari_keyb_init(void); #endif /* _LINUX_ATARIKB_H */ diff --git a/include/asm-powerpc/ps3av.h b/include/asm-powerpc/ps3av.h index 43e90ea9613..9efc40f1c77 100644 --- a/include/asm-powerpc/ps3av.h +++ b/include/asm-powerpc/ps3av.h @@ -18,8 +18,6 @@ #ifndef _ASM_POWERPC_PS3AV_H_ #define _ASM_POWERPC_PS3AV_H_ -#include <linux/mutex.h> - /** command for ioctl() **/ #define PS3AV_VERSION 0x205 /* version of ps3av command */ @@ -643,24 +641,6 @@ struct ps3av_pkt_avb_param { u8 buf[PS3AV_PKT_AVB_PARAM_MAX_BUF_SIZE]; }; -struct ps3av { - int available; - struct semaphore sem; - struct semaphore ping; - struct semaphore pong; - struct mutex mutex; - int open_count; - struct ps3_vuart_port_device *dev; - - int region; - struct ps3av_pkt_av_get_hw_conf av_hw_conf; - u32 av_port[PS3AV_AV_PORT_MAX + PS3AV_OPT_PORT_MAX]; - u32 opt_port[PS3AV_OPT_PORT_MAX]; - u32 head[PS3AV_HEAD_MAX]; - u32 audio_port; - int ps3av_mode; - int ps3av_mode_old; -}; /** command status **/ #define PS3AV_STATUS_SUCCESS 0x0000 /* success */ @@ -718,6 +698,7 @@ static inline void ps3av_cmd_av_monitor_info_dump(const struct ps3av_pkt_av_get_ extern int ps3av_cmd_video_get_monitor_info(struct ps3av_pkt_av_get_monitor_info *, u32); +struct ps3_vuart_port_device; extern int ps3av_vuart_write(struct ps3_vuart_port_device *dev, const void *buf, unsigned long size); extern int ps3av_vuart_read(struct ps3_vuart_port_device *dev, void *buf, @@ -725,6 +706,7 @@ extern int ps3av_vuart_read(struct ps3_vuart_port_device *dev, void *buf, extern int ps3av_set_video_mode(u32, int); extern int ps3av_set_audio_mode(u32, u32, u32, u32, u32); +extern int ps3av_get_auto_mode(int); extern int ps3av_set_mode(u32, int); extern int ps3av_get_mode(void); extern int ps3av_get_scanmode(int); diff --git a/include/asm-s390/ccwdev.h b/include/asm-s390/ccwdev.h index cfc81533b9b..6795ecefd15 100644 --- a/include/asm-s390/ccwdev.h +++ b/include/asm-s390/ccwdev.h @@ -164,9 +164,9 @@ extern int ccw_device_resume(struct ccw_device *); extern int ccw_device_halt(struct ccw_device *, unsigned long); extern int ccw_device_clear(struct ccw_device *, unsigned long); -extern int read_dev_chars(struct ccw_device *cdev, void **buffer, int length); -extern int read_conf_data(struct ccw_device *cdev, void **buffer, int *length); -extern int read_conf_data_lpm(struct ccw_device *cdev, void **buffer, +extern int __deprecated read_dev_chars(struct ccw_device *cdev, void **buffer, int length); +extern int __deprecated read_conf_data(struct ccw_device *cdev, void **buffer, int *length); +extern int __deprecated read_conf_data_lpm(struct ccw_device *cdev, void **buffer, int *length, __u8 lpm); extern int ccw_device_set_online(struct ccw_device *cdev); diff --git a/include/asm-s390/elf.h b/include/asm-s390/elf.h index c0d629d61d3..91d06325cc7 100644 --- a/include/asm-s390/elf.h +++ b/include/asm-s390/elf.h @@ -188,7 +188,8 @@ static inline int dump_task_fpu(struct task_struct *tsk, elf_fpregset_t *fpregs) /* This yields a mask that user programs can use to figure out what instruction set this CPU supports. */ -#define ELF_HWCAP (0) +extern unsigned long elf_hwcap; +#define ELF_HWCAP (elf_hwcap) /* This yields a string that ld.so will use to load implementation specific libraries for optimization. This is more specific in @@ -197,7 +198,9 @@ static inline int dump_task_fpu(struct task_struct *tsk, elf_fpregset_t *fpregs) For the moment, we have only optimizations for the Intel generations, but that could change... */ -#define ELF_PLATFORM (NULL) +#define ELF_PLATFORM_SIZE 8 +extern char elf_platform[]; +#define ELF_PLATFORM (elf_platform) #ifndef __s390x__ #define SET_PERSONALITY(ex, ibcs2) set_personality((ibcs2)?PER_SVR4:PER_LINUX) diff --git a/include/asm-s390/kdebug.h b/include/asm-s390/kdebug.h index 1b50f89819a..d2d7ad27614 100644 --- a/include/asm-s390/kdebug.h +++ b/include/asm-s390/kdebug.h @@ -22,8 +22,21 @@ struct die_args { */ extern int register_die_notifier(struct notifier_block *); extern int unregister_die_notifier(struct notifier_block *); -extern int register_page_fault_notifier(struct notifier_block *); -extern int unregister_page_fault_notifier(struct notifier_block *); + +/* + * These are only here because kprobes.c wants them to implement a + * blatant layering violation. Will hopefully go away soon once all + * architectures are updated. + */ +static inline int register_page_fault_notifier(struct notifier_block *nb) +{ + return 0; +} +static inline int unregister_page_fault_notifier(struct notifier_block *nb) +{ + return 0; +} + extern struct atomic_notifier_head s390die_chain; enum die_val { @@ -39,7 +52,6 @@ enum die_val { DIE_GPF, DIE_CALL, DIE_NMI_IPI, - DIE_PAGE_FAULT, }; static inline int notify_die(enum die_val val, const char *str, diff --git a/include/asm-s390/kprobes.h b/include/asm-s390/kprobes.h index b847ff0ec3f..830fe4c4eea 100644 --- a/include/asm-s390/kprobes.h +++ b/include/asm-s390/kprobes.h @@ -97,18 +97,10 @@ void kretprobe_trampoline(void); int is_prohibited_opcode(kprobe_opcode_t *instruction); void get_instruction_type(struct arch_specific_insn *ainsn); +int kprobe_fault_handler(struct pt_regs *regs, int trapnr); +int kprobe_exceptions_notify(struct notifier_block *self, + unsigned long val, void *data); + #define flush_insn_slot(p) do { } while (0) #endif /* _ASM_S390_KPROBES_H */ - -#ifdef CONFIG_KPROBES - -extern int kprobe_exceptions_notify(struct notifier_block *self, - unsigned long val, void *data); -#else /* !CONFIG_KPROBES */ -static inline int kprobe_exceptions_notify(struct notifier_block *self, - unsigned long val, void *data) -{ - return 0; -} -#endif diff --git a/include/asm-s390/lowcore.h b/include/asm-s390/lowcore.h index ffc9788a21a..801a6fd35b5 100644 --- a/include/asm-s390/lowcore.h +++ b/include/asm-s390/lowcore.h @@ -229,17 +229,19 @@ struct _lowcore __u16 subchannel_nr; /* 0x0ba */ __u32 io_int_parm; /* 0x0bc */ __u32 io_int_word; /* 0x0c0 */ - __u8 pad3[0xD4-0xC4]; /* 0x0c4 */ + __u8 pad3[0xc8-0xc4]; /* 0x0c4 */ + __u32 stfl_fac_list; /* 0x0c8 */ + __u8 pad4[0xd4-0xcc]; /* 0x0cc */ __u32 extended_save_area_addr; /* 0x0d4 */ __u32 cpu_timer_save_area[2]; /* 0x0d8 */ __u32 clock_comp_save_area[2]; /* 0x0e0 */ __u32 mcck_interruption_code[2]; /* 0x0e8 */ - __u8 pad4[0xf4-0xf0]; /* 0x0f0 */ + __u8 pad5[0xf4-0xf0]; /* 0x0f0 */ __u32 external_damage_code; /* 0x0f4 */ __u32 failing_storage_address; /* 0x0f8 */ - __u8 pad5[0x100-0xfc]; /* 0x0fc */ + __u8 pad6[0x100-0xfc]; /* 0x0fc */ __u32 st_status_fixed_logout[4];/* 0x100 */ - __u8 pad6[0x120-0x110]; /* 0x110 */ + __u8 pad7[0x120-0x110]; /* 0x110 */ __u32 access_regs_save_area[16];/* 0x120 */ __u32 floating_pt_save_area[8]; /* 0x160 */ __u32 gpregs_save_area[16]; /* 0x180 */ diff --git a/include/asm-x86_64/agp.h b/include/asm-x86_64/agp.h index 06c52ee9c06..de338666f3f 100644 --- a/include/asm-x86_64/agp.h +++ b/include/asm-x86_64/agp.h @@ -10,8 +10,10 @@ * with different cachability attributes for the same page. */ -int map_page_into_agp(struct page *page); -int unmap_page_from_agp(struct page *page); +/* Caller's responsibility to call global_flush_tlb() for + * performance reasons */ +#define map_page_into_agp(page) change_page_attr(page, 1, PAGE_KERNEL_NOCACHE) +#define unmap_page_from_agp(page) change_page_attr(page, 1, PAGE_KERNEL) #define flush_agp_mappings() global_flush_tlb() /* Could use CLFLUSH here if the cpu supports it. But then it would diff --git a/include/crypto/algapi.h b/include/crypto/algapi.h index 4e05e93ff68..b2b1e6efd81 100644 --- a/include/crypto/algapi.h +++ b/include/crypto/algapi.h @@ -13,8 +13,11 @@ #define _CRYPTO_ALGAPI_H #include <linux/crypto.h> +#include <linux/list.h> +#include <linux/kernel.h> struct module; +struct rtattr; struct seq_file; struct crypto_type { @@ -38,7 +41,7 @@ struct crypto_template { struct hlist_head instances; struct module *module; - struct crypto_instance *(*alloc)(void *param, unsigned int len); + struct crypto_instance *(*alloc)(struct rtattr **tb); void (*free)(struct crypto_instance *inst); char name[CRYPTO_MAX_ALG_NAME]; @@ -48,6 +51,15 @@ struct crypto_spawn { struct list_head list; struct crypto_alg *alg; struct crypto_instance *inst; + u32 mask; +}; + +struct crypto_queue { + struct list_head list; + struct list_head *backlog; + + unsigned int qlen; + unsigned int max_qlen; }; struct scatter_walk { @@ -81,6 +93,7 @@ struct blkcipher_walk { int flags; }; +extern const struct crypto_type crypto_ablkcipher_type; extern const struct crypto_type crypto_blkcipher_type; extern const struct crypto_type crypto_hash_type; @@ -91,16 +104,23 @@ void crypto_unregister_template(struct crypto_template *tmpl); struct crypto_template *crypto_lookup_template(const char *name); int crypto_init_spawn(struct crypto_spawn *spawn, struct crypto_alg *alg, - struct crypto_instance *inst); + struct crypto_instance *inst, u32 mask); void crypto_drop_spawn(struct crypto_spawn *spawn); struct crypto_tfm *crypto_spawn_tfm(struct crypto_spawn *spawn, u32 type, u32 mask); -struct crypto_alg *crypto_get_attr_alg(void *param, unsigned int len, - u32 type, u32 mask); +struct crypto_attr_type *crypto_get_attr_type(struct rtattr **tb); +int crypto_check_attr_type(struct rtattr **tb, u32 type); +struct crypto_alg *crypto_get_attr_alg(struct rtattr **tb, u32 type, u32 mask); struct crypto_instance *crypto_alloc_instance(const char *name, struct crypto_alg *alg); +void crypto_init_queue(struct crypto_queue *queue, unsigned int max_qlen); +int crypto_enqueue_request(struct crypto_queue *queue, + struct crypto_async_request *request); +struct crypto_async_request *crypto_dequeue_request(struct crypto_queue *queue); +int crypto_tfm_in_queue(struct crypto_queue *queue, struct crypto_tfm *tfm); + int blkcipher_walk_done(struct blkcipher_desc *desc, struct blkcipher_walk *walk, int err); int blkcipher_walk_virt(struct blkcipher_desc *desc, @@ -118,11 +138,37 @@ static inline void *crypto_tfm_ctx_aligned(struct crypto_tfm *tfm) return (void *)ALIGN(addr, align); } +static inline struct crypto_instance *crypto_tfm_alg_instance( + struct crypto_tfm *tfm) +{ + return container_of(tfm->__crt_alg, struct crypto_instance, alg); +} + static inline void *crypto_instance_ctx(struct crypto_instance *inst) { return inst->__ctx; } +static inline struct ablkcipher_alg *crypto_ablkcipher_alg( + struct crypto_ablkcipher *tfm) +{ + return &crypto_ablkcipher_tfm(tfm)->__crt_alg->cra_ablkcipher; +} + +static inline void *crypto_ablkcipher_ctx(struct crypto_ablkcipher *tfm) +{ + return crypto_tfm_ctx(&tfm->base); +} + +static inline struct crypto_blkcipher *crypto_spawn_blkcipher( + struct crypto_spawn *spawn) +{ + u32 type = CRYPTO_ALG_TYPE_BLKCIPHER; + u32 mask = CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC; + + return __crypto_blkcipher_cast(crypto_spawn_tfm(spawn, type, mask)); +} + static inline void *crypto_blkcipher_ctx(struct crypto_blkcipher *tfm) { return crypto_tfm_ctx(&tfm->base); @@ -170,5 +216,35 @@ static inline void blkcipher_walk_init(struct blkcipher_walk *walk, walk->total = nbytes; } +static inline struct crypto_async_request *crypto_get_backlog( + struct crypto_queue *queue) +{ + return queue->backlog == &queue->list ? NULL : + container_of(queue->backlog, struct crypto_async_request, list); +} + +static inline int ablkcipher_enqueue_request(struct ablkcipher_alg *alg, + struct ablkcipher_request *request) +{ + return crypto_enqueue_request(alg->queue, &request->base); +} + +static inline struct ablkcipher_request *ablkcipher_dequeue_request( + struct ablkcipher_alg *alg) +{ + return ablkcipher_request_cast(crypto_dequeue_request(alg->queue)); +} + +static inline void *ablkcipher_request_ctx(struct ablkcipher_request *req) +{ + return req->__ctx; +} + +static inline int ablkcipher_tfm_in_queue(struct crypto_ablkcipher *tfm) +{ + return crypto_tfm_in_queue(crypto_ablkcipher_alg(tfm)->queue, + crypto_ablkcipher_tfm(tfm)); +} + #endif /* _CRYPTO_ALGAPI_H */ diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 0899e2cdcdd..3ec6e7ff5fb 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -257,7 +257,6 @@ struct freq_attr { /********************************************************************* * CPUFREQ 2.6. INTERFACE * *********************************************************************/ -int cpufreq_set_policy(struct cpufreq_policy *policy); int cpufreq_get_policy(struct cpufreq_policy *policy, unsigned int cpu); int cpufreq_update_policy(unsigned int cpu); diff --git a/include/linux/crypto.h b/include/linux/crypto.h index 779aa78ee64..0de7e2ace82 100644 --- a/include/linux/crypto.h +++ b/include/linux/crypto.h @@ -56,6 +56,7 @@ #define CRYPTO_TFM_REQ_WEAK_KEY 0x00000100 #define CRYPTO_TFM_REQ_MAY_SLEEP 0x00000200 +#define CRYPTO_TFM_REQ_MAY_BACKLOG 0x00000400 #define CRYPTO_TFM_RES_WEAK_KEY 0x00100000 #define CRYPTO_TFM_RES_BAD_KEY_LEN 0x00200000 #define CRYPTO_TFM_RES_BAD_KEY_SCHED 0x00400000 @@ -88,11 +89,38 @@ #endif struct scatterlist; +struct crypto_ablkcipher; +struct crypto_async_request; struct crypto_blkcipher; struct crypto_hash; +struct crypto_queue; struct crypto_tfm; struct crypto_type; +typedef void (*crypto_completion_t)(struct crypto_async_request *req, int err); + +struct crypto_async_request { + struct list_head list; + crypto_completion_t complete; + void *data; + struct crypto_tfm *tfm; + + u32 flags; +}; + +struct ablkcipher_request { + struct crypto_async_request base; + + unsigned int nbytes; + + void *info; + + struct scatterlist *src; + struct scatterlist *dst; + + void *__ctx[] CRYPTO_MINALIGN_ATTR; +}; + struct blkcipher_desc { struct crypto_blkcipher *tfm; void *info; @@ -116,6 +144,19 @@ struct hash_desc { * Algorithms: modular crypto algorithm implementations, managed * via crypto_register_alg() and crypto_unregister_alg(). */ +struct ablkcipher_alg { + int (*setkey)(struct crypto_ablkcipher *tfm, const u8 *key, + unsigned int keylen); + int (*encrypt)(struct ablkcipher_request *req); + int (*decrypt)(struct ablkcipher_request *req); + + struct crypto_queue *queue; + + unsigned int min_keysize; + unsigned int max_keysize; + unsigned int ivsize; +}; + struct blkcipher_alg { int (*setkey)(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen); @@ -170,6 +211,7 @@ struct compress_alg { unsigned int slen, u8 *dst, unsigned int *dlen); }; +#define cra_ablkcipher cra_u.ablkcipher #define cra_blkcipher cra_u.blkcipher #define cra_cipher cra_u.cipher #define cra_digest cra_u.digest @@ -194,6 +236,7 @@ struct crypto_alg { const struct crypto_type *cra_type; union { + struct ablkcipher_alg ablkcipher; struct blkcipher_alg blkcipher; struct cipher_alg cipher; struct digest_alg digest; @@ -232,6 +275,15 @@ static inline int crypto_has_alg(const char *name, u32 type, u32 mask) * crypto_free_*(), as well as the various helpers below. */ +struct ablkcipher_tfm { + int (*setkey)(struct crypto_ablkcipher *tfm, const u8 *key, + unsigned int keylen); + int (*encrypt)(struct ablkcipher_request *req); + int (*decrypt)(struct ablkcipher_request *req); + unsigned int ivsize; + unsigned int reqsize; +}; + struct blkcipher_tfm { void *iv; int (*setkey)(struct crypto_tfm *tfm, const u8 *key, @@ -290,6 +342,7 @@ struct compress_tfm { u8 *dst, unsigned int *dlen); }; +#define crt_ablkcipher crt_u.ablkcipher #define crt_blkcipher crt_u.blkcipher #define crt_cipher crt_u.cipher #define crt_hash crt_u.hash @@ -300,6 +353,7 @@ struct crypto_tfm { u32 crt_flags; union { + struct ablkcipher_tfm ablkcipher; struct blkcipher_tfm blkcipher; struct cipher_tfm cipher; struct hash_tfm hash; @@ -311,6 +365,10 @@ struct crypto_tfm { void *__crt_ctx[] CRYPTO_MINALIGN_ATTR; }; +struct crypto_ablkcipher { + struct crypto_tfm base; +}; + struct crypto_blkcipher { struct crypto_tfm base; }; @@ -330,12 +388,21 @@ struct crypto_hash { enum { CRYPTOA_UNSPEC, CRYPTOA_ALG, + CRYPTOA_TYPE, + __CRYPTOA_MAX, }; +#define CRYPTOA_MAX (__CRYPTOA_MAX - 1) + struct crypto_attr_alg { char name[CRYPTO_MAX_ALG_NAME]; }; +struct crypto_attr_type { + u32 type; + u32 mask; +}; + /* * Transform user interface. */ @@ -411,6 +478,167 @@ static inline unsigned int crypto_tfm_ctx_alignment(void) /* * API wrappers. */ +static inline struct crypto_ablkcipher *__crypto_ablkcipher_cast( + struct crypto_tfm *tfm) +{ + return (struct crypto_ablkcipher *)tfm; +} + +static inline struct crypto_ablkcipher *crypto_alloc_ablkcipher( + const char *alg_name, u32 type, u32 mask) +{ + type &= ~CRYPTO_ALG_TYPE_MASK; + type |= CRYPTO_ALG_TYPE_BLKCIPHER; + mask |= CRYPTO_ALG_TYPE_MASK; + + return __crypto_ablkcipher_cast( + crypto_alloc_base(alg_name, type, mask)); +} + +static inline struct crypto_tfm *crypto_ablkcipher_tfm( + struct crypto_ablkcipher *tfm) +{ + return &tfm->base; +} + +static inline void crypto_free_ablkcipher(struct crypto_ablkcipher *tfm) +{ + crypto_free_tfm(crypto_ablkcipher_tfm(tfm)); +} + +static inline int crypto_has_ablkcipher(const char *alg_name, u32 type, + u32 mask) +{ + type &= ~CRYPTO_ALG_TYPE_MASK; + type |= CRYPTO_ALG_TYPE_BLKCIPHER; + mask |= CRYPTO_ALG_TYPE_MASK; + + return crypto_has_alg(alg_name, type, mask); +} + +static inline struct ablkcipher_tfm *crypto_ablkcipher_crt( + struct crypto_ablkcipher *tfm) +{ + return &crypto_ablkcipher_tfm(tfm)->crt_ablkcipher; +} + +static inline unsigned int crypto_ablkcipher_ivsize( + struct crypto_ablkcipher *tfm) +{ + return crypto_ablkcipher_crt(tfm)->ivsize; +} + +static inline unsigned int crypto_ablkcipher_blocksize( + struct crypto_ablkcipher *tfm) +{ + return crypto_tfm_alg_blocksize(crypto_ablkcipher_tfm(tfm)); +} + +static inline unsigned int crypto_ablkcipher_alignmask( + struct crypto_ablkcipher *tfm) +{ + return crypto_tfm_alg_alignmask(crypto_ablkcipher_tfm(tfm)); +} + +static inline u32 crypto_ablkcipher_get_flags(struct crypto_ablkcipher *tfm) +{ + return crypto_tfm_get_flags(crypto_ablkcipher_tfm(tfm)); +} + +static inline void crypto_ablkcipher_set_flags(struct crypto_ablkcipher *tfm, + u32 flags) +{ + crypto_tfm_set_flags(crypto_ablkcipher_tfm(tfm), flags); +} + +static inline void crypto_ablkcipher_clear_flags(struct crypto_ablkcipher *tfm, + u32 flags) +{ + crypto_tfm_clear_flags(crypto_ablkcipher_tfm(tfm), flags); +} + +static inline int crypto_ablkcipher_setkey(struct crypto_ablkcipher *tfm, + const u8 *key, unsigned int keylen) +{ + return crypto_ablkcipher_crt(tfm)->setkey(tfm, key, keylen); +} + +static inline struct crypto_ablkcipher *crypto_ablkcipher_reqtfm( + struct ablkcipher_request *req) +{ + return __crypto_ablkcipher_cast(req->base.tfm); +} + +static inline int crypto_ablkcipher_encrypt(struct ablkcipher_request *req) +{ + struct ablkcipher_tfm *crt = + crypto_ablkcipher_crt(crypto_ablkcipher_reqtfm(req)); + return crt->encrypt(req); +} + +static inline int crypto_ablkcipher_decrypt(struct ablkcipher_request *req) +{ + struct ablkcipher_tfm *crt = + crypto_ablkcipher_crt(crypto_ablkcipher_reqtfm(req)); + return crt->decrypt(req); +} + +static inline int crypto_ablkcipher_reqsize(struct crypto_ablkcipher *tfm) +{ + return crypto_ablkcipher_crt(tfm)->reqsize; +} + +static inline void ablkcipher_request_set_tfm( + struct ablkcipher_request *req, struct crypto_ablkcipher *tfm) +{ + req->base.tfm = crypto_ablkcipher_tfm(tfm); +} + +static inline struct ablkcipher_request *ablkcipher_request_cast( + struct crypto_async_request *req) +{ + return container_of(req, struct ablkcipher_request, base); +} + +static inline struct ablkcipher_request *ablkcipher_request_alloc( + struct crypto_ablkcipher *tfm, gfp_t gfp) +{ + struct ablkcipher_request *req; + + req = kmalloc(sizeof(struct ablkcipher_request) + + crypto_ablkcipher_reqsize(tfm), gfp); + + if (likely(req)) + ablkcipher_request_set_tfm(req, tfm); + + return req; +} + +static inline void ablkcipher_request_free(struct ablkcipher_request *req) +{ + kfree(req); +} + +static inline void ablkcipher_request_set_callback( + struct ablkcipher_request *req, + u32 flags, crypto_completion_t complete, void *data) +{ + req->base.complete = complete; + req->base.data = data; + req->base.flags = flags; +} + +static inline void ablkcipher_request_set_crypt( + struct ablkcipher_request *req, + struct scatterlist *src, struct scatterlist *dst, + unsigned int nbytes, void *iv) +{ + req->src = src; + req->dst = dst; + req->nbytes = nbytes; + req->info = iv; +} + static inline struct crypto_blkcipher *__crypto_blkcipher_cast( struct crypto_tfm *tfm) { @@ -427,9 +655,9 @@ static inline struct crypto_blkcipher *crypto_blkcipher_cast( static inline struct crypto_blkcipher *crypto_alloc_blkcipher( const char *alg_name, u32 type, u32 mask) { - type &= ~CRYPTO_ALG_TYPE_MASK; + type &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC); type |= CRYPTO_ALG_TYPE_BLKCIPHER; - mask |= CRYPTO_ALG_TYPE_MASK; + mask |= CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC; return __crypto_blkcipher_cast(crypto_alloc_base(alg_name, type, mask)); } @@ -447,9 +675,9 @@ static inline void crypto_free_blkcipher(struct crypto_blkcipher *tfm) static inline int crypto_has_blkcipher(const char *alg_name, u32 type, u32 mask) { - type &= ~CRYPTO_ALG_TYPE_MASK; + type &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC); type |= CRYPTO_ALG_TYPE_BLKCIPHER; - mask |= CRYPTO_ALG_TYPE_MASK; + mask |= CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC; return crypto_has_alg(alg_name, type, mask); } diff --git a/include/linux/highmem.h b/include/linux/highmem.h index 645d440807c..7bab8eae234 100644 --- a/include/linux/highmem.h +++ b/include/linux/highmem.h @@ -42,8 +42,14 @@ static inline void *kmap(struct page *page) #define kunmap(page) do { (void) (page); } while (0) -#define kmap_atomic(page, idx) \ - ({ pagefault_disable(); page_address(page); }) +#include <asm/kmap_types.h> + +static inline void *kmap_atomic(struct page *page, enum km_type idx) +{ + pagefault_disable(); + return page_address(page); +} + #define kunmap_atomic(addr, idx) do { pagefault_enable(); } while (0) #define kmap_atomic_pfn(pfn, idx) kmap_atomic(pfn_to_page(pfn), (idx)) #define kmap_atomic_to_page(ptr) virt_to_page(ptr) diff --git a/include/linux/i2c-algo-bit.h b/include/linux/i2c-algo-bit.h index 937da70cb4c..9ee0f800592 100644 --- a/include/linux/i2c-algo-bit.h +++ b/include/linux/i2c-algo-bit.h @@ -38,11 +38,14 @@ struct i2c_algo_bit_data { int (*getscl) (void *data); /* local settings */ - int udelay; /* half-clock-cycle time in microsecs */ - /* i.e. clock is (500 / udelay) KHz */ + int udelay; /* half clock cycle time in us, + minimum 2 us for fast-mode I2C, + minimum 5 us for standard-mode I2C and SMBus, + maximum 50 us for SMBus */ int timeout; /* in jiffies */ }; int i2c_bit_add_bus(struct i2c_adapter *); +int i2c_bit_add_numbered_bus(struct i2c_adapter *); #endif /* _LINUX_I2C_ALGO_BIT_H */ diff --git a/include/linux/i2c-gpio.h b/include/linux/i2c-gpio.h new file mode 100644 index 00000000000..c1bcb1f1d73 --- /dev/null +++ b/include/linux/i2c-gpio.h @@ -0,0 +1,38 @@ +/* + * i2c-gpio interface to platform code + * + * Copyright (C) 2007 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef _LINUX_I2C_GPIO_H +#define _LINUX_I2C_GPIO_H + +/** + * struct i2c_gpio_platform_data - Platform-dependent data for i2c-gpio + * @sda_pin: GPIO pin ID to use for SDA + * @scl_pin: GPIO pin ID to use for SCL + * @udelay: signal toggle delay. SCL frequency is (500 / udelay) kHz + * @timeout: clock stretching timeout in jiffies. If the slave keeps + * SCL low for longer than this, the transfer will time out. + * @sda_is_open_drain: SDA is configured as open drain, i.e. the pin + * isn't actively driven high when setting the output value high. + * gpio_get_value() must return the actual pin state even if the + * pin is configured as an output. + * @scl_is_open_drain: SCL is set up as open drain. Same requirements + * as for sda_is_open_drain apply. + * @scl_is_output_only: SCL output drivers cannot be turned off. + */ +struct i2c_gpio_platform_data { + unsigned int sda_pin; + unsigned int scl_pin; + int udelay; + int timeout; + unsigned int sda_is_open_drain:1; + unsigned int scl_is_open_drain:1; + unsigned int scl_is_output_only:1; +}; + +#endif /* _LINUX_I2C_GPIO_H */ diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h index 9c21dc793d7..0e8da684ce6 100644 --- a/include/linux/i2c-id.h +++ b/include/linux/i2c-id.h @@ -258,8 +258,9 @@ /* --- MCP107 adapter */ #define I2C_HW_MPC107 0x0d0000 -/* --- Marvell mv64xxx i2c adapter */ +/* --- Embedded adapters */ #define I2C_HW_MV64XXX 0x190000 +#define I2C_HW_BLACKFIN 0x190001 /* ADI Blackfin I2C TWI driver */ /* --- Miscellaneous adapters */ #define I2C_HW_SAA7146 0x060000 /* SAA7146 video decoder bus */ diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 9428092017e..cae7d618030 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -35,11 +35,6 @@ #include <linux/sched.h> /* for completion */ #include <linux/mutex.h> -/* --- For i2c-isa ---------------------------------------------------- */ - -extern void i2c_adapter_dev_release(struct device *dev); -extern struct device_driver i2c_adapter_driver; -extern struct class i2c_adapter_class; extern struct bus_type i2c_bus_type; /* --- General options ------------------------------------------------ */ @@ -87,6 +82,9 @@ extern s32 i2c_smbus_write_byte_data(struct i2c_client * client, extern s32 i2c_smbus_read_word_data(struct i2c_client * client, u8 command); extern s32 i2c_smbus_write_word_data(struct i2c_client * client, u8 command, u16 value); +/* Returns the number of read bytes */ +extern s32 i2c_smbus_read_block_data(struct i2c_client *client, + u8 command, u8 *values); extern s32 i2c_smbus_write_block_data(struct i2c_client * client, u8 command, u8 length, const u8 *values); @@ -114,7 +112,7 @@ struct i2c_driver { * can be used by the driver to test if the bus meets its conditions * & seek for the presence of the chip(s) it supports. If found, it * registers the client(s) that are on the bus to the i2c admin. via - * i2c_attach_client. + * i2c_attach_client. (LEGACY I2C DRIVERS ONLY) */ int (*attach_adapter)(struct i2c_adapter *); int (*detach_adapter)(struct i2c_adapter *); @@ -122,10 +120,17 @@ struct i2c_driver { /* tells the driver that a client is about to be deleted & gives it * the chance to remove its private data. Also, if the client struct * has been dynamically allocated by the driver in the function above, - * it must be freed here. + * it must be freed here. (LEGACY I2C DRIVERS ONLY) */ int (*detach_client)(struct i2c_client *); + /* Standard driver model interfaces, for "new style" i2c drivers. + * With the driver model, device enumeration is NEVER done by drivers; + * it's done by infrastructure. (NEW STYLE DRIVERS ONLY) + */ + int (*probe)(struct i2c_client *); + int (*remove)(struct i2c_client *); + /* driver model interfaces that don't relate to enumeration */ void (*shutdown)(struct i2c_client *); int (*suspend)(struct i2c_client *, pm_message_t mesg); @@ -141,25 +146,34 @@ struct i2c_driver { }; #define to_i2c_driver(d) container_of(d, struct i2c_driver, driver) -#define I2C_NAME_SIZE 50 +#define I2C_NAME_SIZE 20 -/* - * i2c_client identifies a single device (i.e. chip) that is connected to an - * i2c bus. The behaviour is defined by the routines of the driver. This - * function is mainly used for lookup & other admin. functions. +/** + * struct i2c_client - represent an I2C slave device + * @addr: Address used on the I2C bus connected to the parent adapter. + * @name: Indicates the type of the device, usually a chip name that's + * generic enough to hide second-sourcing and compatible revisions. + * @dev: Driver model device node for the slave. + * @driver_name: Identifies new-style driver used with this device; also + * used as the module name for hotplug/coldplug modprobe support. + * + * An i2c_client identifies a single device (i.e. chip) connected to an + * i2c bus. The behaviour is defined by the routines of the driver. */ struct i2c_client { - unsigned int flags; /* div., see below */ + unsigned short flags; /* div., see below */ unsigned short addr; /* chip address - NOTE: 7bit */ /* addresses are stored in the */ /* _LOWER_ 7 bits */ + char name[I2C_NAME_SIZE]; struct i2c_adapter *adapter; /* the adapter we sit on */ struct i2c_driver *driver; /* and our access routines */ int usage_count; /* How many accesses currently */ /* to the client */ struct device dev; /* the device structure */ + int irq; /* irq issued by device (or -1) */ + char driver_name[KOBJ_NAME_LEN]; struct list_head list; - char name[I2C_NAME_SIZE]; struct completion released; }; #define to_i2c_client(d) container_of(d, struct i2c_client, dev) @@ -179,6 +193,76 @@ static inline void i2c_set_clientdata (struct i2c_client *dev, void *data) dev_set_drvdata (&dev->dev, data); } +/** + * struct i2c_board_info - template for device creation + * @driver_name: identifies the driver to be bound to the device + * @type: optional chip type information, to initialize i2c_client.name + * @flags: to initialize i2c_client.flags + * @addr: stored in i2c_client.addr + * @platform_data: stored in i2c_client.dev.platform_data + * @irq: stored in i2c_client.irq + + * I2C doesn't actually support hardware probing, although controllers and + * devices may be able to use I2C_SMBUS_QUICK to tell whether or not there's + * a device at a given address. Drivers commonly need more information than + * that, such as chip type, configuration, associated IRQ, and so on. + * + * i2c_board_info is used to build tables of information listing I2C devices + * that are present. This information is used to grow the driver model tree + * for "new style" I2C drivers. For mainboards this is done statically using + * i2c_register_board_info(), where @bus_num represents an adapter that isn't + * yet available. For add-on boards, i2c_new_device() does this dynamically + * with the adapter already known. + */ +struct i2c_board_info { + char driver_name[KOBJ_NAME_LEN]; + char type[I2C_NAME_SIZE]; + unsigned short flags; + unsigned short addr; + void *platform_data; + int irq; +}; + +/** + * I2C_BOARD_INFO - macro used to list an i2c device and its driver + * @driver: identifies the driver to use with the device + * @dev_addr: the device's address on the bus. + * + * This macro initializes essential fields of a struct i2c_board_info, + * declaring what has been provided on a particular board. Optional + * fields (such as the chip type, its associated irq, or device-specific + * platform_data) are provided using conventional syntax. + */ +#define I2C_BOARD_INFO(driver,dev_addr) \ + .driver_name = (driver), .addr = (dev_addr) + + +/* Add-on boards should register/unregister their devices; e.g. a board + * with integrated I2C, a config eeprom, sensors, and a codec that's + * used in conjunction with the primary hardware. + */ +extern struct i2c_client * +i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info); + +/* If you don't know the exact address of an I2C device, use this variant + * instead, which can probe for device presence in a list of possible + * addresses. + */ +extern struct i2c_client * +i2c_new_probed_device(struct i2c_adapter *adap, + struct i2c_board_info *info, + unsigned short const *addr_list); + +extern void i2c_unregister_device(struct i2c_client *); + +/* Mainboard arch_initcall() code should register all its I2C devices. + * This is done at arch_initcall time, before declaring any i2c adapters. + * Modules for add-on boards must use other calls. + */ +extern int +i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsigned n); + + /* * The following structs are for those who like to implement new bus drivers: * i2c_algorithm is the interface to a class of hardware solutions which can @@ -228,17 +312,14 @@ struct i2c_adapter { int timeout; int retries; struct device dev; /* the adapter device */ - struct class_device class_dev; /* the class device */ int nr; struct list_head clients; struct list_head list; - char name[I2C_NAME_SIZE]; + char name[48]; struct completion dev_released; - struct completion class_dev_released; }; -#define dev_to_i2c_adapter(d) container_of(d, struct i2c_adapter, dev) -#define class_dev_to_i2c_adapter(d) container_of(d, struct i2c_adapter, class_dev) +#define to_i2c_adapter(d) container_of(d, struct i2c_adapter, dev) static inline void *i2c_get_adapdata (struct i2c_adapter *dev) { @@ -290,9 +371,10 @@ struct i2c_client_address_data { */ extern int i2c_add_adapter(struct i2c_adapter *); extern int i2c_del_adapter(struct i2c_adapter *); +extern int i2c_add_numbered_adapter(struct i2c_adapter *); extern int i2c_register_driver(struct module *, struct i2c_driver *); -extern int i2c_del_driver(struct i2c_driver *); +extern void i2c_del_driver(struct i2c_driver *); static inline int i2c_add_driver(struct i2c_driver *driver) { @@ -365,6 +447,7 @@ struct i2c_msg { #define I2C_M_REV_DIR_ADDR 0x2000 #define I2C_M_IGNORE_NAK 0x1000 #define I2C_M_NO_RD_ACK 0x0800 +#define I2C_M_RECV_LEN 0x0400 /* length will be first received byte */ __u16 len; /* msg length */ __u8 *buf; /* pointer to msg data */ }; diff --git a/include/linux/input.h b/include/linux/input.h index bde65c8a351..327122548c4 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -676,6 +676,7 @@ struct input_absinfo { #define BUS_I2C 0x18 #define BUS_HOST 0x19 #define BUS_GSC 0x1A +#define BUS_ATARI 0x1B /* * Values describing the status of a force-feedback effect diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index 838cf5a5bd7..0319f665dd3 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -185,10 +185,14 @@ static inline int disable_irq_wake(unsigned int irq) * validator need to define the methods below in their asm/irq.h * files, under an #ifdef CONFIG_LOCKDEP section. */ -# ifndef CONFIG_LOCKDEP +#ifndef CONFIG_LOCKDEP # define disable_irq_nosync_lockdep(irq) disable_irq_nosync(irq) +# define disable_irq_nosync_lockdep_irqsave(irq, flags) \ + disable_irq_nosync(irq) # define disable_irq_lockdep(irq) disable_irq(irq) # define enable_irq_lockdep(irq) enable_irq(irq) +# define enable_irq_lockdep_irqrestore(irq, flags) \ + enable_irq(irq) # endif #endif /* CONFIG_GENERIC_HARDIRQS */ diff --git a/include/linux/nubus.h b/include/linux/nubus.h index 870e66a9628..cdb3e9b8db5 100644 --- a/include/linux/nubus.h +++ b/include/linux/nubus.h @@ -28,18 +28,18 @@ enum nubus_category { }; enum nubus_type_network { - NUBUS_TYPE_ETHERNET = 0x0001, - NUBUS_TYPE_RS232 = 0x0002 + NUBUS_TYPE_ETHERNET = 0x0001, + NUBUS_TYPE_RS232 = 0x0002 }; enum nubus_type_display { - NUBUS_TYPE_VIDEO = 0x0001 + NUBUS_TYPE_VIDEO = 0x0001 }; enum nubus_type_cpu { - NUBUS_TYPE_68020 = 0x0003, - NUBUS_TYPE_68030 = 0x0004, - NUBUS_TYPE_68040 = 0x0005 + NUBUS_TYPE_68020 = 0x0003, + NUBUS_TYPE_68030 = 0x0004, + NUBUS_TYPE_68040 = 0x0005 }; /* Known <Cat,Type,SW,HW> tuples: (according to TattleTech and Slots) @@ -56,6 +56,7 @@ enum nubus_type_cpu { * * SONIC comm-slot/on-board and DuoDock Ethernet: <4,1,1,272> * SONIC LC-PDS Ethernet (Dayna, but like Apple 16-bit, sort of): <4,1,1,271> + * Apple SONIC LC-PDS Ethernet ("Apple Ethernet LC Twisted-Pair Card"): <4,1,0,281> * Sonic Systems Ethernet A-Series Card: <4,1,268,256> * Asante MacCon NuBus-A: <4,1,260,256> (alpha-1.0,1.1 revision) * ROM on the above card: <2,1,0,0> @@ -80,24 +81,26 @@ enum nubus_type_cpu { /* Add known DrSW values here */ enum nubus_drsw { /* NUBUS_CAT_DISPLAY */ - NUBUS_DRSW_APPLE = 0x0001, - NUBUS_DRSW_APPLE_HIRES = 0x0013, /* MacII HiRes card driver */ + NUBUS_DRSW_APPLE = 0x0001, + NUBUS_DRSW_APPLE_HIRES = 0x0013, /* MacII HiRes card driver */ /* NUBUS_CAT_NETWORK */ - NUBUS_DRSW_CABLETRON = 0x0001, - NUBUS_DRSW_SONIC_LC = 0x0001, - NUBUS_DRSW_KINETICS = 0x0103, - NUBUS_DRSW_ASANTE = 0x0104, - NUBUS_DRSW_DAYNA = 0x010b, - NUBUS_DRSW_FARALLON = 0x010c, - NUBUS_DRSW_APPLE_SN = 0x010f, - NUBUS_DRSW_DAYNA2 = 0x0115, + NUBUS_DRSW_3COM = 0x0000, + NUBUS_DRSW_CABLETRON = 0x0001, + NUBUS_DRSW_SONIC_LC = 0x0001, + NUBUS_DRSW_KINETICS = 0x0103, + NUBUS_DRSW_ASANTE = 0x0104, + NUBUS_DRSW_TECHWORKS = 0x0109, + NUBUS_DRSW_DAYNA = 0x010b, + NUBUS_DRSW_FARALLON = 0x010c, + NUBUS_DRSW_APPLE_SN = 0x010f, + NUBUS_DRSW_DAYNA2 = 0x0115, NUBUS_DRSW_FOCUS = 0x011a, NUBUS_DRSW_ASANTE_CS = 0x011d, /* use asante SMC9194 driver */ - NUBUS_DRSW_DAYNA_LC = 0x011e, + NUBUS_DRSW_DAYNA_LC = 0x011e, /* NUBUS_CAT_CPU */ - NUBUS_DRSW_NONE = 0x0000, + NUBUS_DRSW_NONE = 0x0000, }; /* DrHW: Uniquely identifies the hardware interface to a board (or at @@ -107,27 +110,48 @@ enum nubus_drsw { /* Add known DrHW values here */ enum nubus_drhw { /* NUBUS_CAT_DISPLAY */ - NUBUS_DRHW_APPLE_TFB = 0x0001, /* Toby frame buffer card */ - NUBUS_DRHW_APPLE_HRVC = 0x0013, /* Mac II High Res Video card */ - NUBUS_DRHW_APPLE_RBV1 = 0x0018, /* IIci RBV video */ - NUBUS_DRHW_APPLE_MDC = 0x0019, /* Macintosh Display Card */ - NUBUS_DRHW_APPLE_SONORA = 0x0022, /* Sonora built-in video */ - NUBUS_DRHW_APPLE_JET = 0x0029, /* Jet framebuffer (DuoDock) */ + NUBUS_DRHW_APPLE_TFB = 0x0001, /* Toby frame buffer card */ + NUBUS_DRHW_APPLE_WVC = 0x0006, /* Apple Workstation Video Card */ + NUBUS_DRHW_SIGMA_CLRMAX = 0x0007, /* Sigma Design ColorMax */ + NUBUS_DRHW_APPLE_SE30 = 0x0009, /* Apple SE/30 video */ + NUBUS_DRHW_APPLE_HRVC = 0x0013, /* Mac II High-Res Video Card */ + NUBUS_DRHW_APPLE_PVC = 0x0017, /* Mac II Portrait Video Card */ + NUBUS_DRHW_APPLE_RBV1 = 0x0018, /* IIci RBV video */ + NUBUS_DRHW_APPLE_MDC = 0x0019, /* Macintosh Display Card */ + NUBUS_DRHW_APPLE_SONORA = 0x0022, /* Sonora built-in video */ + NUBUS_DRHW_APPLE_24AC = 0x002b, /* Mac 24AC Video Card */ NUBUS_DRHW_APPLE_VALKYRIE = 0x002e, - NUBUS_DRHW_THUNDER24 = 0x02cb, /* SuperMac Thunder/24 */ + NUBUS_DRHW_APPLE_JET = 0x0029, /* Jet framebuffer (DuoDock) */ + NUBUS_DRHW_SMAC_GFX = 0x0105, /* SuperMac GFX */ + NUBUS_DRHW_RASTER_CB264 = 0x013B, /* RasterOps ColorBoard 264 */ + NUBUS_DRHW_MICRON_XCEED = 0x0146, /* Micron Exceed color */ + NUBUS_DRHW_RDIUS_GSC = 0x0153, /* Radius GS/C */ + NUBUS_DRHW_SMAC_SPEC8 = 0x017B, /* SuperMac Spectrum/8 */ + NUBUS_DRHW_SMAC_SPEC24 = 0x017C, /* SuperMac Spectrum/24 */ + NUBUS_DRHW_RASTER_CB364 = 0x026F, /* RasterOps ColorBoard 364 */ + NUBUS_DRHW_RDIUS_DCGX = 0x027C, /* Radius DirectColor/GX */ + NUBUS_DRHW_RDIUS_PC8 = 0x0291, /* Radius PrecisionColor 8 */ + NUBUS_DRHW_LAPIS_PCS8 = 0x0292, /* Lapis ProColorServer 8 */ + NUBUS_DRHW_RASTER_24LXI = 0x02A0, /* RasterOps 8/24 XLi */ + NUBUS_DRHW_RASTER_PBPGT = 0x02A5, /* RasterOps PaintBoard Prism GT */ + NUBUS_DRHW_EMACH_FSX = 0x02AE, /* E-Machines Futura SX */ + NUBUS_DRHW_SMAC_THUND24 = 0x02CB, /* SuperMac Thunder/24 */ + NUBUS_DRHW_RDIUS_PC24XP = 0x0406, /* Radius PrecisionColor 24Xp */ + NUBUS_DRHW_RDIUS_PC24X = 0x040A, /* Radius PrecisionColor 24X */ + NUBUS_DRHW_RDIUS_PC8XJ = 0x040B, /* Radius PrecisionColor 8XJ */ /* NUBUS_CAT_NETWORK */ - NUBUS_DRHW_INTERLAN = 0x0100, - NUBUS_DRHW_SMC9194 = 0x0101, - NUBUS_DRHW_KINETICS = 0x0106, - NUBUS_DRHW_CABLETRON = 0x0109, - NUBUS_DRHW_ASANTE_LC = 0x010f, - NUBUS_DRHW_SONIC = 0x0110, - NUBUS_DRHW_SONIC_NB = 0x0118, - NUBUS_DRHW_SONIC_LC = 0x0119, - - /* NUBUS_CAT_COMMUNICATIONS */ - NUBUS_DRHW_DOVEFAX = 0x0100, + NUBUS_DRHW_INTERLAN = 0x0100, + NUBUS_DRHW_SMC9194 = 0x0101, + NUBUS_DRHW_KINETICS = 0x0106, + NUBUS_DRHW_CABLETRON = 0x0109, + NUBUS_DRHW_ASANTE_LC = 0x010f, + NUBUS_DRHW_SONIC = 0x0110, + NUBUS_DRHW_TECHWORKS = 0x0112, + NUBUS_DRHW_APPLE_SONIC_NB = 0x0118, + NUBUS_DRHW_APPLE_SONIC_LC = 0x0119, + NUBUS_DRHW_FOCUS = 0x011c, + NUBUS_DRHW_SONNET = 0x011d, }; /* Resource IDs: These are the identifiers for the various weird and @@ -153,17 +177,17 @@ enum nubus_res_id { /* Category-specific resources. */ enum nubus_board_res_id { - NUBUS_RESID_BOARDID = 0x0020, + NUBUS_RESID_BOARDID = 0x0020, NUBUS_RESID_PRAMINITDATA = 0x0021, - NUBUS_RESID_PRIMARYINIT = 0x0022, + NUBUS_RESID_PRIMARYINIT = 0x0022, NUBUS_RESID_TIMEOUTCONST = 0x0023, - NUBUS_RESID_VENDORINFO = 0x0024, - NUBUS_RESID_BOARDFLAGS = 0x0025, - NUBUS_RESID_SECONDINIT = 0x0026, + NUBUS_RESID_VENDORINFO = 0x0024, + NUBUS_RESID_BOARDFLAGS = 0x0025, + NUBUS_RESID_SECONDINIT = 0x0026, /* Not sure why Apple put these next two in here */ - NUBUS_RESID_VIDNAMES = 0x0041, - NUBUS_RESID_VIDMODES = 0x007e + NUBUS_RESID_VIDNAMES = 0x0041, + NUBUS_RESID_VIDMODES = 0x007e }; /* Fields within the vendor info directory */ @@ -185,13 +209,13 @@ enum nubus_cpu_res_id { }; enum nubus_display_res_id { - NUBUS_RESID_GAMMADIR = 0x0040, - NUBUS_RESID_FIRSTMODE = 0x0080, - NUBUS_RESID_SECONDMODE = 0x0081, - NUBUS_RESID_THIRDMODE = 0x0082, - NUBUS_RESID_FOURTHMODE = 0x0083, - NUBUS_RESID_FIFTHMODE = 0x0084, - NUBUS_RESID_SIXTHMODE = 0x0085 + NUBUS_RESID_GAMMADIR = 0x0040, + NUBUS_RESID_FIRSTMODE = 0x0080, + NUBUS_RESID_SECONDMODE = 0x0081, + NUBUS_RESID_THIRDMODE = 0x0082, + NUBUS_RESID_FOURTHMODE = 0x0083, + NUBUS_RESID_FIFTHMODE = 0x0084, + NUBUS_RESID_SIXTHMODE = 0x0085 }; struct nubus_dir @@ -214,7 +238,7 @@ struct nubus_board { struct nubus_board* next; struct nubus_dev* first_dev; - /* Only 9-E actually exist, though 0-8 are also theoretically + /* Only 9-E actually exist, though 0-8 are also theoretically possible, and 0 is a special case which represents the motherboard and onboard peripherals (Ethernet, video) */ int slot; diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 1b0ddbb8a80..5a48e963d06 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1213,11 +1213,13 @@ #define PCI_DEVICE_ID_NVIDIA_NVENET_16 0x03E5 #define PCI_DEVICE_ID_NVIDIA_NVENET_17 0x03E6 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA 0x03E7 +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SMBUS 0x03EB #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_IDE 0x03EC #define PCI_DEVICE_ID_NVIDIA_NVENET_18 0x03EE #define PCI_DEVICE_ID_NVIDIA_NVENET_19 0x03EF #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA2 0x03F6 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA3 0x03F7 +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_SMBUS 0x0446 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_IDE 0x0448 #define PCI_DEVICE_ID_NVIDIA_NVENET_20 0x0450 #define PCI_DEVICE_ID_NVIDIA_NVENET_21 0x0451 diff --git a/include/media/ovcamchip.h b/include/media/ovcamchip.h index 0f43451f8bb..05b9569ef1c 100644 --- a/include/media/ovcamchip.h +++ b/include/media/ovcamchip.h @@ -16,7 +16,6 @@ #include <linux/videodev.h> #include <media/v4l2-common.h> -#include <linux/i2c.h> /* --------------------------------- */ /* ENUMERATIONS */ diff --git a/include/media/tuner.h b/include/media/tuner.h index a41ac41113a..6dcf3c45707 100644 --- a/include/media/tuner.h +++ b/include/media/tuner.h @@ -23,6 +23,7 @@ #define _TUNER_H #include <linux/videodev2.h> +#include <linux/i2c.h> #include <media/tuner-types.h> extern int tuner_debug; diff --git a/sound/oss/dmasound/tas_ioctl.h b/sound/oss/dmasound/tas_ioctl.h index dccae3a40e0..9d12b373b4a 100644 --- a/sound/oss/dmasound/tas_ioctl.h +++ b/sound/oss/dmasound/tas_ioctl.h @@ -1,7 +1,6 @@ #ifndef _TAS_IOCTL_H_ #define _TAS_IOCTL_H_ -#include <linux/i2c.h> #include <linux/soundcard.h> |