diff options
30 files changed, 2455 insertions, 1943 deletions
@@ -1337,6 +1337,12 @@ S: 998 East 900 South, Suite 26 S: Provo, Utah 84606-5607 S: USA +N: Marcel Holtmann +E: marcel@holtmann.org +W: http://www.holtmann.org +D: Author of the Linux Bluetooth Subsystem PC Card drivers +S: Germany + N: Rob W. W. Hooft E: hooft@EMBL-Heidelberg.DE D: Shared libs for graphics-tools and for the f2c compiler diff --git a/Documentation/ide.txt b/Documentation/ide.txt index 9da199ed4108..3adb7cabfbcd 100644 --- a/Documentation/ide.txt +++ b/Documentation/ide.txt @@ -1,9 +1,6 @@ - - Information regarding the Enhanced IDE drive in Linux 2.5 - ============================================================================== @@ -303,6 +300,53 @@ Everything else is rejected with a "BAD OPTION" message. ================================================================================ +IDE ATAPI streaming tape driver +------------------------------- + +This driver is a part of the Linux ide driver and works in co-operation +with linux/drivers/block/ide.c. + +The driver, in co-operation with ide.c, basically traverses the +request-list for the block device interface. The character device +interface, on the other hand, creates new requests, adds them +to the request-list of the block device, and waits for their completion. + +Pipelined operation mode is now supported on both reads and writes. + +The block device major and minor numbers are determined from the +tape's relative position in the ide interfaces, as explained in ide.c. + +The character device interface consists of the following devices: + + ht0 major 37, minor 0 first IDE tape, rewind on close. + ht1 major 37, minor 1 second IDE tape, rewind on close. + ... + nht0 major 37, minor 128 first IDE tape, no rewind on close. + nht1 major 37, minor 129 second IDE tape, no rewind on close. + ... + +Run linux/scripts/MAKEDEV.ide to create the above entries. + +The general magnetic tape commands compatible interface, as defined by +include/linux/mtio.h, is accessible through the character device. + +General ide driver configuration options, such as the interrupt-unmask +flag, can be configured by issuing an ioctl to the block device interface, +as any other ide device. + +Our own ide-tape ioctl's can be issued to either the block device or +the character device interface. + +Maximal throughput with minimal bus load will usually be achieved in the +following scenario: + + 1. ide-tape is operating in the pipelined operation mode. + 2. No buffering is performed by the user backup program. + + + +================================================================================ + Some Terminology ---------------- IDE = Integrated Drive Electronics, meaning that each drive has a built-in diff --git a/MAINTAINERS b/MAINTAINERS index 493c93ec438b..ebcd5fe6fa67 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -270,6 +270,12 @@ M: maxk@qualcomm.com W: http://bluez.sf.net S: Maintained +BLUETOOTH SUBSYSTEM (PC Card Drivers) +P: Marcel Holtmann +M: marcel@holtmann.org +W: http://www.holtmann.org/linux/bluetooth/ +S: Maintained + BTTV VIDEO4LINUX DRIVER P: Gerd Knorr M: kraxel@bytesex.org diff --git a/drivers/bluetooth/Config.help b/drivers/bluetooth/Config.help index b59648ceaae5..e5a9f19a6290 100644 --- a/drivers/bluetooth/Config.help +++ b/drivers/bluetooth/Config.help @@ -62,6 +62,20 @@ CONFIG_BLUEZ_HCIDTL1 Say Y here to compile support for HCI DTL1 devices into the kernel or say M to compile it as module (dtl1_cs.o). +HCI BT3C (PC Card) device driver +CONFIG_BLUEZ_HCIBT3C + Bluetooth HCI BT3C (PC Card) driver. + This driver provides support for Bluetooth PCMCIA devices with + 3Com BT3C interface: + 3Com Bluetooth Card (3CRWB6096) + HP Bluetooth Card + + The HCI BT3C driver uses external firmware loader program provided in + the BlueFW package. For more information, see <http://bluez.sf.net>. + + Say Y here to compile support for HCI BT3C devices into the + kernel or say M to compile it as module (bt3c_cs.o). + HCI BlueCard (PC Card) device driver CONFIG_BLUEZ_HCIBLUECARD Bluetooth HCI BlueCard (PC Card) driver. diff --git a/drivers/bluetooth/Config.in b/drivers/bluetooth/Config.in index a4d71734c64f..9aef303fc289 100644 --- a/drivers/bluetooth/Config.in +++ b/drivers/bluetooth/Config.in @@ -14,6 +14,8 @@ fi dep_tristate 'HCI DTL1 (PC Card) driver' CONFIG_BLUEZ_HCIDTL1 $CONFIG_PCMCIA $CONFIG_BLUEZ +dep_tristate 'HCI BT3C (PC Card) driver' CONFIG_BLUEZ_HCIBT3C $CONFIG_PCMCIA $CONFIG_BLUEZ + dep_tristate 'HCI BlueCard (PC Card) driver' CONFIG_BLUEZ_HCIBLUECARD $CONFIG_PCMCIA $CONFIG_BLUEZ dep_tristate 'HCI VHCI (Virtual HCI device) driver' CONFIG_BLUEZ_HCIVHCI $CONFIG_BLUEZ diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile index ada41c6689a4..76d3def3ba65 100644 --- a/drivers/bluetooth/Makefile +++ b/drivers/bluetooth/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_BLUEZ_HCIUSB) += hci_usb.o obj-$(CONFIG_BLUEZ_HCIVHCI) += hci_vhci.o obj-$(CONFIG_BLUEZ_HCIUART) += hci_uart.o obj-$(CONFIG_BLUEZ_HCIDTL1) += dtl1_cs.o +obj-$(CONFIG_BLUEZ_HCIBT3C) += bt3c_cs.o obj-$(CONFIG_BLUEZ_HCIBLUECARD) += bluecard_cs.o hci_uart-y := hci_ldisc.o diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c index e358601d42f7..296d674bc38a 100644 --- a/drivers/bluetooth/bluecard_cs.c +++ b/drivers/bluetooth/bluecard_cs.c @@ -89,16 +89,16 @@ typedef struct bluecard_info_t { } bluecard_info_t; -void bluecard_config(dev_link_t * link); +void bluecard_config(dev_link_t *link); void bluecard_release(u_long arg); -int bluecard_event(event_t event, int priority, event_callback_args_t * args); +int bluecard_event(event_t event, int priority, event_callback_args_t *args); static dev_info_t dev_info = "bluecard_cs"; dev_link_t *bluecard_attach(void); void bluecard_detach(dev_link_t *); -dev_link_t *dev_list = NULL; +static dev_link_t *dev_list = NULL; /* Default baud rate: 57600, 115200, 230400 or 460800 */ @@ -171,7 +171,7 @@ dev_link_t *dev_list = NULL; void bluecard_activity_led_timeout(u_long arg) { - bluecard_info_t *info = (bluecard_info_t *) arg; + bluecard_info_t *info = (bluecard_info_t *)arg; unsigned int iobase = info->link.io.BasePort1; if (test_bit(CARD_HAS_ACTIVITY_LED, &(info->hw_state))) { @@ -184,7 +184,7 @@ void bluecard_activity_led_timeout(u_long arg) } -static void bluecard_enable_activity_led(bluecard_info_t * info) +static void bluecard_enable_activity_led(bluecard_info_t *info) { unsigned int iobase = info->link.io.BasePort1; @@ -208,8 +208,7 @@ static void bluecard_enable_activity_led(bluecard_info_t * info) /* ======================== Interrupt handling ======================== */ -static int bluecard_write(unsigned int iobase, unsigned int offset, - __u8 * buf, int len) +static int bluecard_write(unsigned int iobase, unsigned int offset, __u8 *buf, int len) { int i, actual; @@ -224,7 +223,7 @@ static int bluecard_write(unsigned int iobase, unsigned int offset, } -static void bluecard_write_wakeup(bluecard_info_t * info) +static void bluecard_write_wakeup(bluecard_info_t *info) { if (!info) { printk(KERN_WARNING "bluecard_cs: Call of write_wakeup for unknown device.\n"); @@ -253,15 +252,13 @@ static void bluecard_write_wakeup(bluecard_info_t * info) return; if (test_bit(XMIT_BUFFER_NUMBER, &(info->tx_state))) { - if (!test_bit - (XMIT_BUF_TWO_READY, &(info->tx_state))) + if (!test_bit(XMIT_BUF_TWO_READY, &(info->tx_state))) break; offset = 0x10; command = REG_COMMAND_TX_BUF_TWO; ready_bit = XMIT_BUF_TWO_READY; } else { - if (!test_bit - (XMIT_BUF_ONE_READY, &(info->tx_state))) + if (!test_bit(XMIT_BUF_ONE_READY, &(info->tx_state))) break; offset = 0x00; command = REG_COMMAND_TX_BUF_ONE; @@ -272,11 +269,9 @@ static void bluecard_write_wakeup(bluecard_info_t * info) break; if (skb->pkt_type & 0x80) { - /* Disable RTS */ info->ctrl_reg |= REG_CONTROL_RTS; outb(info->ctrl_reg, iobase + REG_CONTROL); - } /* Activate LED */ @@ -349,8 +344,7 @@ static void bluecard_write_wakeup(bluecard_info_t * info) } -static int bluecard_read(unsigned int iobase, unsigned int offset, - __u8 * buf, int size) +static int bluecard_read(unsigned int iobase, unsigned int offset, __u8 *buf, int size) { int i, n, len; @@ -378,7 +372,7 @@ static int bluecard_read(unsigned int iobase, unsigned int offset, } -static void bluecard_receive(bluecard_info_t * info, unsigned int offset) +static void bluecard_receive(bluecard_info_t *info, unsigned int offset) { unsigned int iobase; unsigned char buf[31]; @@ -410,7 +404,7 @@ static void bluecard_receive(bluecard_info_t * info, unsigned int offset) if (info->rx_state == RECV_WAIT_PACKET_TYPE) { - info->rx_skb->dev = (void *) &(info->hdev); + info->rx_skb->dev = (void *)&(info->hdev); info->rx_skb->pkt_type = buf[i]; switch (info->rx_skb->pkt_type) { @@ -469,20 +463,20 @@ static void bluecard_receive(bluecard_info_t * info, unsigned int offset) switch (info->rx_state) { case RECV_WAIT_EVENT_HEADER: - eh = (hci_event_hdr *) (info->rx_skb->data); + eh = (hci_event_hdr *)(info->rx_skb->data); info->rx_state = RECV_WAIT_DATA; info->rx_count = eh->plen; break; case RECV_WAIT_ACL_HEADER: - ah = (hci_acl_hdr *) (info->rx_skb->data); + ah = (hci_acl_hdr *)(info->rx_skb->data); dlen = __le16_to_cpu(ah->dlen); info->rx_state = RECV_WAIT_DATA; info->rx_count = dlen; break; case RECV_WAIT_SCO_HEADER: - sh = (hci_sco_hdr *) (info->rx_skb->data); + sh = (hci_sco_hdr *)(info->rx_skb->data); info->rx_state = RECV_WAIT_DATA; info->rx_count = sh->dlen; break; @@ -571,9 +565,8 @@ void bluecard_interrupt(int irq, void *dev_inst, struct pt_regs *regs) static int bluecard_hci_set_baud_rate(struct hci_dev *hdev, int baud) { - bluecard_info_t *info = (bluecard_info_t *) (hdev->driver_data); + bluecard_info_t *info = (bluecard_info_t *)(hdev->driver_data); struct sk_buff *skb; - int i; /* Ericsson baud rate command */ unsigned char cmd[] = { HCI_COMMAND_PKT, 0x09, 0xfc, 0x01, 0x03 }; @@ -604,8 +597,7 @@ static int bluecard_hci_set_baud_rate(struct hci_dev *hdev, int baud) break; } - for (i = 0; i < sizeof(cmd); i++) - *skb_put(skb, 1) = cmd[i]; + memcpy(skb_put(skb, sizeof(cmd)), cmd, sizeof(cmd)); skb_queue_tail(&(info->txq), skb); @@ -621,7 +613,7 @@ static int bluecard_hci_set_baud_rate(struct hci_dev *hdev, int baud) static int bluecard_hci_flush(struct hci_dev *hdev) { - bluecard_info_t *info = (bluecard_info_t *) (hdev->driver_data); + bluecard_info_t *info = (bluecard_info_t *)(hdev->driver_data); /* Drop TX queue */ skb_queue_purge(&(info->txq)); @@ -632,7 +624,7 @@ static int bluecard_hci_flush(struct hci_dev *hdev) static int bluecard_hci_open(struct hci_dev *hdev) { - bluecard_info_t *info = (bluecard_info_t *) (hdev->driver_data); + bluecard_info_t *info = (bluecard_info_t *)(hdev->driver_data); unsigned int iobase = info->link.io.BasePort1; bluecard_hci_set_baud_rate(hdev, DEFAULT_BAUD_RATE); @@ -649,7 +641,7 @@ static int bluecard_hci_open(struct hci_dev *hdev) static int bluecard_hci_close(struct hci_dev *hdev) { - bluecard_info_t *info = (bluecard_info_t *) (hdev->driver_data); + bluecard_info_t *info = (bluecard_info_t *)(hdev->driver_data); unsigned int iobase = info->link.io.BasePort1; if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags))) @@ -667,14 +659,14 @@ static int bluecard_hci_close(struct hci_dev *hdev) static int bluecard_hci_send_frame(struct sk_buff *skb) { bluecard_info_t *info; - struct hci_dev *hdev = (struct hci_dev *) (skb->dev); + struct hci_dev *hdev = (struct hci_dev *)(skb->dev); if (!hdev) { printk(KERN_WARNING "bluecard_cs: Frame for unknown HCI device (hdev=NULL)."); return -ENODEV; } - info = (bluecard_info_t *) (hdev->driver_data); + info = (bluecard_info_t *)(hdev->driver_data); switch (skb->pkt_type) { case HCI_COMMAND_PKT: @@ -703,8 +695,7 @@ static void bluecard_hci_destruct(struct hci_dev *hdev) } -static int bluecard_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, - unsigned long arg) +static int bluecard_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg) { return -ENOIOCTLCMD; } @@ -714,7 +705,7 @@ static int bluecard_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, /* ======================== Card services HCI interaction ======================== */ -int bluecard_open(bluecard_info_t * info) +int bluecard_open(bluecard_info_t *info) { unsigned int iobase = info->link.io.BasePort1; struct hci_dev *hdev; @@ -724,7 +715,7 @@ int bluecard_open(bluecard_info_t * info) init_timer(&(info->timer)); info->timer.function = &bluecard_activity_led_timeout; - info->timer.data = (u_long) info; + info->timer.data = (u_long)info; skb_queue_head_init(&(info->txq)); @@ -781,7 +772,8 @@ int bluecard_open(bluecard_info_t * info) /* Timeout before it is safe to send the first HCI packet */ set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout((HZ * 5) / 4); // or set it to 3/2 + schedule_timeout((HZ * 5) / 4); // or set it to 3/2 + /* Initialize and register HCI device */ @@ -806,7 +798,7 @@ int bluecard_open(bluecard_info_t * info) } -int bluecard_close(bluecard_info_t * info) +int bluecard_close(bluecard_info_t *info) { unsigned int iobase = info->link.io.BasePort1; struct hci_dev *hdev = &(info->hdev); @@ -858,7 +850,7 @@ dev_link_t *bluecard_attach(void) link->priv = info; link->release.function = &bluecard_release; - link->release.data = (u_long) link; + link->release.data = (u_long)link; link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; link->io.NumPorts1 = 8; link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; @@ -883,9 +875,9 @@ dev_link_t *bluecard_attach(void) client_reg.dev_info = &dev_info; client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; + CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | + CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | + CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; client_reg.event_handler = &bluecard_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; @@ -901,7 +893,7 @@ dev_link_t *bluecard_attach(void) } -void bluecard_detach(dev_link_t * link) +void bluecard_detach(dev_link_t *link) { bluecard_info_t *info = link->priv; dev_link_t **linkp; @@ -917,7 +909,7 @@ void bluecard_detach(dev_link_t * link) del_timer(&link->release); if (link->state & DEV_CONFIG) - bluecard_release((u_long) link); + bluecard_release((u_long)link); if (link->handle) { ret = CardServices(DeregisterClient, link->handle); @@ -932,8 +924,7 @@ void bluecard_detach(dev_link_t * link) } -static int get_tuple(int fn, client_handle_t handle, tuple_t * tuple, - cisparse_t * parse) +static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, cisparse_t *parse) { int i; @@ -952,7 +943,7 @@ static int get_tuple(int fn, client_handle_t handle, tuple_t * tuple, #define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c) #define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c) -void bluecard_config(dev_link_t * link) +void bluecard_config(dev_link_t *link) { client_handle_t handle = link->handle; bluecard_info_t *info = link->priv; @@ -962,7 +953,7 @@ void bluecard_config(dev_link_t * link) config_info_t config; int i, n, last_ret, last_fn; - tuple.TupleData = (cisdata_t *) buf; + tuple.TupleData = (cisdata_t *)buf; tuple.TupleOffset = 0; tuple.TupleDataMax = 255; tuple.Attributes = 0; @@ -1010,12 +1001,12 @@ void bluecard_config(dev_link_t * link) goto failed; } - MOD_INC_USE_COUNT; if (bluecard_open(info) != 0) goto failed; + strcpy(info->node.dev_name, info->hdev.name); link->dev = &info->node; link->state &= ~DEV_CONFIG_PENDING; @@ -1025,13 +1016,13 @@ cs_failed: cs_error(link->handle, last_fn, last_ret); failed: - bluecard_release((u_long) link); + bluecard_release((u_long)link); } void bluecard_release(u_long arg) { - dev_link_t *link = (dev_link_t *) arg; + dev_link_t *link = (dev_link_t *)arg; bluecard_info_t *info = link->priv; if (link->state & DEV_PRESENT) @@ -1049,8 +1040,7 @@ void bluecard_release(u_long arg) } -int bluecard_event(event_t event, int priority, - event_callback_args_t * args) +int bluecard_event(event_t event, int priority, event_callback_args_t *args) { dev_link_t *link = args->client_data; bluecard_info_t *info = link->priv; @@ -1079,8 +1069,7 @@ int bluecard_event(event_t event, int priority, /* Fall through... */ case CS_EVENT_CARD_RESET: if (DEV_OK(link)) - CardServices(RequestConfiguration, link->handle, - &link->conf); + CardServices(RequestConfiguration, link->handle, &link->conf); break; } diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c new file mode 100644 index 000000000000..d50e4e945d34 --- /dev/null +++ b/drivers/bluetooth/bt3c_cs.c @@ -0,0 +1,944 @@ +/* + * + * Driver for the 3Com Bluetooth PCMCIA card + * + * Copyright (C) 2001-2002 Marcel Holtmann <marcel@holtmann.org> + * Jose Orlando Pereira <jop@di.uminho.pt> + * + * + * 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; + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The initial developer of the original code is David A. Hinds + * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + * + */ + +#include <linux/config.h> +#include <linux/module.h> + +#define __KERNEL_SYSCALLS__ + +#include <linux/kernel.h> +#include <linux/kmod.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/types.h> +#include <linux/sched.h> +#include <linux/delay.h> +#include <linux/timer.h> +#include <linux/errno.h> +#include <linux/unistd.h> +#include <linux/ptrace.h> +#include <linux/ioport.h> +#include <linux/spinlock.h> + +#include <linux/skbuff.h> +#include <linux/string.h> +#include <linux/serial.h> +#include <linux/serial_reg.h> +#include <asm/system.h> +#include <asm/bitops.h> +#include <asm/io.h> + +#include <pcmcia/version.h> +#include <pcmcia/cs_types.h> +#include <pcmcia/cs.h> +#include <pcmcia/cistpl.h> +#include <pcmcia/ciscode.h> +#include <pcmcia/ds.h> +#include <pcmcia/cisreg.h> + +#include <net/bluetooth/bluetooth.h> +#include <net/bluetooth/hci_core.h> + + + +/* ======================== Module parameters ======================== */ + + +/* Bit map of interrupts to choose from */ +static u_int irq_mask = 0xffff; +static int irq_list[4] = { -1 }; + +MODULE_PARM(irq_mask, "i"); +MODULE_PARM(irq_list, "1-4i"); + +MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>, Jose Orlando Pereira <jop@di.uminho.pt>"); +MODULE_DESCRIPTION("BlueZ driver for the 3Com Bluetooth PCMCIA card"); +MODULE_LICENSE("GPL"); + + + +/* ======================== Local structures ======================== */ + + +typedef struct bt3c_info_t { + dev_link_t link; + dev_node_t node; + + struct hci_dev hdev; + + spinlock_t lock; /* For serializing operations */ + + struct sk_buff_head txq; + unsigned long tx_state; + + unsigned long rx_state; + unsigned long rx_count; + struct sk_buff *rx_skb; +} bt3c_info_t; + + +void bt3c_config(dev_link_t *link); +void bt3c_release(u_long arg); +int bt3c_event(event_t event, int priority, event_callback_args_t *args); + +static dev_info_t dev_info = "bt3c_cs"; + +dev_link_t *bt3c_attach(void); +void bt3c_detach(dev_link_t *); + +static dev_link_t *dev_list = NULL; + + +/* Transmit states */ +#define XMIT_SENDING 1 +#define XMIT_WAKEUP 2 +#define XMIT_WAITING 8 + +/* Receiver states */ +#define RECV_WAIT_PACKET_TYPE 0 +#define RECV_WAIT_EVENT_HEADER 1 +#define RECV_WAIT_ACL_HEADER 2 +#define RECV_WAIT_SCO_HEADER 3 +#define RECV_WAIT_DATA 4 + + + +/* ======================== Special I/O functions ======================== */ + + +#define DATA_L 0 +#define DATA_H 1 +#define ADDR_L 2 +#define ADDR_H 3 +#define CONTROL 4 + + +inline void bt3c_address(unsigned int iobase, unsigned short addr) +{ + outb(addr & 0xff, iobase + ADDR_L); + outb((addr >> 8) & 0xff, iobase + ADDR_H); +} + + +inline void bt3c_put(unsigned int iobase, unsigned short value) +{ + outb(value & 0xff, iobase + DATA_L); + outb((value >> 8) & 0xff, iobase + DATA_H); +} + + +inline void bt3c_io_write(unsigned int iobase, unsigned short addr, unsigned short value) +{ + bt3c_address(iobase, addr); + bt3c_put(iobase, value); +} + + +inline unsigned short bt3c_get(unsigned int iobase) +{ + unsigned short value = inb(iobase + DATA_L); + + value |= inb(iobase + DATA_H) << 8; + + return value; +} + + +inline unsigned short bt3c_read(unsigned int iobase, unsigned short addr) +{ + bt3c_address(iobase, addr); + + return bt3c_get(iobase); +} + + + +/* ======================== Interrupt handling ======================== */ + + +static int bt3c_write(unsigned int iobase, int fifo_size, __u8 *buf, int len) +{ + int actual = 0; + + bt3c_address(iobase, 0x7080); + + /* Fill FIFO with current frame */ + while (actual < len) { + /* Transmit next byte */ + bt3c_put(iobase, buf[actual]); + actual++; + } + + bt3c_io_write(iobase, 0x7005, actual); + + return actual; +} + + +static void bt3c_write_wakeup(bt3c_info_t *info, int from) +{ + unsigned long flags; + + if (!info) { + printk(KERN_WARNING "bt3c_cs: Call of write_wakeup for unknown device.\n"); + return; + } + + if (test_and_set_bit(XMIT_SENDING, &(info->tx_state))) + return; + + spin_lock_irqsave(&(info->lock), flags); + + do { + register unsigned int iobase = info->link.io.BasePort1; + register struct sk_buff *skb; + register int len; + + if (!(info->link.state & DEV_PRESENT)) + break; + + + if (!(skb = skb_dequeue(&(info->txq)))) { + clear_bit(XMIT_SENDING, &(info->tx_state)); + break; + } + + /* Send frame */ + len = bt3c_write(iobase, 256, skb->data, skb->len); + + if (len != skb->len) { + printk(KERN_WARNING "bt3c_cs: very strange\n"); + } + + kfree_skb(skb); + + info->hdev.stat.byte_tx += len; + + } while (0); + + spin_unlock_irqrestore(&(info->lock), flags); +} + + +static void bt3c_receive(bt3c_info_t *info) +{ + unsigned int iobase; + int size = 0, avail; + + if (!info) { + printk(KERN_WARNING "bt3c_cs: Call of receive for unknown device.\n"); + return; + } + + iobase = info->link.io.BasePort1; + + avail = bt3c_read(iobase, 0x7006); + //printk("bt3c_cs: receiving %d bytes\n", avail); + + bt3c_address(iobase, 0x7480); + while (size < avail) { + size++; + info->hdev.stat.byte_rx++; + + /* Allocate packet */ + if (info->rx_skb == NULL) { + info->rx_state = RECV_WAIT_PACKET_TYPE; + info->rx_count = 0; + if (!(info->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) { + printk(KERN_WARNING "bt3c_cs: Can't allocate mem for new packet.\n"); + return; + } + } + + + if (info->rx_state == RECV_WAIT_PACKET_TYPE) { + + info->rx_skb->dev = (void *)&(info->hdev); + info->rx_skb->pkt_type = inb(iobase + DATA_L); + inb(iobase + DATA_H); + //printk("bt3c: PACKET_TYPE=%02x\n", info->rx_skb->pkt_type); + + switch (info->rx_skb->pkt_type) { + + case HCI_EVENT_PKT: + info->rx_state = RECV_WAIT_EVENT_HEADER; + info->rx_count = HCI_EVENT_HDR_SIZE; + break; + + case HCI_ACLDATA_PKT: + info->rx_state = RECV_WAIT_ACL_HEADER; + info->rx_count = HCI_ACL_HDR_SIZE; + break; + + case HCI_SCODATA_PKT: + info->rx_state = RECV_WAIT_SCO_HEADER; + info->rx_count = HCI_SCO_HDR_SIZE; + break; + + default: + /* Unknown packet */ + printk(KERN_WARNING "bt3c_cs: Unknown HCI packet with type 0x%02x received.\n", info->rx_skb->pkt_type); + info->hdev.stat.err_rx++; + clear_bit(HCI_RUNNING, &(info->hdev.flags)); + + kfree_skb(info->rx_skb); + info->rx_skb = NULL; + break; + + } + + } else { + + __u8 x = inb(iobase + DATA_L); + + *skb_put(info->rx_skb, 1) = x; + inb(iobase + DATA_H); + info->rx_count--; + + if (info->rx_count == 0) { + + int dlen; + hci_event_hdr *eh; + hci_acl_hdr *ah; + hci_sco_hdr *sh; + + switch (info->rx_state) { + + case RECV_WAIT_EVENT_HEADER: + eh = (hci_event_hdr *)(info->rx_skb->data); + info->rx_state = RECV_WAIT_DATA; + info->rx_count = eh->plen; + break; + + case RECV_WAIT_ACL_HEADER: + ah = (hci_acl_hdr *)(info->rx_skb->data); + dlen = __le16_to_cpu(ah->dlen); + info->rx_state = RECV_WAIT_DATA; + info->rx_count = dlen; + break; + + case RECV_WAIT_SCO_HEADER: + sh = (hci_sco_hdr *)(info->rx_skb->data); + info->rx_state = RECV_WAIT_DATA; + info->rx_count = sh->dlen; + break; + + case RECV_WAIT_DATA: + hci_recv_frame(info->rx_skb); + info->rx_skb = NULL; + break; + + } + + } + + } + + } + + bt3c_io_write(iobase, 0x7006, 0x0000); +} + + +void bt3c_interrupt(int irq, void *dev_inst, struct pt_regs *regs) +{ + bt3c_info_t *info = dev_inst; + unsigned int iobase; + int iir; + + if (!info) { + printk(KERN_WARNING "bt3c_cs: Call of irq %d for unknown device.\n", irq); + return; + } + + iobase = info->link.io.BasePort1; + + spin_lock(&(info->lock)); + + iir = inb(iobase + CONTROL); + if (iir & 0x80) { + int stat = bt3c_read(iobase, 0x7001); + + if ((stat & 0xff) == 0x7f) { + printk(KERN_WARNING "bt3c_cs: STRANGE stat=%04x\n", stat); + } else if ((stat & 0xff) != 0xff) { + if (stat & 0x0020) { + int stat = bt3c_read(iobase, 0x7002) & 0x10; + printk(KERN_WARNING "bt3c_cs: antena %s\n", stat ? "OUT" : "IN"); + } + if (stat & 0x0001) + bt3c_receive(info); + if (stat & 0x0002) { + //printk("bt3c_cs: ACK %04x\n", stat); + clear_bit(XMIT_SENDING, &(info->tx_state)); + bt3c_write_wakeup(info, 1); + } + + bt3c_io_write(iobase, 0x7001, 0x0000); + + outb(iir, iobase + CONTROL); + } + } + + spin_unlock(&(info->lock)); +} + + + + +/* ======================== HCI interface ======================== */ + + +static int bt3c_hci_flush(struct hci_dev *hdev) +{ + bt3c_info_t *info = (bt3c_info_t *)(hdev->driver_data); + + /* Drop TX queue */ + skb_queue_purge(&(info->txq)); + + return 0; +} + + +static int bt3c_hci_open(struct hci_dev *hdev) +{ + set_bit(HCI_RUNNING, &(hdev->flags)); + + return 0; +} + + +static int bt3c_hci_close(struct hci_dev *hdev) +{ + if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags))) + return 0; + + bt3c_hci_flush(hdev); + + return 0; +} + + +static int bt3c_hci_send_frame(struct sk_buff *skb) +{ + bt3c_info_t *info; + struct hci_dev *hdev = (struct hci_dev *)(skb->dev); + + if (!hdev) { + printk(KERN_WARNING "bt3c_cs: Frame for unknown HCI device (hdev=NULL)."); + return -ENODEV; + } + + info = (bt3c_info_t *) (hdev->driver_data); + + switch (skb->pkt_type) { + case HCI_COMMAND_PKT: + hdev->stat.cmd_tx++; + break; + case HCI_ACLDATA_PKT: + hdev->stat.acl_tx++; + break; + case HCI_SCODATA_PKT: + hdev->stat.sco_tx++; + break; + }; + + /* Prepend skb with frame type */ + memcpy(skb_push(skb, 1), &(skb->pkt_type), 1); + skb_queue_tail(&(info->txq), skb); + + bt3c_write_wakeup(info, 0); + + return 0; +} + + +static void bt3c_hci_destruct(struct hci_dev *hdev) +{ +} + + +static int bt3c_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg) +{ + return -ENOIOCTLCMD; +} + + + +/* ======================== User mode firmware loader ======================== */ + + +#define FW_LOADER "/sbin/bluefw" +static int errno; + + +static int bt3c_fw_loader_exec(void *dev) +{ + char *argv[] = { FW_LOADER, "pccard", dev, NULL }; + char *envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL }; + int err; + + err = exec_usermodehelper(FW_LOADER, argv, envp); + if (err) + printk(KERN_WARNING "bt3c_cs: Failed to exec \"%s pccard %s\".\n", FW_LOADER, (char *)dev); + + return err; +} + + +static int bt3c_firmware_load(bt3c_info_t *info) +{ + sigset_t tmpsig; + char dev[16]; + pid_t pid; + int result; + + /* Check if root fs is mounted */ + if (!current->fs->root) { + printk(KERN_WARNING "bt3c_cs: Root filesystem is not mounted.\n"); + return -EPERM; + } + + sprintf(dev, "%04x", info->link.io.BasePort1); + + pid = kernel_thread(bt3c_fw_loader_exec, (void *)dev, 0); + if (pid < 0) { + printk(KERN_WARNING "bt3c_cs: Forking of kernel thread failed (errno=%d).\n", -pid); + return pid; + } + + /* Block signals, everything but SIGKILL/SIGSTOP */ + spin_lock_irq(¤t->sigmask_lock); + tmpsig = current->blocked; + siginitsetinv(¤t->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP)); + recalc_sigpending(); + spin_unlock_irq(¤t->sigmask_lock); + + result = waitpid(pid, NULL, __WCLONE); + + /* Allow signals again */ + spin_lock_irq(¤t->sigmask_lock); + current->blocked = tmpsig; + recalc_sigpending(); + spin_unlock_irq(¤t->sigmask_lock); + + if (result != pid) { + printk(KERN_WARNING "bt3c_cs: Waiting for pid %d failed (errno=%d).\n", pid, -result); + return -result; + } + + return 0; +} + + + +/* ======================== Card services HCI interaction ======================== */ + + +int bt3c_open(bt3c_info_t *info) +{ + struct hci_dev *hdev; + int err; + + spin_lock_init(&(info->lock)); + + skb_queue_head_init(&(info->txq)); + + info->rx_state = RECV_WAIT_PACKET_TYPE; + info->rx_count = 0; + info->rx_skb = NULL; + + /* Load firmware */ + + if ((err = bt3c_firmware_load(info)) < 0) + return err; + + /* Timeout before it is safe to send the first HCI packet */ + + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ); + + + /* Initialize and register HCI device */ + + hdev = &(info->hdev); + + hdev->type = HCI_PCCARD; + hdev->driver_data = info; + + hdev->open = bt3c_hci_open; + hdev->close = bt3c_hci_close; + hdev->flush = bt3c_hci_flush; + hdev->send = bt3c_hci_send_frame; + hdev->destruct = bt3c_hci_destruct; + hdev->ioctl = bt3c_hci_ioctl; + + if (hci_register_dev(hdev) < 0) { + printk(KERN_WARNING "bt3c_cs: Can't register HCI device %s.\n", hdev->name); + return -ENODEV; + } + + return 0; +} + + +int bt3c_close(bt3c_info_t *info) +{ + struct hci_dev *hdev = &(info->hdev); + + bt3c_hci_close(hdev); + + if (hci_unregister_dev(hdev) < 0) + printk(KERN_WARNING "bt3c_cs: Can't unregister HCI device %s.\n", hdev->name); + + return 0; +} + + + +/* ======================== Card services ======================== */ + + +static void cs_error(client_handle_t handle, int func, int ret) +{ + error_info_t err = { func, ret }; + + CardServices(ReportError, handle, &err); +} + + +dev_link_t *bt3c_attach(void) +{ + bt3c_info_t *info; + client_reg_t client_reg; + dev_link_t *link; + int i, ret; + + /* Create new info device */ + info = kmalloc(sizeof(*info), GFP_KERNEL); + if (!info) + return NULL; + memset(info, 0, sizeof(*info)); + + link = &info->link; + link->priv = info; + + link->release.function = &bt3c_release; + link->release.data = (u_long)link; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + link->io.NumPorts1 = 8; + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; + link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID; + + if (irq_list[0] == -1) + link->irq.IRQInfo2 = irq_mask; + else + for (i = 0; i < 4; i++) + link->irq.IRQInfo2 |= 1 << irq_list[i]; + + link->irq.Handler = bt3c_interrupt; + link->irq.Instance = info; + + link->conf.Attributes = CONF_ENABLE_IRQ; + link->conf.Vcc = 50; + link->conf.IntType = INT_MEMORY_AND_IO; + + /* Register with Card Services */ + link->next = dev_list; + dev_list = link; + client_reg.dev_info = &dev_info; + client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; + client_reg.EventMask = + CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | + CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | + CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; + client_reg.event_handler = &bt3c_event; + client_reg.Version = 0x0210; + client_reg.event_callback_args.client_data = link; + + ret = CardServices(RegisterClient, &link->handle, &client_reg); + if (ret != CS_SUCCESS) { + cs_error(link->handle, RegisterClient, ret); + bt3c_detach(link); + return NULL; + } + + return link; +} + + +void bt3c_detach(dev_link_t *link) +{ + bt3c_info_t *info = link->priv; + dev_link_t **linkp; + int ret; + + /* Locate device structure */ + for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) + if (*linkp == link) + break; + + if (*linkp == NULL) + return; + + del_timer(&link->release); + + if (link->state & DEV_CONFIG) + bt3c_release((u_long)link); + + if (link->handle) { + ret = CardServices(DeregisterClient, link->handle); + if (ret != CS_SUCCESS) + cs_error(link->handle, DeregisterClient, ret); + } + + /* Unlink device structure, free bits */ + *linkp = link->next; + + kfree(info); +} + + +static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, cisparse_t *parse) +{ + int i; + + i = CardServices(fn, handle, tuple); + if (i != CS_SUCCESS) + return CS_NO_MORE_ITEMS; + + i = CardServices(GetTupleData, handle, tuple); + if (i != CS_SUCCESS) + return i; + + return CardServices(ParseTuple, handle, tuple, parse); +} + + +#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c) +#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c) + +void bt3c_config(dev_link_t *link) +{ + static ioaddr_t base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 }; + client_handle_t handle = link->handle; + bt3c_info_t *info = link->priv; + tuple_t tuple; + u_short buf[256]; + cisparse_t parse; + cistpl_cftable_entry_t *cf = &parse.cftable_entry; + config_info_t config; + int i, j, try, last_ret, last_fn; + + tuple.TupleData = (cisdata_t *)buf; + tuple.TupleOffset = 0; + tuple.TupleDataMax = 255; + tuple.Attributes = 0; + + /* Get configuration register information */ + tuple.DesiredTuple = CISTPL_CONFIG; + last_ret = first_tuple(handle, &tuple, &parse); + if (last_ret != CS_SUCCESS) { + last_fn = ParseTuple; + goto cs_failed; + } + link->conf.ConfigBase = parse.config.base; + link->conf.Present = parse.config.rmask[0]; + + /* Configure card */ + link->state |= DEV_CONFIG; + i = CardServices(GetConfigurationInfo, handle, &config); + link->conf.Vcc = config.Vcc; + + /* First pass: look for a config entry that looks normal. */ + tuple.TupleData = (cisdata_t *)buf; + tuple.TupleOffset = 0; + tuple.TupleDataMax = 255; + tuple.Attributes = 0; + tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; + /* Two tries: without IO aliases, then with aliases */ + for (try = 0; try < 2; try++) { + i = first_tuple(handle, &tuple, &parse); + while (i != CS_NO_MORE_ITEMS) { + if (i != CS_SUCCESS) + goto next_entry; + if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM)) + link->conf.Vpp1 = link->conf.Vpp2 = cf->vpp1.param[CISTPL_POWER_VNOM] / 10000; + if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) && (cf->io.win[0].base != 0)) { + link->conf.ConfigIndex = cf->index; + link->io.BasePort1 = cf->io.win[0].base; + link->io.IOAddrLines = (try == 0) ? 16 : cf->io.flags & CISTPL_IO_LINES_MASK; + i = CardServices(RequestIO, link->handle, &link->io); + if (i == CS_SUCCESS) + goto found_port; + } +next_entry: + i = next_tuple(handle, &tuple, &parse); + } + } + + /* Second pass: try to find an entry that isn't picky about + its base address, then try to grab any standard serial port + address, and finally try to get any free port. */ + i = first_tuple(handle, &tuple, &parse); + while (i != CS_NO_MORE_ITEMS) { + if ((i == CS_SUCCESS) && (cf->io.nwin > 0) && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) { + link->conf.ConfigIndex = cf->index; + for (j = 0; j < 5; j++) { + link->io.BasePort1 = base[j]; + link->io.IOAddrLines = base[j] ? 16 : 3; + i = CardServices(RequestIO, link->handle, &link->io); + if (i == CS_SUCCESS) + goto found_port; + } + } + i = next_tuple(handle, &tuple, &parse); + } + +found_port: + if (i != CS_SUCCESS) { + printk(KERN_NOTICE "bt3c_cs: No usable port range found. Giving up.\n"); + cs_error(link->handle, RequestIO, i); + goto failed; + } + + i = CardServices(RequestIRQ, link->handle, &link->irq); + if (i != CS_SUCCESS) { + cs_error(link->handle, RequestIRQ, i); + link->irq.AssignedIRQ = 0; + } + + i = CardServices(RequestConfiguration, link->handle, &link->conf); + if (i != CS_SUCCESS) { + cs_error(link->handle, RequestConfiguration, i); + goto failed; + } + + MOD_INC_USE_COUNT; + + if (bt3c_open(info) != 0) + goto failed; + + strcpy(info->node.dev_name, info->hdev.name); + link->dev = &info->node; + link->state &= ~DEV_CONFIG_PENDING; + + return; + +cs_failed: + cs_error(link->handle, last_fn, last_ret); + +failed: + bt3c_release((u_long)link); +} + + +void bt3c_release(u_long arg) +{ + dev_link_t *link = (dev_link_t *)arg; + bt3c_info_t *info = link->priv; + + if (link->state & DEV_PRESENT) + bt3c_close(info); + + MOD_DEC_USE_COUNT; + + link->dev = NULL; + + CardServices(ReleaseConfiguration, link->handle); + CardServices(ReleaseIO, link->handle, &link->io); + CardServices(ReleaseIRQ, link->handle, &link->irq); + + link->state &= ~DEV_CONFIG; +} + + +int bt3c_event(event_t event, int priority, event_callback_args_t *args) +{ + dev_link_t *link = args->client_data; + bt3c_info_t *info = link->priv; + + switch (event) { + case CS_EVENT_CARD_REMOVAL: + link->state &= ~DEV_PRESENT; + if (link->state & DEV_CONFIG) { + bt3c_close(info); + mod_timer(&link->release, jiffies + HZ / 20); + } + break; + case CS_EVENT_CARD_INSERTION: + link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; + bt3c_config(link); + break; + case CS_EVENT_PM_SUSPEND: + link->state |= DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_RESET_PHYSICAL: + if (link->state & DEV_CONFIG) + CardServices(ReleaseConfiguration, link->handle); + break; + case CS_EVENT_PM_RESUME: + link->state &= ~DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_CARD_RESET: + if (DEV_OK(link)) + CardServices(RequestConfiguration, link->handle, &link->conf); + break; + } + + return 0; +} + + + +/* ======================== Module initialization ======================== */ + + +int __init init_bt3c_cs(void) +{ + servinfo_t serv; + int err; + + CardServices(GetCardServicesInfo, &serv); + if (serv.Revision != CS_RELEASE_CODE) { + printk(KERN_NOTICE "bt3c_cs: Card Services release does not match!\n"); + return -1; + } + + err = register_pccard_driver(&dev_info, &bt3c_attach, &bt3c_detach); + + return err; +} + + +void __exit exit_bt3c_cs(void) +{ + unregister_pccard_driver(&dev_info); + + while (dev_list != NULL) + bt3c_detach(dev_list); +} + + +module_init(init_bt3c_cs); +module_exit(exit_bt3c_cs); diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c index 97f32d8e0049..80df236ec1dc 100644 --- a/drivers/bluetooth/dtl1_cs.c +++ b/drivers/bluetooth/dtl1_cs.c @@ -75,23 +75,22 @@ MODULE_LICENSE("GPL"); typedef struct dtl1_info_t { - dev_link_t link; - dev_node_t node; + dev_link_t link; + dev_node_t node; - struct hci_dev hdev; + struct hci_dev hdev; - spinlock_t lock; /* For serializing operations */ + spinlock_t lock; /* For serializing operations */ - unsigned long flowmask; /* HCI flow mask */ - int ri_latch; + unsigned long flowmask; /* HCI flow mask */ + int ri_latch; - struct sk_buff_head txq; - unsigned long tx_state; - - unsigned long rx_state; - unsigned long rx_count; - struct sk_buff *rx_skb; + struct sk_buff_head txq; + unsigned long tx_state; + unsigned long rx_state; + unsigned long rx_count; + struct sk_buff *rx_skb; } dtl1_info_t; @@ -104,7 +103,7 @@ static dev_info_t dev_info = "dtl1_cs"; dev_link_t *dtl1_attach(void); void dtl1_detach(dev_link_t *); -dev_link_t *dev_list = NULL; +static dev_link_t *dev_list = NULL; /* Transmit states */ @@ -118,282 +117,253 @@ dev_link_t *dev_list = NULL; typedef struct { - u8 type; - u8 zero; - u16 len; -} __attribute__ ((packed)) nsh_t; /* Nokia Specific Header */ + u8 type; + u8 zero; + u16 len; +} __attribute__ ((packed)) nsh_t; /* Nokia Specific Header */ -#define NSHL 4 /* Nokia Specific Header Length */ +#define NSHL 4 /* Nokia Specific Header Length */ /* ======================== Interrupt handling ======================== */ -static int dtl1_write(unsigned int iobase, int fifo_size, __u8 *buf, int len) { - - int actual = 0; - - - /* Tx FIFO should be empty */ - if (!(inb(iobase + UART_LSR) & UART_LSR_THRE)) - return 0; - +static int dtl1_write(unsigned int iobase, int fifo_size, __u8 *buf, int len) +{ + int actual = 0; - /* Fill FIFO with current frame */ - while ((fifo_size-- > 0) && (actual < len)) { - /* Transmit next byte */ - outb(buf[actual], iobase + UART_TX); - actual++; - } + /* Tx FIFO should be empty */ + if (!(inb(iobase + UART_LSR) & UART_LSR_THRE)) + return 0; + /* Fill FIFO with current frame */ + while ((fifo_size-- > 0) && (actual < len)) { + /* Transmit next byte */ + outb(buf[actual], iobase + UART_TX); + actual++; + } - return actual; - + return actual; } -static void dtl1_write_wakeup(dtl1_info_t *info) { - - if (!info) { - printk(KERN_WARNING "dtl1_cs: Call of write_wakeup for unknown device.\n"); - return; - } - - - if (test_bit(XMIT_WAITING, &(info->tx_state))) { - set_bit(XMIT_WAKEUP, &(info->tx_state)); - return; - } - - if (test_and_set_bit(XMIT_SENDING, &(info->tx_state))) { - set_bit(XMIT_WAKEUP, &(info->tx_state)); - return; - } +static void dtl1_write_wakeup(dtl1_info_t *info) +{ + if (!info) { + printk(KERN_WARNING "dtl1_cs: Call of write_wakeup for unknown device.\n"); + return; + } + if (test_bit(XMIT_WAITING, &(info->tx_state))) { + set_bit(XMIT_WAKEUP, &(info->tx_state)); + return; + } - do { - register unsigned int iobase = info->link.io.BasePort1; - register struct sk_buff *skb; - register int len; + if (test_and_set_bit(XMIT_SENDING, &(info->tx_state))) { + set_bit(XMIT_WAKEUP, &(info->tx_state)); + return; + } - clear_bit(XMIT_WAKEUP, &(info->tx_state)); + do { + register unsigned int iobase = info->link.io.BasePort1; + register struct sk_buff *skb; + register int len; - if (!(info->link.state & DEV_PRESENT)) - return; + clear_bit(XMIT_WAKEUP, &(info->tx_state)); + if (!(info->link.state & DEV_PRESENT)) + return; - if (!(skb = skb_dequeue(&(info->txq)))) - break; + if (!(skb = skb_dequeue(&(info->txq)))) + break; + /* Send frame */ + len = dtl1_write(iobase, 32, skb->data, skb->len); - /* Send frame */ - len = dtl1_write(iobase, 32, skb->data, skb->len); + if (len == skb->len) { + set_bit(XMIT_WAITING, &(info->tx_state)); + kfree_skb(skb); + } else { + skb_pull(skb, len); + skb_queue_head(&(info->txq), skb); + } - if (len == skb->len) { - set_bit(XMIT_WAITING, &(info->tx_state)); - kfree_skb(skb); - } - else { - skb_pull(skb, len); - skb_queue_head(&(info->txq), skb); - } + info->hdev.stat.byte_tx += len; - info->hdev.stat.byte_tx += len; - - } while (test_bit(XMIT_WAKEUP, &(info->tx_state))); - - - clear_bit(XMIT_SENDING, &(info->tx_state)); + } while (test_bit(XMIT_WAKEUP, &(info->tx_state))); + clear_bit(XMIT_SENDING, &(info->tx_state)); } -static void dtl1_control(dtl1_info_t *info, struct sk_buff *skb) { - - u8 flowmask = *(u8 *)skb->data; - int i; - +static void dtl1_control(dtl1_info_t *info, struct sk_buff *skb) +{ + u8 flowmask = *(u8 *)skb->data; + int i; - printk(KERN_INFO "dtl1_cs: Nokia control data = "); - for (i = 0; i < skb->len; i++) { - printk("%02x ", skb->data[i]); - } - printk("\n"); + printk(KERN_INFO "dtl1_cs: Nokia control data = "); + for (i = 0; i < skb->len; i++) { + printk("%02x ", skb->data[i]); + } + printk("\n"); + /* transition to active state */ + if (((info->flowmask & 0x07) == 0) && ((flowmask & 0x07) != 0)) { + clear_bit(XMIT_WAITING, &(info->tx_state)); + dtl1_write_wakeup(info); + } - /* transition to active state */ - if (((info->flowmask & 0x07) == 0) && ((flowmask & 0x07) != 0)) { - clear_bit(XMIT_WAITING, &(info->tx_state)); - dtl1_write_wakeup(info); - } - - info->flowmask = flowmask; - - - kfree_skb(skb); + info->flowmask = flowmask; + kfree_skb(skb); } -static void dtl1_receive(dtl1_info_t *info) { - - unsigned int iobase; - nsh_t *nsh; - int boguscount = 0; - - - if (!info) { - printk(KERN_WARNING "dtl1_cs: Call of receive for unknown device.\n"); - return; - } - - - iobase = info->link.io.BasePort1; - - do { - info->hdev.stat.byte_rx++; - - /* Allocate packet */ - if (info->rx_skb == NULL) - if (!(info->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) { - printk(KERN_WARNING "dtl1_cs: Can't allocate mem for new packet.\n"); - info->rx_state = RECV_WAIT_NSH; - info->rx_count = NSHL; - return; - } - - - *skb_put(info->rx_skb, 1) = inb(iobase + UART_RX); - nsh = (nsh_t *)info->rx_skb->data; - - info->rx_count--; - - - if (info->rx_count == 0) { - - switch (info->rx_state) { - case RECV_WAIT_NSH: - info->rx_state = RECV_WAIT_DATA; - info->rx_count = nsh->len + (nsh->len & 0x0001); - break; - case RECV_WAIT_DATA: - info->rx_skb->pkt_type = nsh->type; - - /* remove PAD byte if it exists */ - if (nsh->len & 0x0001) { - info->rx_skb->tail--; - info->rx_skb->len--; - } - - /* remove NSH */ - skb_pull(info->rx_skb, NSHL); - - - switch (info->rx_skb->pkt_type) { - case 0x80: - /* control data for the Nokia Card */ - dtl1_control(info, info->rx_skb); - break; - case 0x82: - case 0x83: - case 0x84: - /* send frame to the HCI layer */ - info->rx_skb->dev = (void *)&(info->hdev); - info->rx_skb->pkt_type &= 0x0f; - hci_recv_frame(info->rx_skb); - break; - default: - /* unknown packet */ - printk(KERN_WARNING "dtl1_cs: Unknown HCI packet with type 0x%02x received.\n", info->rx_skb->pkt_type); - kfree_skb(info->rx_skb); - break; - } - - - info->rx_state = RECV_WAIT_NSH; - info->rx_count = NSHL; - info->rx_skb = NULL; - break; - } - - } - - - /* Make sure we don't stay here to long */ - if (boguscount++ > 32) - break; - - } while (inb(iobase + UART_LSR) & UART_LSR_DR); - - +static void dtl1_receive(dtl1_info_t *info) +{ + unsigned int iobase; + nsh_t *nsh; + int boguscount = 0; + + if (!info) { + printk(KERN_WARNING "dtl1_cs: Call of receive for unknown device.\n"); + return; + } + + iobase = info->link.io.BasePort1; + + do { + info->hdev.stat.byte_rx++; + + /* Allocate packet */ + if (info->rx_skb == NULL) + if (!(info->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) { + printk(KERN_WARNING "dtl1_cs: Can't allocate mem for new packet.\n"); + info->rx_state = RECV_WAIT_NSH; + info->rx_count = NSHL; + return; + } + + *skb_put(info->rx_skb, 1) = inb(iobase + UART_RX); + nsh = (nsh_t *)info->rx_skb->data; + + info->rx_count--; + + if (info->rx_count == 0) { + + switch (info->rx_state) { + case RECV_WAIT_NSH: + info->rx_state = RECV_WAIT_DATA; + info->rx_count = nsh->len + (nsh->len & 0x0001); + break; + case RECV_WAIT_DATA: + info->rx_skb->pkt_type = nsh->type; + + /* remove PAD byte if it exists */ + if (nsh->len & 0x0001) { + info->rx_skb->tail--; + info->rx_skb->len--; + } + + /* remove NSH */ + skb_pull(info->rx_skb, NSHL); + + switch (info->rx_skb->pkt_type) { + case 0x80: + /* control data for the Nokia Card */ + dtl1_control(info, info->rx_skb); + break; + case 0x82: + case 0x83: + case 0x84: + /* send frame to the HCI layer */ + info->rx_skb->dev = (void *)&(info->hdev); + info->rx_skb->pkt_type &= 0x0f; + hci_recv_frame(info->rx_skb); + break; + default: + /* unknown packet */ + printk(KERN_WARNING "dtl1_cs: Unknown HCI packet with type 0x%02x received.\n", info->rx_skb->pkt_type); + kfree_skb(info->rx_skb); + break; + } + + info->rx_state = RECV_WAIT_NSH; + info->rx_count = NSHL; + info->rx_skb = NULL; + break; + } + + } + + /* Make sure we don't stay here to long */ + if (boguscount++ > 32) + break; + + } while (inb(iobase + UART_LSR) & UART_LSR_DR); } -void dtl1_interrupt(int irq, void *dev_inst, struct pt_regs *regs) { - - dtl1_info_t *info = dev_inst; - unsigned int iobase; - unsigned char msr; - int boguscount = 0; - int iir, lsr; - - - if (!info) { - printk(KERN_WARNING "dtl1_cs: Call of irq %d for unknown device.\n", irq); - return; - } - - - iobase = info->link.io.BasePort1; - - - spin_lock(&(info->lock)); - - iir = inb(iobase + UART_IIR) & UART_IIR_ID; - while (iir) { - - /* Clear interrupt */ - lsr = inb(iobase + UART_LSR); - - switch (iir) { - case UART_IIR_RLSI: - printk(KERN_NOTICE "dtl1_cs: RLSI\n"); - break; - case UART_IIR_RDI: - /* Receive interrupt */ - dtl1_receive(info); - break; - case UART_IIR_THRI: - if (lsr & UART_LSR_THRE) { - /* Transmitter ready for data */ - dtl1_write_wakeup(info); - } - break; - default: - printk(KERN_NOTICE "dtl1_cs: Unhandled IIR=%#x\n", iir); - break; - } - - /* Make sure we don't stay here to long */ - if (boguscount++ > 100) - break; - - iir = inb(iobase + UART_IIR) & UART_IIR_ID; - - } - - - msr = inb(iobase + UART_MSR); - - if (info->ri_latch ^ (msr & UART_MSR_RI)) { - info->ri_latch = msr & UART_MSR_RI; - clear_bit(XMIT_WAITING, &(info->tx_state)); - dtl1_write_wakeup(info); - } - - spin_unlock(&(info->lock)); - +void dtl1_interrupt(int irq, void *dev_inst, struct pt_regs *regs) +{ + dtl1_info_t *info = dev_inst; + unsigned int iobase; + unsigned char msr; + int boguscount = 0; + int iir, lsr; + + if (!info) { + printk(KERN_WARNING "dtl1_cs: Call of irq %d for unknown device.\n", irq); + return; + } + + iobase = info->link.io.BasePort1; + + spin_lock(&(info->lock)); + + iir = inb(iobase + UART_IIR) & UART_IIR_ID; + while (iir) { + + /* Clear interrupt */ + lsr = inb(iobase + UART_LSR); + + switch (iir) { + case UART_IIR_RLSI: + printk(KERN_NOTICE "dtl1_cs: RLSI\n"); + break; + case UART_IIR_RDI: + /* Receive interrupt */ + dtl1_receive(info); + break; + case UART_IIR_THRI: + if (lsr & UART_LSR_THRE) { + /* Transmitter ready for data */ + dtl1_write_wakeup(info); + } + break; + default: + printk(KERN_NOTICE "dtl1_cs: Unhandled IIR=%#x\n", iir); + break; + } + + /* Make sure we don't stay here to long */ + if (boguscount++ > 100) + break; + + iir = inb(iobase + UART_IIR) & UART_IIR_ID; + + } + + msr = inb(iobase + UART_MSR); + + if (info->ri_latch ^ (msr & UART_MSR_RI)) { + info->ri_latch = msr & UART_MSR_RI; + clear_bit(XMIT_WAITING, &(info->tx_state)); + dtl1_write_wakeup(info); + } + + spin_unlock(&(info->lock)); } @@ -401,107 +371,94 @@ void dtl1_interrupt(int irq, void *dev_inst, struct pt_regs *regs) { /* ======================== HCI interface ======================== */ -static int dtl1_hci_open(struct hci_dev *hdev) { - - set_bit(HCI_RUNNING, &(hdev->flags)); - - - return 0; +static int dtl1_hci_open(struct hci_dev *hdev) +{ + set_bit(HCI_RUNNING, &(hdev->flags)); + return 0; } -static int dtl1_hci_flush(struct hci_dev *hdev) { - - dtl1_info_t *info = (dtl1_info_t *)(hdev->driver_data); +static int dtl1_hci_flush(struct hci_dev *hdev) +{ + dtl1_info_t *info = (dtl1_info_t *)(hdev->driver_data); + /* Drop TX queue */ + skb_queue_purge(&(info->txq)); - /* Drop TX queue */ - skb_queue_purge(&(info->txq)); - - - return 0; - + return 0; } -static int dtl1_hci_close(struct hci_dev *hdev) { - - if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags))) - return 0; - +static int dtl1_hci_close(struct hci_dev *hdev) +{ + if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags))) + return 0; - dtl1_hci_flush(hdev); - - - return 0; + dtl1_hci_flush(hdev); + return 0; } -static int dtl1_hci_send_frame(struct sk_buff *skb) { - - dtl1_info_t *info; - struct hci_dev* hdev = (struct hci_dev *)(skb->dev); - struct sk_buff *s; - nsh_t nsh; - - - if (!hdev) { - printk(KERN_WARNING "dtl1_cs: Frame for unknown HCI device (hdev=NULL)."); - return -ENODEV; - } - - info = (dtl1_info_t *)(hdev->driver_data); - - - switch (skb->pkt_type) { - case HCI_COMMAND_PKT: - hdev->stat.cmd_tx++; - nsh.type = 0x81; - break; - case HCI_ACLDATA_PKT: - hdev->stat.acl_tx++; - nsh.type = 0x82; - break; - case HCI_SCODATA_PKT: - hdev->stat.sco_tx++; - nsh.type = 0x83; - break; - }; - - nsh.zero = 0; - nsh.len = skb->len; - - s = bluez_skb_alloc(NSHL + skb->len + 1, GFP_ATOMIC); - skb_reserve(s, NSHL); - memcpy(skb_put(s, skb->len), skb->data, skb->len); - if (skb->len & 0x0001) - *skb_put(s, 1) = 0; /* PAD */ - - /* Prepend skb with Nokia frame header and queue */ - memcpy(skb_push(s, NSHL), &nsh, NSHL); - skb_queue_tail(&(info->txq), s); - - - dtl1_write_wakeup(info); - - kfree_skb(skb); - - - return 0; - +static int dtl1_hci_send_frame(struct sk_buff *skb) +{ + dtl1_info_t *info; + struct hci_dev *hdev = (struct hci_dev *)(skb->dev); + struct sk_buff *s; + nsh_t nsh; + + if (!hdev) { + printk(KERN_WARNING "dtl1_cs: Frame for unknown HCI device (hdev=NULL)."); + return -ENODEV; + } + + info = (dtl1_info_t *)(hdev->driver_data); + + switch (skb->pkt_type) { + case HCI_COMMAND_PKT: + hdev->stat.cmd_tx++; + nsh.type = 0x81; + break; + case HCI_ACLDATA_PKT: + hdev->stat.acl_tx++; + nsh.type = 0x82; + break; + case HCI_SCODATA_PKT: + hdev->stat.sco_tx++; + nsh.type = 0x83; + break; + }; + + nsh.zero = 0; + nsh.len = skb->len; + + s = bluez_skb_alloc(NSHL + skb->len + 1, GFP_ATOMIC); + skb_reserve(s, NSHL); + memcpy(skb_put(s, skb->len), skb->data, skb->len); + if (skb->len & 0x0001) + *skb_put(s, 1) = 0; /* PAD */ + + /* Prepend skb with Nokia frame header and queue */ + memcpy(skb_push(s, NSHL), &nsh, NSHL); + skb_queue_tail(&(info->txq), s); + + dtl1_write_wakeup(info); + + kfree_skb(skb); + + return 0; } -static void dtl1_hci_destruct(struct hci_dev *hdev) { +static void dtl1_hci_destruct(struct hci_dev *hdev) +{ } -static int dtl1_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg) { - - return -ENOIOCTLCMD; - +static int dtl1_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg) +{ + return -ENOIOCTLCMD; } @@ -509,101 +466,91 @@ static int dtl1_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long /* ======================== Card services HCI interaction ======================== */ -int dtl1_open(dtl1_info_t *info) { - - unsigned long flags; - unsigned int iobase = info->link.io.BasePort1; - struct hci_dev *hdev; +int dtl1_open(dtl1_info_t *info) +{ + unsigned long flags; + unsigned int iobase = info->link.io.BasePort1; + struct hci_dev *hdev; + spin_lock_init(&(info->lock)); - spin_lock_init(&(info->lock)); + skb_queue_head_init(&(info->txq)); - skb_queue_head_init(&(info->txq)); + info->rx_state = RECV_WAIT_NSH; + info->rx_count = NSHL; + info->rx_skb = NULL; - info->rx_state = RECV_WAIT_NSH; - info->rx_count = NSHL; - info->rx_skb = NULL; + set_bit(XMIT_WAITING, &(info->tx_state)); - set_bit(XMIT_WAITING, &(info->tx_state)); + spin_lock_irqsave(&(info->lock), flags); + /* Reset UART */ + outb(0, iobase + UART_MCR); - spin_lock_irqsave(&(info->lock), flags); + /* Turn off interrupts */ + outb(0, iobase + UART_IER); - /* Reset UART */ - outb(0, iobase + UART_MCR); + /* Initialize UART */ + outb(UART_LCR_WLEN8, iobase + UART_LCR); /* Reset DLAB */ + outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase + UART_MCR); - /* Turn off interrupts */ - outb(0, iobase + UART_IER); + info->ri_latch = inb(info->link.io.BasePort1 + UART_MSR) & UART_MSR_RI; - /* Initialize UART */ - outb(UART_LCR_WLEN8, iobase + UART_LCR); /* Reset DLAB */ - outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase + UART_MCR); + /* Turn on interrupts */ + outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER); - info->ri_latch = inb(info->link.io.BasePort1 + UART_MSR) & UART_MSR_RI; + spin_unlock_irqrestore(&(info->lock), flags); - /* Turn on interrupts */ - outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER); + /* Timeout before it is safe to send the first HCI packet */ + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ * 2); - spin_unlock_irqrestore(&(info->lock), flags); + /* Initialize and register HCI device */ - /* Timeout before it is safe to send the first HCI packet */ - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ * 2); + hdev = &(info->hdev); + hdev->type = HCI_PCCARD; + hdev->driver_data = info; - /* Initialize and register HCI device */ + hdev->open = dtl1_hci_open; + hdev->close = dtl1_hci_close; + hdev->flush = dtl1_hci_flush; + hdev->send = dtl1_hci_send_frame; + hdev->destruct = dtl1_hci_destruct; + hdev->ioctl = dtl1_hci_ioctl; - hdev = &(info->hdev); - - hdev->type = HCI_PCCARD; - hdev->driver_data = info; - - hdev->open = dtl1_hci_open; - hdev->close = dtl1_hci_close; - hdev->flush = dtl1_hci_flush; - hdev->send = dtl1_hci_send_frame; - hdev->destruct = dtl1_hci_destruct; - hdev->ioctl = dtl1_hci_ioctl; - - if (hci_register_dev(hdev) < 0) { - printk(KERN_WARNING "dtl1_cs: Can't register HCI device %s.\n", hdev->name); - return -ENODEV; - } - - - return 0; + if (hci_register_dev(hdev) < 0) { + printk(KERN_WARNING "dtl1_cs: Can't register HCI device %s.\n", hdev->name); + return -ENODEV; + } + return 0; } -int dtl1_close(dtl1_info_t *info) { - - unsigned long flags; - unsigned int iobase = info->link.io.BasePort1; - struct hci_dev *hdev = &(info->hdev); - - - dtl1_hci_close(hdev); - - - spin_lock_irqsave(&(info->lock), flags); +int dtl1_close(dtl1_info_t *info) +{ + unsigned long flags; + unsigned int iobase = info->link.io.BasePort1; + struct hci_dev *hdev = &(info->hdev); - /* Reset UART */ - outb(0, iobase + UART_MCR); + dtl1_hci_close(hdev); - /* Turn off interrupts */ - outb(0, iobase + UART_IER); + spin_lock_irqsave(&(info->lock), flags); - spin_unlock_irqrestore(&(info->lock), flags); + /* Reset UART */ + outb(0, iobase + UART_MCR); + /* Turn off interrupts */ + outb(0, iobase + UART_IER); - if (hci_unregister_dev(hdev) < 0) - printk(KERN_WARNING "dtl1_cs: Can't unregister HCI device %s.\n", hdev->name); + spin_unlock_irqrestore(&(info->lock), flags); + if (hci_unregister_dev(hdev) < 0) + printk(KERN_WARNING "dtl1_cs: Can't unregister HCI device %s.\n", hdev->name); - return 0; - + return 0; } @@ -611,291 +558,267 @@ int dtl1_close(dtl1_info_t *info) { /* ======================== Card services ======================== */ -static void cs_error(client_handle_t handle, int func, int ret) { - - error_info_t err = { func, ret }; - - - CardServices(ReportError, handle, &err); +static void cs_error(client_handle_t handle, int func, int ret) +{ + error_info_t err = { func, ret }; + CardServices(ReportError, handle, &err); } -dev_link_t *dtl1_attach(void) { - - dtl1_info_t *info; - client_reg_t client_reg; - dev_link_t *link; - int i, ret; - - - /* Create new info device */ - info = kmalloc(sizeof(*info), GFP_KERNEL); - if (!info) - return NULL; - memset(info, 0, sizeof(*info)); - - - link = &info->link; - link->priv = info; - - link->release.function = &dtl1_release; - link->release.data = (u_long)link; - link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; - link->io.NumPorts1 = 8; - link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; - link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID; - - if (irq_list[0] == -1) - link->irq.IRQInfo2 = irq_mask; - else - for (i = 0; i < 4; i++) - link->irq.IRQInfo2 |= 1 << irq_list[i]; - - link->irq.Handler = dtl1_interrupt; - link->irq.Instance = info; - - link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.Vcc = 50; - link->conf.IntType = INT_MEMORY_AND_IO; - - - /* Register with Card Services */ - link->next = dev_list; - dev_list = link; - client_reg.dev_info = &dev_info; - client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; - client_reg.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &dtl1_event; - client_reg.Version = 0x0210; - client_reg.event_callback_args.client_data = link; - - ret = CardServices(RegisterClient, &link->handle, &client_reg); - if (ret != CS_SUCCESS) { - cs_error(link->handle, RegisterClient, ret); - dtl1_detach(link); - return NULL; - } - - - return link; - +dev_link_t *dtl1_attach(void) +{ + dtl1_info_t *info; + client_reg_t client_reg; + dev_link_t *link; + int i, ret; + + /* Create new info device */ + info = kmalloc(sizeof(*info), GFP_KERNEL); + if (!info) + return NULL; + memset(info, 0, sizeof(*info)); + + link = &info->link; + link->priv = info; + + link->release.function = &dtl1_release; + link->release.data = (u_long)link; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + link->io.NumPorts1 = 8; + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; + link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID; + + if (irq_list[0] == -1) + link->irq.IRQInfo2 = irq_mask; + else + for (i = 0; i < 4; i++) + link->irq.IRQInfo2 |= 1 << irq_list[i]; + + link->irq.Handler = dtl1_interrupt; + link->irq.Instance = info; + + link->conf.Attributes = CONF_ENABLE_IRQ; + link->conf.Vcc = 50; + link->conf.IntType = INT_MEMORY_AND_IO; + + /* Register with Card Services */ + link->next = dev_list; + dev_list = link; + client_reg.dev_info = &dev_info; + client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; + client_reg.EventMask = + CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | + CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | + CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; + client_reg.event_handler = &dtl1_event; + client_reg.Version = 0x0210; + client_reg.event_callback_args.client_data = link; + + ret = CardServices(RegisterClient, &link->handle, &client_reg); + if (ret != CS_SUCCESS) { + cs_error(link->handle, RegisterClient, ret); + dtl1_detach(link); + return NULL; + } + + return link; } -void dtl1_detach(dev_link_t *link) { - - dtl1_info_t *info = link->priv; - dev_link_t **linkp; - int ret; +void dtl1_detach(dev_link_t *link) +{ + dtl1_info_t *info = link->priv; + dev_link_t **linkp; + int ret; + /* Locate device structure */ + for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) + if (*linkp == link) + break; - /* Locate device structure */ - for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) - if (*linkp == link) - break; + if (*linkp == NULL) + return; - if (*linkp == NULL) - return; + del_timer(&link->release); + if (link->state & DEV_CONFIG) + dtl1_release((u_long)link); + if (link->handle) { + ret = CardServices(DeregisterClient, link->handle); + if (ret != CS_SUCCESS) + cs_error(link->handle, DeregisterClient, ret); + } - del_timer(&link->release); - if (link->state & DEV_CONFIG) - dtl1_release((u_long)link); - - - if (link->handle) { - ret = CardServices(DeregisterClient, link->handle); - if (ret != CS_SUCCESS) - cs_error(link->handle, DeregisterClient, ret); - } - - - /* Unlink device structure, free bits */ - *linkp = link->next; - - kfree(info); + /* Unlink device structure, free bits */ + *linkp = link->next; + kfree(info); } -static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, - cisparse_t *parse) { +static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, cisparse_t *parse) +{ + int i; - int i; + i = CardServices(fn, handle, tuple); + if (i != CS_SUCCESS) + return CS_NO_MORE_ITEMS; + i = CardServices(GetTupleData, handle, tuple); + if (i != CS_SUCCESS) + return i; - i = CardServices(fn, handle, tuple); - if (i != CS_SUCCESS) - return CS_NO_MORE_ITEMS; - - i = CardServices(GetTupleData, handle, tuple); - if (i != CS_SUCCESS) - return i; - - return CardServices(ParseTuple, handle, tuple, parse); - + return CardServices(ParseTuple, handle, tuple, parse); } #define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c) #define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c) -void dtl1_config(dev_link_t *link) { - - client_handle_t handle = link->handle; - dtl1_info_t *info = link->priv; - tuple_t tuple; - u_short buf[256]; - cisparse_t parse; - cistpl_cftable_entry_t *cf = &parse.cftable_entry; - config_info_t config; - int i, last_ret, last_fn; - - - tuple.TupleData = (cisdata_t *)buf; - tuple.TupleOffset = 0; - tuple.TupleDataMax = 255; - tuple.Attributes = 0; - - /* Get configuration register information */ - tuple.DesiredTuple = CISTPL_CONFIG; - last_ret = first_tuple(handle, &tuple, &parse); - if (last_ret != CS_SUCCESS) { - last_fn = ParseTuple; - goto cs_failed; - } - link->conf.ConfigBase = parse.config.base; - link->conf.Present = parse.config.rmask[0]; - - - /* Configure card */ - link->state |= DEV_CONFIG; - i = CardServices(GetConfigurationInfo, handle, &config); - link->conf.Vcc = config.Vcc; - - tuple.TupleData = (cisdata_t *)buf; - tuple.TupleOffset = 0; tuple.TupleDataMax = 255; - tuple.Attributes = 0; - tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - - /* Look for a generic full-sized window */ - link->io.NumPorts1 = 8; - i = first_tuple(handle, &tuple, &parse); - while (i != CS_NO_MORE_ITEMS) { - if ((i == CS_SUCCESS) && (cf->io.nwin == 1) && (cf->io.win[0].len > 8)) { - link->conf.ConfigIndex = cf->index; - link->io.BasePort1 = cf->io.win[0].base; - link->io.NumPorts1 = cf->io.win[0].len; /*yo*/ - link->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK; - i = CardServices(RequestIO, link->handle, &link->io); - if (i == CS_SUCCESS) - break; - } - i = next_tuple(handle, &tuple, &parse); - } - - if (i != CS_SUCCESS) { - cs_error(link->handle, RequestIO, i); - goto failed; - } - - i = CardServices(RequestIRQ, link->handle, &link->irq); - if (i != CS_SUCCESS) { - cs_error(link->handle, RequestIRQ, i); - link->irq.AssignedIRQ = 0; - } - - i = CardServices(RequestConfiguration, link->handle, &link->conf); - if (i != CS_SUCCESS) { - cs_error(link->handle, RequestConfiguration, i); - goto failed; - } - - - MOD_INC_USE_COUNT; - - if (dtl1_open(info) != 0) - goto failed; - - - link->dev = &info->node; - link->state &= ~DEV_CONFIG_PENDING; - - - return; - +void dtl1_config(dev_link_t *link) +{ + client_handle_t handle = link->handle; + dtl1_info_t *info = link->priv; + tuple_t tuple; + u_short buf[256]; + cisparse_t parse; + cistpl_cftable_entry_t *cf = &parse.cftable_entry; + config_info_t config; + int i, last_ret, last_fn; + + tuple.TupleData = (cisdata_t *)buf; + tuple.TupleOffset = 0; + tuple.TupleDataMax = 255; + tuple.Attributes = 0; + + /* Get configuration register information */ + tuple.DesiredTuple = CISTPL_CONFIG; + last_ret = first_tuple(handle, &tuple, &parse); + if (last_ret != CS_SUCCESS) { + last_fn = ParseTuple; + goto cs_failed; + } + link->conf.ConfigBase = parse.config.base; + link->conf.Present = parse.config.rmask[0]; + + /* Configure card */ + link->state |= DEV_CONFIG; + i = CardServices(GetConfigurationInfo, handle, &config); + link->conf.Vcc = config.Vcc; + + tuple.TupleData = (cisdata_t *)buf; + tuple.TupleOffset = 0; + tuple.TupleDataMax = 255; + tuple.Attributes = 0; + tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; + + /* Look for a generic full-sized window */ + link->io.NumPorts1 = 8; + i = first_tuple(handle, &tuple, &parse); + while (i != CS_NO_MORE_ITEMS) { + if ((i == CS_SUCCESS) && (cf->io.nwin == 1) && (cf->io.win[0].len > 8)) { + link->conf.ConfigIndex = cf->index; + link->io.BasePort1 = cf->io.win[0].base; + link->io.NumPorts1 = cf->io.win[0].len; /*yo */ + link->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK; + i = CardServices(RequestIO, link->handle, &link->io); + if (i == CS_SUCCESS) + break; + } + i = next_tuple(handle, &tuple, &parse); + } + + if (i != CS_SUCCESS) { + cs_error(link->handle, RequestIO, i); + goto failed; + } + + i = CardServices(RequestIRQ, link->handle, &link->irq); + if (i != CS_SUCCESS) { + cs_error(link->handle, RequestIRQ, i); + link->irq.AssignedIRQ = 0; + } + + i = CardServices(RequestConfiguration, link->handle, &link->conf); + if (i != CS_SUCCESS) { + cs_error(link->handle, RequestConfiguration, i); + goto failed; + } + + MOD_INC_USE_COUNT; + + if (dtl1_open(info) != 0) + goto failed; + + strcpy(info->node.dev_name, info->hdev.name); + link->dev = &info->node; + link->state &= ~DEV_CONFIG_PENDING; + + return; cs_failed: - cs_error(link->handle, last_fn, last_ret); -failed: - dtl1_release((u_long)link); + cs_error(link->handle, last_fn, last_ret); +failed: + dtl1_release((u_long)link); } -void dtl1_release(u_long arg) { - - dev_link_t *link = (dev_link_t *)arg; - dtl1_info_t *info = link->priv; +void dtl1_release(u_long arg) +{ + dev_link_t *link = (dev_link_t *)arg; + dtl1_info_t *info = link->priv; + if (link->state & DEV_PRESENT) + dtl1_close(info); - if (link->state & DEV_PRESENT) - dtl1_close(info); + MOD_DEC_USE_COUNT; - MOD_DEC_USE_COUNT; + link->dev = NULL; + CardServices(ReleaseConfiguration, link->handle); + CardServices(ReleaseIO, link->handle, &link->io); + CardServices(ReleaseIRQ, link->handle, &link->irq); - link->dev = NULL; - - CardServices(ReleaseConfiguration, link->handle); - CardServices(ReleaseIO, link->handle, &link->io); - CardServices(ReleaseIRQ, link->handle, &link->irq); - - link->state &= ~DEV_CONFIG; - + link->state &= ~DEV_CONFIG; } -int dtl1_event(event_t event, int priority, event_callback_args_t *args) { - - dev_link_t *link = args->client_data; - dtl1_info_t *info = link->priv; - - - switch (event) { - case CS_EVENT_CARD_REMOVAL: - link->state &= ~DEV_PRESENT; - if (link->state & DEV_CONFIG) { - dtl1_close(info); - mod_timer(&link->release, jiffies + HZ/20); - } - break; - case CS_EVENT_CARD_INSERTION: - link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; - dtl1_config(link); - break; - case CS_EVENT_PM_SUSPEND: - link->state |= DEV_SUSPEND; - /* Fall through... */ - case CS_EVENT_RESET_PHYSICAL: - if (link->state & DEV_CONFIG) - CardServices(ReleaseConfiguration, link->handle); - break; - case CS_EVENT_PM_RESUME: - link->state &= ~DEV_SUSPEND; - /* Fall through... */ - case CS_EVENT_CARD_RESET: - if (DEV_OK(link)) - CardServices(RequestConfiguration, link->handle, &link->conf); - break; - } - - - return 0; - +int dtl1_event(event_t event, int priority, event_callback_args_t *args) +{ + dev_link_t *link = args->client_data; + dtl1_info_t *info = link->priv; + + switch (event) { + case CS_EVENT_CARD_REMOVAL: + link->state &= ~DEV_PRESENT; + if (link->state & DEV_CONFIG) { + dtl1_close(info); + mod_timer(&link->release, jiffies + HZ / 20); + } + break; + case CS_EVENT_CARD_INSERTION: + link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; + dtl1_config(link); + break; + case CS_EVENT_PM_SUSPEND: + link->state |= DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_RESET_PHYSICAL: + if (link->state & DEV_CONFIG) + CardServices(ReleaseConfiguration, link->handle); + break; + case CS_EVENT_PM_RESUME: + link->state &= ~DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_CARD_RESET: + if (DEV_OK(link)) + CardServices(RequestConfiguration, link->handle, &link->conf); + break; + } + + return 0; } @@ -903,33 +826,29 @@ int dtl1_event(event_t event, int priority, event_callback_args_t *args) { /* ======================== Module initialization ======================== */ -int __init init_dtl1_cs(void) { - - servinfo_t serv; - int err; +int __init init_dtl1_cs(void) +{ + servinfo_t serv; + int err; + CardServices(GetCardServicesInfo, &serv); + if (serv.Revision != CS_RELEASE_CODE) { + printk(KERN_NOTICE "dtl1_cs: Card Services release does not match!\n"); + return -1; + } - CardServices(GetCardServicesInfo, &serv); - if (serv.Revision != CS_RELEASE_CODE) { - printk(KERN_NOTICE "dtl1_cs: Card Services release does not match!\n"); - return -1; - } - - - err = register_pccard_driver(&dev_info, &dtl1_attach, &dtl1_detach); - - - return err; + err = register_pccard_driver(&dev_info, &dtl1_attach, &dtl1_detach); + return err; } -void __exit exit_dtl1_cs(void) { - - unregister_pccard_driver(&dev_info); - while (dev_list != NULL) - dtl1_detach(dev_list); +void __exit exit_dtl1_cs(void) +{ + unregister_pccard_driver(&dev_info); + while (dev_list != NULL) + dtl1_detach(dev_list); } diff --git a/drivers/ide/ali14xx.c b/drivers/ide/ali14xx.c index 9d2e97c47d36..bf0600ed7ede 100644 --- a/drivers/ide/ali14xx.c +++ b/drivers/ide/ali14xx.c @@ -107,13 +107,14 @@ static inline void out_reg(u8 data, u8 reg) * Set PIO mode for the specified drive. * This function computes timing parameters * and sets controller registers accordingly. + * It assumes IRQ's are disabled or at least that no other process will + * attempt to access the IDE registers concurrently. */ static void ali14xx_tune_drive(struct ata_device *drive, u8 pio) { int drive_num; int time1, time2; u8 param1, param2, param3, param4; - unsigned long flags; struct ata_timing *t; if (pio == 255) @@ -140,15 +141,12 @@ static void ali14xx_tune_drive(struct ata_device *drive, u8 pio) /* stuff timing parameters into controller registers */ drive_num = (drive->channel->index << 1) + drive->select.b.unit; - save_flags(flags); /* all CPUs */ - cli(); /* all CPUs */ outb_p(reg_on, base_port); out_reg(param1, reg_tab[drive_num].reg1); out_reg(param2, reg_tab[drive_num].reg2); out_reg(param3, reg_tab[drive_num].reg3); out_reg(param4, reg_tab[drive_num].reg4); outb_p(reg_off, base_port); - restore_flags(flags); /* all CPUs */ } /* diff --git a/drivers/ide/cs5530.c b/drivers/ide/cs5530.c index 89ee79cfcda3..86540a2709fe 100644 --- a/drivers/ide/cs5530.c +++ b/drivers/ide/cs5530.c @@ -218,6 +218,7 @@ static unsigned int __init pci_init_cs5530(struct pci_dev *dev) } } } + if (!master_0) { printk("%s: unable to locate PCI MASTER function\n", dev->name); return 0; @@ -227,15 +228,13 @@ static unsigned int __init pci_init_cs5530(struct pci_dev *dev) return 0; } - save_flags(flags); - cli(); /* all CPUs (there should only be one CPU with this chipset) */ - /* * Enable BusMaster and MemoryWriteAndInvalidate for the cs5530: * --> OR 0x14 into 16-bit PCI COMMAND reg of function 0 of the cs5530 */ - pci_read_config_word (cs5530_0, PCI_COMMAND, &pcicmd); - pci_write_config_word(cs5530_0, PCI_COMMAND, pcicmd | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE); + + pci_set_master(cs5530_0); + pci_set_mwi(cs5530_0); /* * Set PCI CacheLineSize to 16-bytes: @@ -274,8 +273,6 @@ static unsigned int __init pci_init_cs5530(struct pci_dev *dev) pci_write_config_byte(master_0, 0x42, 0x00); pci_write_config_byte(master_0, 0x43, 0xc1); - restore_flags(flags); - return 0; } diff --git a/drivers/ide/dtc2278.c b/drivers/ide/dtc2278.c index 8d947231d2ab..61583d9c8001 100644 --- a/drivers/ide/dtc2278.c +++ b/drivers/ide/dtc2278.c @@ -66,21 +66,18 @@ static void sub22 (char b, char c) } } +/* Assumes IRQ's are disabled or at least that no other process will + attempt to access the IDE registers concurrently. */ static void tune_dtc2278(struct ata_device *drive, u8 pio) { - unsigned long flags; - pio = ata_timing_mode(drive, XFER_PIO | XFER_EPIO) - XFER_PIO_0; if (pio >= 3) { - save_flags(flags); /* all CPUs */ - cli(); /* all CPUs */ /* * This enables PIO mode4 (3?) on the first interface */ sub22(1,0xc3); sub22(0,0xa0); - restore_flags(flags); /* all CPUs */ } else { /* we don't know how to set it back again.. */ } diff --git a/drivers/ide/hd.c b/drivers/ide/hd.c index f5fb26632eb2..31de0290cd79 100644 --- a/drivers/ide/hd.c +++ b/drivers/ide/hd.c @@ -1,15 +1,11 @@ /* - * linux/drivers/ide/hd.c - * * Copyright (C) 1991, 1992 Linus Torvalds - */ - -/* + * * This is the low-level hd interrupt support. It traverses the * request-list, using interrupts to jump between functions. As * all the functions are called within interrupts, we may not * sleep. Special care is recommended. - * + * * modified by Drew Eckhardt to check nr of hd's from the CMOS. * * Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug @@ -26,10 +22,10 @@ * Bugfix: max_sectors must be <= 255 or the wheels tend to come * off in a hurry once you queue things up - Paul G. 02/2001 */ - + /* Uncomment the following if you want verbose error reports. */ /* #define VERBOSE_ERRORS */ - + #include <linux/errno.h> #include <linux/signal.h> #include <linux/sched.h> @@ -37,7 +33,6 @@ #include <linux/fs.h> #include <linux/devfs_fs_kernel.h> #include <linux/kernel.h> -#include <linux/hdreg.h> #include <linux/genhd.h> #include <linux/slab.h> #include <linux/string.h> @@ -45,6 +40,7 @@ #include <linux/mc146818rtc.h> /* CMOS defines */ #include <linux/init.h> #include <linux/blkpg.h> +#include <linux/hdreg.h> #define REALLY_SLOW_IO #include <asm/system.h> @@ -55,6 +51,15 @@ #define DEVICE_NR(device) (minor(device)>>6) #include <linux/blk.h> +/* ATA commands we use. + */ +#define WIN_SPECIFY 0x91 /* set drive geometry translation */ +#define WIN_RESTORE 0x10 +#define WIN_READ 0x20 /* 28-Bit */ +#define WIN_WRITE 0x30 /* 28-Bit */ + +#define HD_IRQ 14 /* the standard disk interrupt */ + #ifdef __arm__ #undef HD_IRQ #endif @@ -63,6 +68,45 @@ #define HD_IRQ IRQ_HARDDISK #endif +/* Hd controller regster ports */ + +#define HD_DATA 0x1f0 /* _CTL when writing */ +#define HD_ERROR 0x1f1 /* see err-bits */ +#define HD_NSECTOR 0x1f2 /* nr of sectors to read/write */ +#define HD_SECTOR 0x1f3 /* starting sector */ +#define HD_LCYL 0x1f4 /* starting cylinder */ +#define HD_HCYL 0x1f5 /* high byte of starting cyl */ +#define HD_CURRENT 0x1f6 /* 101dhhhh , d=drive, hhhh=head */ +#define HD_STATUS 0x1f7 /* see status-bits */ +#define HD_FEATURE HD_ERROR /* same io address, read=error, write=feature */ +#define HD_PRECOMP HD_FEATURE /* obsolete use of this port - predates IDE */ +#define HD_COMMAND HD_STATUS /* same io address, read=status, write=cmd */ + +#define HD_CMD 0x3f6 /* used for resets */ +#define HD_ALTSTATUS 0x3f6 /* same as HD_STATUS but doesn't clear irq */ + +/* Bits of HD_STATUS */ +#define ERR_STAT 0x01 +#define INDEX_STAT 0x02 +#define ECC_STAT 0x04 /* Corrected error */ +#define DRQ_STAT 0x08 +#define SEEK_STAT 0x10 +#define SERVICE_STAT SEEK_STAT +#define WRERR_STAT 0x20 +#define READY_STAT 0x40 +#define BUSY_STAT 0x80 + +/* Bits for HD_ERROR */ +#define MARK_ERR 0x01 /* Bad address mark */ +#define TRK0_ERR 0x02 /* couldn't find track 0 */ +#define ABRT_ERR 0x04 /* Command aborted */ +#define MCR_ERR 0x08 /* media change request */ +#define ID_ERR 0x10 /* ID field not found */ +#define MC_ERR 0x20 /* media changed */ +#define ECC_ERR 0x40 /* Uncorrectable ECC error */ +#define BBD_ERR 0x80 /* pre-EIDE meaning: block marked bad */ +#define ICRC_ERR 0x80 /* new meaning: CRC error during transfer */ + static spinlock_t hd_lock = SPIN_LOCK_UNLOCKED; static int revalidate_hddisk(kdev_t, int); @@ -162,12 +206,9 @@ void __init hd_setup(char *str, int *ints) static void dump_status (const char *msg, unsigned int stat) { - unsigned long flags; char devc; devc = !blk_queue_empty(QUEUE) ? 'a' + DEVICE_NR(CURRENT->rq_dev) : '?'; - save_flags (flags); - sti(); #ifdef VERBOSE_ERRORS printk("hd%c: %s: status=0x%02x { ", devc, msg, stat & 0xff); if (stat & BUSY_STAT) printk("Busy "); @@ -207,8 +248,7 @@ static void dump_status (const char *msg, unsigned int stat) hd_error = inb(HD_ERROR); printk("hd%c: %s: error=0x%02x.\n", devc, msg, hd_error & 0xff); } -#endif /* verbose errors */ - restore_flags (flags); +#endif } void check_status(void) @@ -467,7 +507,7 @@ ok_to_write: if (i > 0) { SET_HANDLER(&write_intr); outsw(HD_DATA,CURRENT->buffer,256); - sti(); + local_irq_enable(); } else { #if (HD_DELAY > 0) last_req = read_timer(); @@ -500,7 +540,7 @@ static void hd_times_out(unsigned long dummy) return; disable_irq(HD_IRQ); - sti(); + local_irq_enable(); reset = 1; dev = DEVICE_NR(CURRENT->rq_dev); printk("hd%c: timeout\n", dev+'a'); @@ -510,7 +550,7 @@ static void hd_times_out(unsigned long dummy) #endif end_request(CURRENT, 0); } - cli(); + local_irq_disable(); hd_request(); enable_irq(HD_IRQ); } @@ -548,7 +588,7 @@ static void hd_request(void) return; repeat: del_timer(&device_timer); - sti(); + local_irq_enable(); if (blk_queue_empty(QUEUE)) { do_hd = NULL; @@ -556,7 +596,7 @@ repeat: } if (reset) { - cli(); + local_irq_disable(); reset_hd(); return; } @@ -688,7 +728,7 @@ static void hd_interrupt(int irq, void *dev_id, struct pt_regs *regs) if (!handler) handler = unexpected_hd_interrupt; handler(); - sti(); + local_irq_enable(); } static struct block_device_operations hd_fops = { diff --git a/drivers/ide/ht6560b.c b/drivers/ide/ht6560b.c index 34207cd5d911..4594368da382 100644 --- a/drivers/ide/ht6560b.c +++ b/drivers/ide/ht6560b.c @@ -249,12 +249,8 @@ static u8 ht_pio2timings(struct ata_device *drive, u8 pio) */ static void ht_set_prefetch(struct ata_device *drive, u8 state) { - unsigned long flags; int t = HT_PREFETCH_MODE << 8; - save_flags (flags); /* all CPUs */ - cli(); /* all CPUs */ - /* * Prefetch mode and unmask irq seems to conflict */ @@ -267,16 +263,16 @@ static void ht_set_prefetch(struct ata_device *drive, u8 state) drive->channel->no_unmask = 0; } - restore_flags (flags); /* all CPUs */ - #ifdef DEBUG printk("ht6560b: drive %s prefetch mode %sabled\n", drive->name, (state ? "en" : "dis")); #endif } +/* Assumes IRQ's are disabled or at least that no other process will attempt to + * access the IDE registers concurrently. + */ static void tune_ht6560b(struct ata_device *drive, u8 pio) { - unsigned long flags; u8 timing; switch (pio) { @@ -288,14 +284,9 @@ static void tune_ht6560b(struct ata_device *drive, u8 pio) timing = ht_pio2timings(drive, pio); - save_flags (flags); /* all CPUs */ - cli(); /* all CPUs */ - drive->drive_data &= 0xff00; drive->drive_data |= timing; - restore_flags (flags); /* all CPUs */ - #ifdef DEBUG printk("ht6560b: drive %s tuned to pio mode %#x timing=%#x\n", drive->name, pio, timing); #endif diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index 1e4dbbebcec7..574895510c0e 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -305,8 +305,9 @@ #include <linux/interrupt.h> #include <linux/errno.h> #include <linux/cdrom.h> -#include <linux/ide.h> #include <linux/completion.h> +#include <linux/hdreg.h> +#include <linux/ide.h> #include <asm/irq.h> #include <asm/io.h> @@ -2914,7 +2915,7 @@ int ide_cdrom_cleanup(struct ata_device *drive) struct cdrom_info *info = drive->driver_data; struct cdrom_device_info *devinfo = &info->devinfo; - if (ide_unregister_subdriver (drive)) + if (ata_unregister_device(drive)) return 1; if (info->buffer != NULL) kfree(info->buffer); @@ -2973,7 +2974,7 @@ static void ide_cdrom_attach(struct ata_device *drive) printk(KERN_ERR "%s: Can't allocate a cdrom structure\n", drive->name); return; } - if (ide_register_subdriver (drive, &ide_cdrom_driver)) { + if (ata_register_device(drive, &ide_cdrom_driver)) { printk(KERN_ERR "%s: Failed to register the driver with ide.c\n", drive->name); kfree (info); return; diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c index 4070de3d2832..ccd271701974 100644 --- a/drivers/ide/ide-disk.c +++ b/drivers/ide/ide-disk.c @@ -1279,7 +1279,7 @@ static int idedisk_cleanup(struct ata_device *drive) printk (KERN_INFO "%s: Write Cache FAILED Flushing!\n", drive->name); } - ret = ide_unregister_subdriver(drive); + ret = ata_unregister_device(drive); /* FIXME: This is killing the kernel with BUG 185 at asm/spinlocks.h * horribly. Check whatever we did REGISTER the device properly @@ -1471,8 +1471,8 @@ static void idedisk_attach(struct ata_device *drive) if (req[0] != '\0' && strcmp(req, "ide-disk")) return; - if (ide_register_subdriver(drive, &idedisk_driver)) { - printk (KERN_ERR "ide-disk: %s: Failed to register the driver with ide.c\n", drive->name); + if (ata_register_device(drive, &idedisk_driver)) { + printk(KERN_ERR "%s: Failed to register the driver with ide.c\n", drive->name); return; } diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c index e346d1d12b58..4651a5319935 100644 --- a/drivers/ide/ide-floppy.c +++ b/drivers/ide/ide-floppy.c @@ -94,9 +94,10 @@ #include <linux/genhd.h> #include <linux/slab.h> #include <linux/cdrom.h> +#include <linux/buffer_head.h> +#include <linux/hdreg.h> #include <linux/ide.h> #include <linux/atapi.h> -#include <linux/buffer_head.h> #include <asm/byteorder.h> #include <asm/irq.h> @@ -1722,10 +1723,10 @@ static int idefloppy_cleanup(struct ata_device *drive) { idefloppy_floppy_t *floppy = drive->driver_data; - if (ide_unregister_subdriver (drive)) + if (ata_unregister_device(drive)) return 1; drive->driver_data = NULL; - kfree (floppy); + kfree(floppy); return 0; } @@ -1779,7 +1780,7 @@ static void idefloppy_attach(struct ata_device *drive) drive->name); return; } - if (ide_register_subdriver(drive, &idefloppy_driver)) { + if (ata_register_device(drive, &idefloppy_driver)) { printk(KERN_ERR "ide-floppy: %s: Failed to register the driver with ide.c\n", drive->name); kfree (floppy); return; diff --git a/drivers/ide/ide-pci.c b/drivers/ide/ide-pci.c index a9173ffad2dd..c3f821a4c17a 100644 --- a/drivers/ide/ide-pci.c +++ b/drivers/ide/ide-pci.c @@ -550,7 +550,8 @@ static void __init hpt374_device_order_fixup (struct pci_dev *dev, struct ata_pc if (!dev2) { return; } else { - byte irq = 0, irq2 = 0; + u8 irq = 0; + u8 irq2 = 0; pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq); pci_read_config_byte(dev2, PCI_INTERRUPT_LINE, &irq2); if (irq != irq2) { diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index 4dc463ba33fa..ab4ddba56fee 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c @@ -7,401 +7,18 @@ * * It is hereby placed under the terms of the GNU general public license. * (See linux/COPYING). - */ - -/* - * BIG FAT FIXME: clean tape->spinlock locking --bzolnier - */ - -/* - * IDE ATAPI streaming tape driver. - * - * This driver is a part of the Linux ide driver and works in co-operation - * with linux/drivers/block/ide.c. - * - * The driver, in co-operation with ide.c, basically traverses the - * request-list for the block device interface. The character device - * interface, on the other hand, creates new requests, adds them - * to the request-list of the block device, and waits for their completion. - * - * Pipelined operation mode is now supported on both reads and writes. - * - * The block device major and minor numbers are determined from the - * tape's relative position in the ide interfaces, as explained in ide.c. - * - * The character device interface consists of the following devices: - * - * ht0 major 37, minor 0 first IDE tape, rewind on close. - * ht1 major 37, minor 1 second IDE tape, rewind on close. - * ... - * nht0 major 37, minor 128 first IDE tape, no rewind on close. - * nht1 major 37, minor 129 second IDE tape, no rewind on close. - * ... - * - * Run linux/scripts/MAKEDEV.ide to create the above entries. - * - * The general magnetic tape commands compatible interface, as defined by - * include/linux/mtio.h, is accessible through the character device. - * - * General ide driver configuration options, such as the interrupt-unmask - * flag, can be configured by issuing an ioctl to the block device interface, - * as any other ide device. - * - * Our own ide-tape ioctl's can be issued to either the block device or - * the character device interface. - * - * Maximal throughput with minimal bus load will usually be achieved in the - * following scenario: - * - * 1. ide-tape is operating in the pipelined operation mode. - * 2. No buffering is performed by the user backup program. - * - * Testing was done with a 2 GB CONNER CTMA 4000 IDE ATAPI Streaming Tape Drive. - * - * Ver 0.1 Nov 1 95 Pre-working code :-) - * Ver 0.2 Nov 23 95 A short backup (few megabytes) and restore procedure - * was successful ! (Using tar cvf ... on the block - * device interface). - * A longer backup resulted in major swapping, bad - * overall Linux performance and eventually failed as - * we received non serial read-ahead requests from the - * buffer cache. - * Ver 0.3 Nov 28 95 Long backups are now possible, thanks to the - * character device interface. Linux's responsiveness - * and performance doesn't seem to be much affected - * from the background backup procedure. - * Some general mtio.h magnetic tape operations are - * now supported by our character device. As a result, - * popular tape utilities are starting to work with - * ide tapes :-) - * The following configurations were tested: - * 1. An IDE ATAPI TAPE shares the same interface - * and irq with an IDE ATAPI CDROM. - * 2. An IDE ATAPI TAPE shares the same interface - * and irq with a normal IDE disk. - * Both configurations seemed to work just fine ! - * However, to be on the safe side, it is meanwhile - * recommended to give the IDE TAPE its own interface - * and irq. - * The one thing which needs to be done here is to - * add a "request postpone" feature to ide.c, - * so that we won't have to wait for the tape to finish - * performing a long media access (DSC) request (such - * as a rewind) before we can access the other device - * on the same interface. This effect doesn't disturb - * normal operation most of the time because read/write - * requests are relatively fast, and once we are - * performing one tape r/w request, a lot of requests - * from the other device can be queued and ide.c will - * service all of them after this single tape request. - * Ver 1.0 Dec 11 95 Integrated into Linux 1.3.46 development tree. - * On each read / write request, we now ask the drive - * if we can transfer a constant number of bytes - * (a parameter of the drive) only to its buffers, - * without causing actual media access. If we can't, - * we just wait until we can by polling the DSC bit. - * This ensures that while we are not transferring - * more bytes than the constant referred to above, the - * interrupt latency will not become too high and - * we won't cause an interrupt timeout, as happened - * occasionally in the previous version. - * While polling for DSC, the current request is - * postponed and ide.c is free to handle requests from - * the other device. This is handled transparently to - * ide.c. The hwgroup locking method which was used - * in the previous version was removed. - * Use of new general features which are provided by - * ide.c for use with atapi devices. - * (Programming done by Mark Lord) - * Few potential bug fixes (Again, suggested by Mark) - * Single character device data transfers are now - * not limited in size, as they were before. - * We are asking the tape about its recommended - * transfer unit and send a larger data transfer - * as several transfers of the above size. - * For best results, use an integral number of this - * basic unit (which is shown during driver - * initialization). I will soon add an ioctl to get - * this important parameter. - * Our data transfer buffer is allocated on startup, - * rather than before each data transfer. This should - * ensure that we will indeed have a data buffer. - * Ver 1.1 Dec 14 95 Fixed random problems which occurred when the tape - * shared an interface with another device. - * (poll_for_dsc was a complete mess). - * Removed some old (non-active) code which had - * to do with supporting buffer cache originated - * requests. - * The block device interface can now be opened, so - * that general ide driver features like the unmask - * interrupts flag can be selected with an ioctl. - * This is the only use of the block device interface. - * New fast pipelined operation mode (currently only on - * writes). When using the pipelined mode, the - * throughput can potentially reach the maximum - * tape supported throughput, regardless of the - * user backup program. On my tape drive, it sometimes - * boosted performance by a factor of 2. Pipelined - * mode is enabled by default, but since it has a few - * downfalls as well, you may want to disable it. - * A short explanation of the pipelined operation mode - * is available below. - * Ver 1.2 Jan 1 96 Eliminated pipelined mode race condition. - * Added pipeline read mode. As a result, restores - * are now as fast as backups. - * Optimized shared interface behavior. The new behavior - * typically results in better IDE bus efficiency and - * higher tape throughput. - * Pre-calculation of the expected read/write request - * service time, based on the tape's parameters. In - * the pipelined operation mode, this allows us to - * adjust our polling frequency to a much lower value, - * and thus to dramatically reduce our load on Linux, - * without any decrease in performance. - * Implemented additional mtio.h operations. - * The recommended user block size is returned by - * the MTIOCGET ioctl. - * Additional minor changes. - * Ver 1.3 Feb 9 96 Fixed pipelined read mode bug which prevented the - * use of some block sizes during a restore procedure. - * The character device interface will now present a - * continuous view of the media - any mix of block sizes - * during a backup/restore procedure is supported. The - * driver will buffer the requests internally and - * convert them to the tape's recommended transfer - * unit, making performance almost independent of the - * chosen user block size. - * Some improvements in error recovery. - * By cooperating with ide-dma.c, bus mastering DMA can - * now sometimes be used with IDE tape drives as well. - * Bus mastering DMA has the potential to dramatically - * reduce the CPU's overhead when accessing the device, - * and can be enabled by using hdparm -d1 on the tape's - * block device interface. For more info, read the - * comments in ide-dma.c. - * Ver 1.4 Mar 13 96 Fixed serialize support. - * Ver 1.5 Apr 12 96 Fixed shared interface operation, broken in 1.3.85. - * Fixed pipelined read mode inefficiency. - * Fixed nasty null dereferencing bug. - * Ver 1.6 Aug 16 96 Fixed FPU usage in the driver. - * Fixed end of media bug. - * Ver 1.7 Sep 10 96 Minor changes for the CONNER CTT8000-A model. - * Ver 1.8 Sep 26 96 Attempt to find a better balance between good - * interactive response and high system throughput. - * Ver 1.9 Nov 5 96 Automatically cross encountered filemarks rather - * than requiring an explicit FSF command. - * Abort pending requests at end of media. - * MTTELL was sometimes returning incorrect results. - * Return the real block size in the MTIOCGET ioctl. - * Some error recovery bug fixes. - * Ver 1.10 Nov 5 96 Major reorganization. - * Reduced CPU overhead a bit by eliminating internal - * bounce buffers. - * Added module support. - * Added multiple tape drives support. - * Added partition support. - * Rewrote DSC handling. - * Some portability fixes. - * Removed ide-tape.h. - * Additional minor changes. - * Ver 1.11 Dec 2 96 Bug fix in previous DSC timeout handling. - * Use ide_stall_queue() for DSC overlap. - * Use the maximum speed rather than the current speed - * to compute the request service time. - * Ver 1.12 Dec 7 97 Fix random memory overwriting and/or last block data - * corruption, which could occur if the total number - * of bytes written to the tape was not an integral - * number of tape blocks. - * Add support for INTERRUPT DRQ devices. - * Ver 1.13 Jan 2 98 Add "speed == 0" work-around for HP COLORADO 5GB - * Ver 1.14 Dec 30 98 Partial fixes for the Sony/AIWA tape drives. - * Replace cli()/sti() with hwgroup spinlocks. - * Ver 1.15 Mar 25 99 Fix SMP race condition by replacing hwgroup - * spinlock with private per-tape spinlock. - * Ver 1.16 Sep 1 99 Add OnStream tape support. - * Abort read pipeline on EOD. - * Wait for the tape to become ready in case it returns - * "in the process of becoming ready" on open(). - * Fix zero padding of the last written block in - * case the tape block size is larger than PAGE_SIZE. - * Decrease the default disconnection time to tn. - * Ver 1.16e Oct 3 99 Minor fixes. - * Ver 1.16e1 Oct 13 99 Patches by Arnold Niessen, - * niessen@iae.nl / arnold.niessen@philips.com - * GO-1) Undefined code in idetape_read_position - * according to Gadi's email - * AJN-1) Minor fix asc == 11 should be asc == 0x11 - * in idetape_issue_packet_command (did effect - * debugging output only) - * AJN-2) Added more debugging output, and - * added ide-tape: where missing. I would also - * like to add tape->name where possible - * AJN-3) Added different debug_level's - * via /proc/ide/hdc/settings - * "debug_level" determines amount of debugging output; - * can be changed using /proc/ide/hdx/settings - * 0 : almost no debugging output - * 1 : 0+output errors only - * 2 : 1+output all sensekey/asc - * 3 : 2+follow all chrdev related procedures - * 4 : 3+follow all procedures - * 5 : 4+include pc_stack rq_stack info - * 6 : 5+USE_COUNT updates - * AJN-4) Fixed timeout for retension in idetape_queue_pc_tail - * from 5 to 10 minutes - * AJN-5) Changed maximum number of blocks to skip when - * reading tapes with multiple consecutive write - * errors from 100 to 1000 in idetape_get_logical_blk - * Proposed changes to code: - * 1) output "logical_blk_num" via /proc - * 2) output "current_operation" via /proc - * 3) Either solve or document the fact that `mt rewind' is - * required after reading from /dev/nhtx to be - * able to rmmod the idetape module; - * Also, sometimes an application finishes but the - * device remains `busy' for some time. Same cause ? - * Proposed changes to release-notes: - * 4) write a simple `quickstart' section in the - * release notes; I volunteer if you don't want to - * 5) include a pointer to video4linux in the doc - * to stimulate video applications - * 6) release notes lines 331 and 362: explain what happens - * if the application data rate is higher than 1100 KB/s; - * similar approach to lower-than-500 kB/s ? - * 7) 6.6 Comparison; wouldn't it be better to allow different - * strategies for read and write ? - * Wouldn't it be better to control the tape buffer - * contents instead of the bandwidth ? - * 8) line 536: replace will by would (if I understand - * this section correctly, a hypothetical and unwanted situation - * is being described) - * Ver 1.16f Dec 15 99 Change place of the secondary OnStream header frames. - * Ver 1.17 Nov 2000 / Jan 2001 Marcel Mol, marcel@mesa.nl - * - Add idetape_onstream_mode_sense_tape_parameter_page - * function to get tape capacity in frames: tape->capacity. - * - Add support for DI-50 drives( or any DI- drive). - * - 'workaround' for read error/blank block arround block 3000. - * - Implement Early warning for end of media for Onstream. - * - Cosmetic code changes for readability. - * - Idetape_position_tape should not use SKIP bit during - * Onstream read recovery. - * - Add capacity, logical_blk_num and first/last_frame_position - * to /proc/ide/hd?/settings. - * - Module use count was gone in the Linux 2.4 driver. - * Ver 1.17a Apr 2001 Willem Riede osst@riede.org - * - Get drive's actual block size from mode sense block descriptor - * - Limit size of pipeline - * - * Here are some words from the first releases of hd.c, which are quoted - * in ide.c and apply here as well: - * - * | Special care is recommended. Have Fun! - * - */ - -/* - * An overview of the pipelined operation mode. - * - * In the pipelined write mode, we will usually just add requests to our - * pipeline and return immediately, before we even start to service them. The - * user program will then have enough time to prepare the next request while - * we are still busy servicing previous requests. In the pipelined read mode, - * the situation is similar - we add read-ahead requests into the pipeline, - * before the user even requested them. - * - * The pipeline can be viewed as a "safety net" which will be activated when - * the system load is high and prevents the user backup program from keeping up - * with the current tape speed. At this point, the pipeline will get - * shorter and shorter but the tape will still be streaming at the same speed. - * Assuming we have enough pipeline stages, the system load will hopefully - * decrease before the pipeline is completely empty, and the backup program - * will be able to "catch up" and refill the pipeline again. - * - * When using the pipelined mode, it would be best to disable any type of - * buffering done by the user program, as ide-tape already provides all the - * benefits in the kernel, where it can be done in a more efficient way. - * As we will usually not block the user program on a request, the most - * efficient user code will then be a simple read-write-read-... cycle. - * Any additional logic will usually just slow down the backup process. - * - * Using the pipelined mode, I get a constant over 400 KBps throughput, - * which seems to be the maximum throughput supported by my tape. - * - * However, there are some downfalls: - * - * 1. We use memory (for data buffers) in proportional to the number - * of pipeline stages (each stage is about 26 KB with my tape). - * 2. In the pipelined write mode, we cheat and postpone error codes - * to the user task. In read mode, the actual tape position - * will be a bit further than the last requested block. - * - * Concerning (1): - * - * 1. We allocate stages dynamically only when we need them. When - * we don't need them, we don't consume additional memory. In - * case we can't allocate stages, we just manage without them - * (at the expense of decreased throughput) so when Linux is - * tight in memory, we will not pose additional difficulties. - * - * 2. The maximum number of stages (which is, in fact, the maximum - * amount of memory) which we allocate is limited by the compile - * time parameter IDETAPE_MAX_PIPELINE_STAGES. - * - * 3. The maximum number of stages is a controlled parameter - We - * don't start from the user defined maximum number of stages - * but from the lower IDETAPE_MIN_PIPELINE_STAGES (again, we - * will not even allocate this amount of stages if the user - * program can't handle the speed). We then implement a feedback - * loop which checks if the pipeline is empty, and if it is, we - * increase the maximum number of stages as necessary until we - * reach the optimum value which just manages to keep the tape - * busy with minimum allocated memory or until we reach - * IDETAPE_MAX_PIPELINE_STAGES. - * - * Concerning (2): - * - * In pipelined write mode, ide-tape can not return accurate error codes - * to the user program since we usually just add the request to the - * pipeline without waiting for it to be serviced. In case an error - * occurs, I will report it on the next user request. * - * In the pipelined read mode, subsequent read requests or forward - * filemark spacing will perform correctly, as we preserve all blocks - * and filemarks which we encountered during our excess read-ahead. - * - * For accurate tape positioning and error reporting, disabling - * pipelined mode might be the best option. + * Contributors: * - * You can enable/disable/tune the pipelined operation mode by adjusting - * the compile time parameters below. + * Oct 1999 Arnold Niessen, <niessen@iae.nl>, <arnold.niessen@philips.com> + * Nov 2000, Jan 2001 Marcel Mol, <marcel@mesa.nl> + * Apr 2001 Willem Riede, <osst@riede.org> */ /* - * Possible improvements. - * - * 1. Support for the ATAPI overlap protocol. - * - * In order to maximize bus throughput, we currently use the DSC - * overlap method which enables ide.c to service requests from the - * other device while the tape is busy executing a command. The - * DSC overlap method involves polling the tape's status register - * for the DSC bit, and servicing the other device while the tape - * isn't ready. - * - * In the current QIC development standard (December 1995), - * it is recommended that new tape drives will *in addition* - * implement the ATAPI overlap protocol, which is used for the - * same purpose - efficient use of the IDE bus, but is interrupt - * driven and thus has much less CPU overhead. - * - * ATAPI overlap is likely to be supported in most new ATAPI - * devices, including new ATAPI cdroms, and thus provides us - * a method by which we can achieve higher throughput when - * sharing a (fast) ATA-2 disk with any (slow) new ATAPI device. + * FIXME: clean tape->spinlock locking --bzolnier */ -#define IDETAPE_VERSION "1.17a" - #include <linux/config.h> #include <linux/module.h> #include <linux/types.h> @@ -419,9 +36,10 @@ #include <linux/pci.h> #include <linux/smp_lock.h> #include <linux/completion.h> +#include <linux/buffer_head.h> +#include <linux/hdreg.h> #include <linux/ide.h> #include <linux/atapi.h> -#include <linux/buffer_head.h> #include <asm/byteorder.h> #include <asm/irq.h> @@ -445,6 +63,7 @@ #define OS_DATA_STARTFRAME1 20 #define OS_DATA_ENDFRAME1 2980 + /* * partition */ @@ -1249,7 +868,7 @@ char *idetape_sense_key_verbose(u8 idetape_sense_key) } } -char *idetape_command_key_verbose (byte idetape_command_key) +char *idetape_command_key_verbose(u8 idetape_command_key) { switch (idetape_command_key) { case IDETAPE_TEST_UNIT_READY_CMD: return("TEST_UNIT_READY_CMD"); @@ -1439,7 +1058,7 @@ static void idetape_analyze_error(struct ata_device *drive, atapi_request_sense_ # if IDETAPE_DEBUG_LOG_VERBOSE if (tape->debug_level >= 1) printk (KERN_INFO "ide-tape: pc = %s, sense key = %x, asc = %x, ascq = %x\n", - idetape_command_key_verbose((byte) pc->c[0]), + idetape_command_key_verbose(pc->c[0]), result->sense_key, result->asc, result->ascq); @@ -2166,7 +1785,7 @@ static void idetape_pc_callback(struct ata_device *drive, struct request *rq) /* * A mode sense command is used to "sense" tape parameters. */ -static void idetape_create_mode_sense_cmd(struct atapi_packet_command *pc, byte page_code) +static void idetape_create_mode_sense_cmd(struct atapi_packet_command *pc, u8 page_code) { atapi_init_pc(pc); pc->c[0] = IDETAPE_MODE_SENSE_CMD; @@ -3225,7 +2844,7 @@ static int __idetape_discard_read_pipeline(struct ata_device *drive) * of the request queue and wait for their completion. * */ -static int idetape_position_tape(struct ata_device *drive, unsigned int block, byte partition, int skip) +static int idetape_position_tape(struct ata_device *drive, unsigned int block, u8 partition, int skip) { idetape_tape_t *tape = drive->driver_data; int retval; @@ -3981,7 +3600,7 @@ static int idetape_add_chrdev_read_request(struct ata_device *drive,int blocks) printk (KERN_ERR "ide-tape: bug: trying to return more bytes than requested\n"); bytes_read=blocks*tape->tape_block_size; } -#endif /* IDETAPE_DEBUG_BUGS */ +#endif return (bytes_read); } @@ -5892,18 +5511,17 @@ static int idetape_cleanup(struct ata_device *drive) int minor = tape->minor; unsigned long flags; - save_flags (flags); /* all CPUs (overkill?) */ - cli(); /* all CPUs (overkill?) */ + spin_lock_irqsave (&tape->spinlock, flags); /* overkill? */ if (test_bit (IDETAPE_BUSY, &tape->flags) || tape->first_stage != NULL || tape->merge_stage_size || drive->usage) { - restore_flags(flags); /* all CPUs (overkill?) */ + spin_unlock_irqrestore(&tape->spinlock, flags); return 1; } idetape_chrdevs[minor].drive = NULL; - restore_flags (flags); /* all CPUs (overkill?) */ + spin_unlock_irqrestore(&tape->spinlock, flags); MOD_DEC_USE_COUNT; - ide_unregister_subdriver (drive); + ata_unregister_device(drive); drive->driver_data = NULL; devfs_unregister (tape->de_r); devfs_unregister (tape->de_n); @@ -5992,11 +5610,11 @@ static void idetape_attach(struct ata_device *drive) } tape = (idetape_tape_t *) kmalloc (sizeof (idetape_tape_t), GFP_KERNEL); if (!tape) { - printk (KERN_ERR "ide-tape: %s: Can't allocate a tape structure\n", drive->name); + printk(KERN_ERR "ide-tape: %s: Can't allocate a tape structure\n", drive->name); return; } - if (ide_register_subdriver (drive, &idetape_driver)) { - printk (KERN_ERR "ide-tape: %s: Failed to register the driver with ide.c\n", drive->name); + if (ata_register_device(drive, &idetape_driver)) { + printk(KERN_ERR "ide-tape: %s: Failed to register the driver with ide.c\n", drive->name); kfree (tape); return; } diff --git a/drivers/ide/ioctl.c b/drivers/ide/ioctl.c index d1b5f6f8d4ad..5ab0adcdcac6 100644 --- a/drivers/ide/ioctl.c +++ b/drivers/ide/ioctl.c @@ -33,6 +33,15 @@ #include "ioctl.h" + +/* BIG GEOMETRY - dying, used only by HDIO_GETGEO_BIG_RAW */ +struct hd_big_geometry { + u8 heads; + u8 sectors; + u32 cylinders; + unsigned long start; +}; + /* * Implement generic ioctls invoked from userspace to imlpement specific * functionality. diff --git a/drivers/ide/it8172.c b/drivers/ide/it8172.c index 838718764c4f..cc38ee5d8843 100644 --- a/drivers/ide/it8172.c +++ b/drivers/ide/it8172.c @@ -89,10 +89,7 @@ static void it8172_tune_drive (struct ata_device *drive, u8 pio) drive_enables |= 0x0006; } - save_flags(flags); - cli(); pci_write_config_word(dev, master_port, master_data); - restore_flags(flags); } #if defined(CONFIG_BLK_DEV_IDEDMA) && defined(CONFIG_IT8172_TUNING) diff --git a/drivers/ide/main.c b/drivers/ide/main.c index 50bc8732e38b..5649e68fb97e 100644 --- a/drivers/ide/main.c +++ b/drivers/ide/main.c @@ -191,7 +191,11 @@ static void init_hwif_data(struct ata_channel *ch, unsigned int index) ch->noprobe = !ch->io_ports[IDE_DATA_OFFSET]; #ifdef CONFIG_BLK_DEV_HD - if (ch->io_ports[IDE_DATA_OFFSET] == HD_DATA) + + /* Ignore disks for which handling by the legacy driver was requested + * by the used. + */ + if (ch->io_ports[IDE_DATA_OFFSET] == 0x1f0) ch->noprobe = 1; /* may be overridden by ide_setup() */ #endif @@ -361,7 +365,7 @@ void ide_unregister(struct ata_channel *ch) if (ata_ops(drive)->cleanup(drive)) goto abort; } else - ide_unregister_subdriver(drive); + ata_unregister_device(drive); } } ch->present = 0; @@ -701,79 +705,46 @@ static void __init init_global_data(void) /* * This gets called VERY EARLY during initialization, to handle kernel "command - * line" strings beginning with "hdx=" or "ide".It gets called even before the - * actual module gets initialized. + * line" strings beginning with "hdx=". It gets called even before the actual + * module gets initialized. * * Please look at Documentation/ide.txt to see the complete list of supported * options. */ -int __init ide_setup(char *s) +static int __init ata_hd_setup(char *s) { - int i, vals[4]; - struct ata_channel *ch; + int vals[4]; + struct ata_channel *ch; /* FIXME: Channel parms should not be accessed in ata_hd_setup */ struct ata_device *drive; unsigned int hw, unit; const char max_drive = 'a' + ((MAX_HWIFS * MAX_DRIVES) - 1); - const char max_ch = '0' + (MAX_HWIFS - 1); - if (!strncmp(s, "hd=", 3)) /* hd= is for hd.c driver and not us */ + if (s[0] == '=') /* hd= is for hd.c driver and not us */ return 0; - if (strncmp(s,"ide",3) && - strncmp(s,"hd",2)) /* hdx= & hdxlun= */ - return 0; - - printk(KERN_INFO "ide_setup: %s", s); + printk(KERN_INFO "hd%s", s); init_global_data(); -#ifdef CONFIG_BLK_DEV_IDEDOUBLER - if (!strcmp(s, "ide=doubler")) { - extern int ide_doubler; - - printk(KERN_INFO" : Enabled support for IDE doublers\n"); - ide_doubler = 1; - - return 1; - } -#endif - - if (!strcmp(s, "ide=nodma")) { - printk(KERN_INFO "ATA: Prevented DMA\n"); - noautodma = 1; - - return 1; - } - -#ifdef CONFIG_PCI - if (!strcmp(s, "ide=reverse")) { - ide_scan_direction = 1; - printk(" : Enabled support for IDE inverse scan order.\n"); - - return 1; - } -#endif - - /* - * Look for drive options: "hdx=" - */ - if (!strncmp(s, "hd", 2) && s[2] >= 'a' && s[2] <= max_drive) { - const char *hd_words[] = {"none", "noprobe", "nowerr", "cdrom", + if (s[0] >= 'a' && s[0] <= max_drive) { + static const char *hd_words[] = {"none", "noprobe", "nowerr", "cdrom", "serialize", "autotune", "noautotune", "slow", "flash", "remap", "noremap", "scsi", NULL}; - unit = s[2] - 'a'; + unit = s[0] - 'a'; hw = unit / MAX_DRIVES; unit = unit % MAX_DRIVES; ch = &ide_hwifs[hw]; drive = &ch->drives[unit]; - if (!strncmp(s+3, "=ide-", 5)) { - strncpy(drive->driver_req, s + 4, 9); + + /* Look for hdx=ide-* */ + if (!strncmp(s+1, "=ide-", 5)) { + strncpy(drive->driver_req, s+2, 9); goto done; } /* * Look for last lun option: "hdxlun=" */ - if (!strncmp(s+3, "lun=", 4)) { - if (*get_options(s+7, 2, vals) || vals[0]!=1) + if (!strncmp(s+1, "lun=", 4)) { + if (*get_options(s+5, 2, vals) || vals[0]!=1) goto bad_option; if (vals[1] >= 0 && vals[1] <= 7) { drive->last_lun = vals[1]; @@ -782,7 +753,7 @@ int __init ide_setup(char *s) printk(" -- BAD LAST LUN! Expected value from 0 to 7"); goto done; } - switch (match_parm(s+3, hd_words, vals, 3)) { + switch (match_parm(s+1, hd_words, vals, 3)) { case -1: /* "none" */ drive->nobios = 1; /* drop into "noprobe" */ case -2: /* "noprobe" */ @@ -790,16 +761,16 @@ int __init ide_setup(char *s) goto done; case -3: /* "nowerr" */ drive->bad_wstat = BAD_R_STAT; - ch->noprobe = 0; + ch->noprobe = 0; /* FIXME: Channel parm */ goto done; case -4: /* "cdrom" */ drive->present = 1; drive->type = ATA_ROM; - ch->noprobe = 0; + ch->noprobe = 0; /* FIXME: Channel parm */ goto done; case -5: /* "serialize" */ printk(" -- USE \"ide%d=serialize\" INSTEAD", hw); - goto do_serialize; + goto bad_option; case -6: /* "autotune" */ drive->autotune = 1; goto done; @@ -807,7 +778,7 @@ int __init ide_setup(char *s) drive->autotune = 2; goto done; case -8: /* "slow" */ - ch->slow = 1; + ch->slow = 1; /* FIXME: Channel parm */ goto done; case -9: /* "flash" */ drive->ata_flash = 1; @@ -840,11 +811,63 @@ int __init ide_setup(char *s) } } +bad_option: + printk(" -- BAD OPTION\n"); + return 1; + +done: + printk("\n"); + + return 1; +} + +/* + * This gets called VERY EARLY during initialization, to handle kernel "command + * line" strings beginning with "ide". It gets called even before the actual + * module gets initialized. + * + * Please look at Documentation/ide.txt to see the complete list of supported + * options. + */ +int __init ide_setup(char *s) +{ + int i, vals[4]; + struct ata_channel *ch; + unsigned int hw; + const char max_ch = '0' + (MAX_HWIFS - 1); + + printk(KERN_INFO "ide_setup: ide%s", s); + init_global_data(); + +#ifdef CONFIG_BLK_DEV_IDEDOUBLER + if (!strcmp(s, "=doubler")) { + extern int ide_doubler; + + printk(KERN_INFO" : Enabled support for IDE doublers\n"); + ide_doubler = 1; + return 1; + } +#endif + + if (!strcmp(s, "=nodma")) { + printk(KERN_INFO "ATA: Prevented DMA\n"); + noautodma = 1; + return 1; + } + +#ifdef CONFIG_PCI + if (!strcmp(s, "=reverse")) { + ide_scan_direction = 1; + printk(" : Enabled support for IDE inverse scan order.\n"); + return 1; + } +#endif + /* * Look for bus speed option: "idebus=" */ - if (!strncmp(s, "idebus=", 7)) { - if (*get_options(s+7, 2, vals) || vals[0] != 1) + if (!strncmp(s, "bus=", 4)) { + if (*get_options(s+4, 2, vals) || vals[0] != 1) goto bad_option; idebus_parameter = vals[1]; goto done; @@ -853,7 +876,7 @@ int __init ide_setup(char *s) /* * Look for interface options: "idex=" */ - if (!strncmp(s, "ide", 3) && s[3] >= '0' && s[3] <= max_ch) { + if (s[0] >= '0' && s[0] <= max_ch) { /* * Be VERY CAREFUL changing this: note hardcoded indexes below */ @@ -861,11 +884,11 @@ int __init ide_setup(char *s) "noprobe", "serialize", "autotune", "noautotune", "reset", "dma", "ata66", NULL }; const char *ide_words[] = { "qd65xx", "ht6560b", "cmd640_vlb", "dtc2278", "umc8672", "ali14xx", "dc4030", NULL }; - hw = s[3] - '0'; + hw = s[0] - '0'; ch = &ide_hwifs[hw]; - switch (match_parm(s+4, ide_options, vals, 1)) { + switch (match_parm(s+1, ide_options, vals, 1)) { case -7: /* ata66 */ #ifdef CONFIG_PCI ch->udma_four = 1; @@ -889,7 +912,6 @@ int __init ide_setup(char *s) ch->drives[1].autotune = 1; goto done; case -2: /* "serialize" */ - do_serialize: { struct ata_channel *mate; @@ -904,7 +926,10 @@ int __init ide_setup(char *s) goto done; } - i = match_parm(&s[4], ide_words, vals, 3); + /* + * Check for specific chipset name + */ + i = match_parm(s+1, ide_words, vals, 3); /* * Cryptic check to ensure chipset not already set for a channel: @@ -913,7 +938,7 @@ int __init ide_setup(char *s) if (ide_hwifs[hw].chipset != ide_unknown) goto bad_option; /* chipset already specified */ if (i != -7 && hw != 0) - goto bad_channel; /* chipset drivers are for "ide0=" only */ + goto bad_channel; /* chipset drivers are for "ide0=" only */ if (i != -7 && ide_hwifs[1].chipset != ide_unknown) goto bad_option; /* chipset for 2nd port already specified */ printk("\n"); @@ -1012,10 +1037,7 @@ done: /****************************************************************************/ -/* - * This is in fact registering a device not a driver. - */ -int ide_register_subdriver(struct ata_device *drive, struct ata_operations *driver) +int ata_register_device(struct ata_device *drive, struct ata_operations *driver) { unsigned long flags; @@ -1027,12 +1049,9 @@ int ide_register_subdriver(struct ata_device *drive, struct ata_operations *driv return 1; } - /* FIXME: This will be pushed to the drivers! Thus allowing us to - * save one parameter here and to separate this out. - */ drive->driver = driver; - spin_unlock_irqrestore(&ide_lock, flags); + /* Default autotune or requested autotune */ if (drive->autotune != 2) { struct ata_channel *ch = drive->channel; @@ -1046,11 +1065,13 @@ int ide_register_subdriver(struct ata_device *drive, struct ata_operations *driv * PARANOIA!!! */ + spin_lock_irqsave(ch->lock, flags); udma_enable(drive, 0, 0); ch->udma_setup(drive, ch->modes_map); #ifdef CONFIG_BLK_DEV_IDE_TCQ_DEFAULT udma_tcq_enable(drive, 1); #endif + spin_unlock_irqrestore(ch->lock, flags); } /* Only CD-ROMs and tape drives support DSC overlap. But only @@ -1078,13 +1099,8 @@ int ide_register_subdriver(struct ata_device *drive, struct ata_operations *driv * * FIXME: Check whatever we maybe don't call it twice!. */ -int ide_unregister_subdriver(struct ata_device *drive) +int ata_unregister_device(struct ata_device *drive) { -#if 0 - if (__MOD_IN_USE(ata_ops(drive)->owner)) - return 1; -#endif - if (drive->usage || drive->busy || !ata_ops(drive)) return 1; @@ -1156,8 +1172,8 @@ EXPORT_SYMBOL(ide_lock); devfs_handle_t ide_devfs_handle; -EXPORT_SYMBOL(ide_register_subdriver); -EXPORT_SYMBOL(ide_unregister_subdriver); +EXPORT_SYMBOL(ata_register_device); +EXPORT_SYMBOL(ata_unregister_device); EXPORT_SYMBOL(ata_revalidate); EXPORT_SYMBOL(ide_register_hw); EXPORT_SYMBOL(ide_unregister); @@ -1432,8 +1448,14 @@ static int __init init_ata(void) while ((options = next) != NULL) { if ((next = strchr(options,' ')) != NULL) *next++ = 0; - if (!ide_setup(options)) - printk(KERN_ERR "Unknown option '%s'\n", options); + if (!strncmp(options,"hd",2)) { + if (!ata_hd_setup(options+2)) + printk(KERN_ERR "Unknown option '%s'\n", options); + } + else if (!strncmp(options,"ide",3)) { + if (!ide_setup(options+3)) + printk(KERN_ERR "Unknown option '%s'\n", options); + } } } return ata_module_init(); @@ -1457,6 +1479,7 @@ module_exit(cleanup_ata); #ifndef MODULE /* command line option parser */ -__setup("", ide_setup); +__setup("ide", ide_setup); +__setup("hd", ata_hd_setup); #endif diff --git a/drivers/ide/opti621.c b/drivers/ide/opti621.c index c141def6663d..723695b953f3 100644 --- a/drivers/ide/opti621.c +++ b/drivers/ide/opti621.c @@ -244,13 +244,15 @@ static void compute_clocks(int pio, pio_clocks_t *clks) } -/* Main tune procedure, called from tuneproc. */ +/* Main tune procedure, called from tuneproc. + Assumes IRQ's are disabled or at least that no other process will + attempt to access the IDE registers concurrently. +*/ static void opti621_tune_drive(struct ata_device *drive, u8 pio) { /* primary and secondary drives share some registers, * so we have to program both drives */ - unsigned long flags; u8 pio1, pio2; pio_clocks_t first, second; int ax, drdy; @@ -281,9 +283,6 @@ static void opti621_tune_drive(struct ata_device *drive, u8 pio) hwif->name, ax, second.data_time, second.recovery_time, drdy); #endif - save_flags(flags); /* all CPUs */ - cli(); /* all CPUs */ - reg_base = hwif->io_ports[IDE_DATA_OFFSET]; outb(0xc0, reg_base+CNTRL_REG); /* allow Register-B */ outb(0xff, reg_base+5); /* hmm, setupvic.exe does this ;-) */ @@ -306,8 +305,6 @@ static void opti621_tune_drive(struct ata_device *drive, u8 pio) write_reg(misc, MISC_REG); /* set address setup, DRDY timings, */ /* and read prefetch for both drives */ - - restore_flags(flags); /* all CPUs */ } /* diff --git a/drivers/ide/probe.c b/drivers/ide/probe.c index 3766b7531c78..f6adc59bb0b5 100644 --- a/drivers/ide/probe.c +++ b/drivers/ide/probe.c @@ -1082,7 +1082,12 @@ static void channel_init(struct ata_channel *ch) } } #ifdef CONFIG_BLK_DEV_HD - if (ch->irq == HD_IRQ && ch->io_ports[IDE_DATA_OFFSET] != HD_DATA) { + + /* The first "legacy" HD gets distinguished by the IRQ it is attached + * to and the IO port it takes. + */ + + if (ch->irq == 14 && ch->io_ports[IDE_DATA_OFFSET] != 0x1f0) { printk("%s: CANNOT SHARE IRQ WITH OLD HARDDISK DRIVER (hd.c)\n", ch->name); return; diff --git a/drivers/ide/qd65xx.c b/drivers/ide/qd65xx.c index 633a75950d60..3ed266424233 100644 --- a/drivers/ide/qd65xx.c +++ b/drivers/ide/qd65xx.c @@ -1,8 +1,6 @@ /* * Copyright (C) 1996-2001 Linus Torvalds & author (see below) - */ - -/* + * * Version 0.03 Cleaned auto-tune, added probe * Version 0.04 Added second channel tuning * Version 0.05 Enhanced tuning ; added qd6500 support @@ -81,36 +79,12 @@ * bit 5 : status, but of what ? * bit 6 : always set 1 by dos driver * bit 7 : set 1 for non-ATAPI devices on primary port - * (maybe read-ahead and post-write buffer ?) + * (maybe read-ahead and post-write buffer ?) */ static int timings[4]={-1,-1,-1,-1}; /* stores current timing for each timer */ -static void qd_write_reg(u8 content, unsigned int reg) -{ - unsigned long flags; - - save_flags(flags); /* all CPUs */ - cli(); /* all CPUs */ - outb(content,reg); - restore_flags(flags); /* all CPUs */ -} - -static u8 __init qd_read_reg(unsigned int reg) -{ - unsigned long flags; - u8 read; - - save_flags(flags); /* all CPUs */ - cli(); /* all CPUs */ - read = inb(reg); - restore_flags(flags); /* all CPUs */ - return read; -} - /* - * qd_select: - * * This routine is invoked from ide.c to prepare for access to a given drive. */ @@ -120,12 +94,10 @@ static void qd_select(struct ata_device *drive) (QD_TIMREG(drive) & 0x02); if (timings[index] != QD_TIMING(drive)) - qd_write_reg(timings[index] = QD_TIMING(drive), QD_TIMREG(drive)); + outb(timings[index] = QD_TIMING(drive), QD_TIMREG(drive)); } /* - * qd6500_compute_timing - * * computes the timing value where * lower nibble represents active time, in count of VLB clocks * upper nibble represents recovery time, in count of VLB clocks @@ -147,8 +119,6 @@ static u8 qd6500_compute_timing(struct ata_channel *hwif, int active_time, int r } /* - * qd6580_compute_timing - * * idem for qd6580 */ @@ -161,8 +131,6 @@ static u8 qd6580_compute_timing(int active_time, int recovery_time) } /* - * qd_find_disk_type - * * tries to find timing from dos driver's table */ @@ -187,8 +155,6 @@ static int qd_find_disk_type(struct ata_device *drive, } /* - * qd_timing_ok: - * * check whether timings don't conflict */ @@ -201,8 +167,6 @@ static int qd_timing_ok(struct ata_device drives[]) } /* - * qd_set_timing: - * * records the timing, and enables selectproc as needed */ @@ -221,10 +185,6 @@ static void qd_set_timing(struct ata_device *drive, u8 timing) printk(KERN_DEBUG "%s: %#x\n", drive->name, timing); } -/* - * qd6500_tune_drive - */ - static void qd6500_tune_drive(struct ata_device *drive, u8 pio) { int active_time = 175; @@ -242,10 +202,6 @@ static void qd6500_tune_drive(struct ata_device *drive, u8 pio) qd_set_timing(drive, qd6500_compute_timing(drive->channel, active_time, recovery_time)); } -/* - * qd6580_tune_drive - */ - static void qd6580_tune_drive(struct ata_device *drive, u8 pio) { struct ata_timing *t; @@ -291,7 +247,7 @@ static void qd6580_tune_drive(struct ata_device *drive, u8 pio) } if (!drive->channel->unit && drive->type != ATA_DISK) { - qd_write_reg(0x5f, QD_CONTROL_PORT); + outb(0x5f, QD_CONTROL_PORT); printk(KERN_WARNING "%s: ATAPI: disabled read-ahead FIFO and post-write buffer on %s.\n", drive->name, drive->channel->name); } @@ -299,8 +255,6 @@ static void qd6580_tune_drive(struct ata_device *drive, u8 pio) } /* - * qd_testreg - * * tests if the given port is a register */ @@ -329,8 +283,6 @@ static int __init qd_testreg(int port) } /* - * qd_setup: - * * called to setup an ata channel : adjusts attributes & links for tuning */ @@ -349,8 +301,6 @@ void __init qd_setup(int unit, int base, int config, unsigned int data0, unsigne } /* - * qd_unsetup: - * * called to unsetup an ata channel : back to default values, unlinks tuning */ void __init qd_unsetup(int unit) { @@ -368,13 +318,13 @@ void __init qd_unsetup(int unit) { if (tuneproc == (void *) qd6500_tune_drive) { // will do it for both - qd_write_reg(QD6500_DEF_DATA, QD_TIMREG(&hwif->drives[0])); + outb(QD6500_DEF_DATA, QD_TIMREG(&hwif->drives[0])); } else if (tuneproc == (void *) qd6580_tune_drive) { if (QD_CONTROL(hwif) & QD_CONTR_SEC_DISABLED) { - qd_write_reg(QD6580_DEF_DATA, QD_TIMREG(&hwif->drives[0])); - qd_write_reg(QD6580_DEF_DATA2, QD_TIMREG(&hwif->drives[1])); + outb(QD6580_DEF_DATA, QD_TIMREG(&hwif->drives[0])); + outb(QD6580_DEF_DATA2, QD_TIMREG(&hwif->drives[1])); } else { - qd_write_reg(unit?QD6580_DEF_DATA2:QD6580_DEF_DATA, QD_TIMREG(&hwif->drives[0])); + outb(unit ? QD6580_DEF_DATA2 : QD6580_DEF_DATA, QD_TIMREG(&hwif->drives[0])); } } else { printk(KERN_WARNING "Unknown qd65xx tuning fonction !\n"); @@ -383,8 +333,6 @@ void __init qd_unsetup(int unit) { } /* - * qd_probe: - * * looks at the specified baseport, and if qd found, registers & initialises it * return 1 if another qd may be probed */ @@ -394,7 +342,7 @@ int __init qd_probe(int base) u8 config; int unit; - config = qd_read_reg(QD_CONFIG_PORT); + config = inb(QD_CONFIG_PORT); if (! ((config & QD_CONFIG_BASEPORT) >> 1 == (base == 0xb0)) ) return 1; @@ -425,7 +373,7 @@ int __init qd_probe(int base) /* qd6580 found */ - control = qd_read_reg(QD_CONTROL_PORT); + control = inb(QD_CONTROL_PORT); printk(KERN_NOTICE "qd6580 at %#x\n", base); printk(KERN_DEBUG "qd6580: config=%#x, control=%#x, ID3=%u\n", config, control, QD_ID3); @@ -434,7 +382,7 @@ int __init qd_probe(int base) /* secondary disabled */ printk(KERN_INFO "%s: qd6580: single IDE board\n", ide_hwifs[unit].name); qd_setup(unit, base, config | (control << 8), QD6580_DEF_DATA, QD6580_DEF_DATA2, &qd6580_tune_drive); - qd_write_reg(QD_DEF_CONTR, QD_CONTROL_PORT); + outb(QD_DEF_CONTR, QD_CONTROL_PORT); return 1; } else { @@ -443,7 +391,7 @@ int __init qd_probe(int base) qd_setup(ATA_PRIMARY, base, config | (control << 8), QD6580_DEF_DATA, QD6580_DEF_DATA, &qd6580_tune_drive); qd_setup(ATA_SECONDARY, base, config | (control << 8), QD6580_DEF_DATA2, QD6580_DEF_DATA2, &qd6580_tune_drive); - qd_write_reg(QD_DEF_CONTR, QD_CONTROL_PORT); + outb(QD_DEF_CONTR, QD_CONTROL_PORT); return 0; /* no other qd65xx possible */ } @@ -454,8 +402,6 @@ int __init qd_probe(int base) #ifndef MODULE /* - * init_qd65xx: - * * called by ide.c when parsing command line */ diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c index f05c5f37b1ed..fac559f73abe 100644 --- a/drivers/scsi/ide-scsi.c +++ b/drivers/scsi/ide-scsi.c @@ -1,33 +1,12 @@ /* * Copyright (C) 1996 - 1999 Gadi Oxman <gadio@netvision.net.il> - */ -/* + * * Emulation of a SCSI host adapter for IDE ATAPI devices. * * With this driver, one can use the Linux SCSI drivers instead of the * native IDE ATAPI drivers. - * - * Ver 0.1 Dec 3 96 Initial version. - * Ver 0.2 Jan 26 97 Fixed bug in cleanup_module() and added emulation - * of MODE_SENSE_6/MODE_SELECT_6 for cdroms. Thanks - * to Janos Farkas for pointing this out. - * Avoid using bitfields in structures for m68k. - * Added Scatter/Gather and DMA support. - * Ver 0.4 Dec 7 97 Add support for ATAPI PD/CD drives. - * Use variable timeout for each command. - * Ver 0.5 Jan 2 98 Fix previous PD/CD support. - * Allow disabling of SCSI-6 to SCSI-10 transformation. - * Ver 0.6 Jan 27 98 Allow disabling of SCSI command translation layer - * for access through /dev/sg. - * Fix MODE_SENSE_6/MODE_SELECT_6/INQUIRY translation. - * Ver 0.7 Dec 04 98 Ignore commands where lun != 0 to avoid multiple - * detection of devices with CONFIG_SCSI_MULTI_LUN - * Ver 0.8 Feb 05 99 Optical media need translation too. Reverse 0.7. - * Ver 0.9 Jul 04 99 Fix a bug in SG_SET_TRANSFORM. */ -#define IDESCSI_VERSION "0.9" - #include <linux/module.h> #include <linux/types.h> #include <linux/string.h> @@ -495,9 +474,8 @@ static void idescsi_release(struct inode *inode, struct file *filp, struct ata_d static Scsi_Host_Template template; static int idescsi_cleanup (struct ata_device *drive) { - if (ide_unregister_subdriver (drive)) { + if (ata_unregister_device(drive)) return 1; - } scsi_unregister_host(&template); return 0; @@ -762,7 +740,7 @@ static void idescsi_attach(struct ata_device *drive) host = scsi_register(&template, sizeof(idescsi_scsi_t)); if (!host) { - printk (KERN_ERR + printk(KERN_ERR "ide-scsi: %s: Can't allocate a scsi host structure\n", drive->name); return; @@ -771,8 +749,8 @@ static void idescsi_attach(struct ata_device *drive) host->max_lun = drive->last_lun + 1; host->max_id = 1; - if (ide_register_subdriver(drive, &ata_ops)) { - printk (KERN_ERR "ide-scsi: %s: Failed to register the driver with ide.c\n", drive->name); + if (ata_register_device(drive, &ata_ops)) { + printk(KERN_ERR "ide-scsi: %s: Failed to register the driver with ide.c\n", drive->name); scsi_unregister(host); return; } diff --git a/drivers/usb/storage/freecom.c b/drivers/usb/storage/freecom.c index a5a2d59be9ca..c8d70991ae3a 100644 --- a/drivers/usb/storage/freecom.c +++ b/drivers/usb/storage/freecom.c @@ -40,43 +40,47 @@ static void pdump (void *, int); #endif +/* Bits of HD_STATUS */ +#define ERR_STAT 0x01 +#define DRQ_STAT 0x08 + struct freecom_udata { - __u8 buffer[64]; /* Common command block. */ + u8 buffer[64]; /* Common command block. */ }; typedef struct freecom_udata *freecom_udata_t; /* All of the outgoing packets are 64 bytes long. */ struct freecom_cb_wrap { - __u8 Type; /* Command type. */ - __u8 Timeout; /* Timeout in seconds. */ - __u8 Atapi[12]; /* An ATAPI packet. */ - __u8 Filler[50]; /* Padding Data. */ + u8 Type; /* Command type. */ + u8 Timeout; /* Timeout in seconds. */ + u8 Atapi[12]; /* An ATAPI packet. */ + u8 Filler[50]; /* Padding Data. */ }; struct freecom_xfer_wrap { - __u8 Type; /* Command type. */ - __u8 Timeout; /* Timeout in seconds. */ - __u32 Count; /* Number of bytes to transfer. */ - __u8 Pad[58]; + u8 Type; /* Command type. */ + u8 Timeout; /* Timeout in seconds. */ + u32 Count; /* Number of bytes to transfer. */ + u8 Pad[58]; } __attribute__ ((packed)); struct freecom_ide_out { - __u8 Type; /* Type + IDE register. */ - __u8 Pad; - __u16 Value; /* Value to write. */ - __u8 Pad2[60]; + u8 Type; /* Type + IDE register. */ + u8 Pad; + u16 Value; /* Value to write. */ + u8 Pad2[60]; }; struct freecom_ide_in { - __u8 Type; /* Type | IDE register. */ - __u8 Pad[63]; + u8 Type; /* Type | IDE register. */ + u8 Pad[63]; }; struct freecom_status { - __u8 Status; - __u8 Reason; - __u16 Count; - __u8 Pad[60]; + u8 Status; + u8 Reason; + u16 Count; + u8 Pad[60]; }; /* Freecom stuffs the interrupt status in the INDEX_STAT bit of the ide diff --git a/include/linux/hdreg.h b/include/linux/hdreg.h index dcedacb849ea..5ed104e84e43 100644 --- a/include/linux/hdreg.h +++ b/include/linux/hdreg.h @@ -2,279 +2,18 @@ #define _LINUX_HDREG_H /* - * This file contains some defines for the AT-hd-controller. - * Various sources. - */ - -#define HD_IRQ 14 /* the standard disk interrupt */ - -/* ide.c has its own port definitions in "ide.h" */ - -/* Hd controller regs. Ref: IBM AT Bios-listing */ -#define HD_DATA 0x1f0 /* _CTL when writing */ -#define HD_ERROR 0x1f1 /* see err-bits */ -#define HD_NSECTOR 0x1f2 /* nr of sectors to read/write */ -#define HD_SECTOR 0x1f3 /* starting sector */ -#define HD_LCYL 0x1f4 /* starting cylinder */ -#define HD_HCYL 0x1f5 /* high byte of starting cyl */ -#define HD_CURRENT 0x1f6 /* 101dhhhh , d=drive, hhhh=head */ -#define HD_STATUS 0x1f7 /* see status-bits */ -#define HD_FEATURE HD_ERROR /* same io address, read=error, write=feature */ -#define HD_PRECOMP HD_FEATURE /* obsolete use of this port - predates IDE */ -#define HD_COMMAND HD_STATUS /* same io address, read=status, write=cmd */ - -#define HD_CMD 0x3f6 /* used for resets */ -#define HD_ALTSTATUS 0x3f6 /* same as HD_STATUS but doesn't clear irq */ - -/* remainder is shared between hd.c, ide.c, ide-cd.c, and the hdparm utility */ - -/* Bits of HD_STATUS */ -#define ERR_STAT 0x01 -#define INDEX_STAT 0x02 -#define ECC_STAT 0x04 /* Corrected error */ -#define DRQ_STAT 0x08 -#define SEEK_STAT 0x10 -#define SERVICE_STAT SEEK_STAT -#define WRERR_STAT 0x20 -#define READY_STAT 0x40 -#define BUSY_STAT 0x80 - -/* Bits for HD_ERROR */ -#define MARK_ERR 0x01 /* Bad address mark */ -#define TRK0_ERR 0x02 /* couldn't find track 0 */ -#define ABRT_ERR 0x04 /* Command aborted */ -#define MCR_ERR 0x08 /* media change request */ -#define ID_ERR 0x10 /* ID field not found */ -#define MC_ERR 0x20 /* media changed */ -#define ECC_ERR 0x40 /* Uncorrectable ECC error */ -#define BBD_ERR 0x80 /* pre-EIDE meaning: block marked bad */ -#define ICRC_ERR 0x80 /* new meaning: CRC error during transfer */ - -/* - * sector count bits - */ -#define NSEC_CD 0x01 -#define NSEC_IO 0x02 -#define NSEC_REL 0x04 - -/* * Command Header sizes for IOCTL commands */ - #define HDIO_DRIVE_CMD_HDR_SIZE (4 * sizeof(u8)) #define HDIO_DRIVE_HOB_HDR_SIZE (8 * sizeof(u8)) -#define IDE_DRIVE_TASK_INVALID -1 -#define IDE_DRIVE_TASK_NO_DATA 0 -#define IDE_DRIVE_TASK_SET_XFER 1 - -#define IDE_DRIVE_TASK_IN 2 - -#define IDE_DRIVE_TASK_OUT 3 -#define IDE_DRIVE_TASK_RAW_WRITE 4 - -struct hd_drive_task_hdr { - u8 feature; - u8 sector_count; - u8 sector_number; - u8 low_cylinder; - u8 high_cylinder; - u8 device_head; -} __attribute__((packed)); - -/* - * Define standard taskfile in/out register - */ -#define IDE_TASKFILE_STD_OUT_FLAGS 0xFE -#define IDE_TASKFILE_STD_IN_FLAGS 0xFE -#define IDE_HOB_STD_OUT_FLAGS 0xC0 -#define IDE_HOB_STD_IN_FLAGS 0xC0 - -#define TASKFILE_INVALID 0x7fff -#define TASKFILE_48 0x8000 - -#define TASKFILE_NO_DATA 0x0000 - -#define TASKFILE_IN 0x0001 -#define TASKFILE_MULTI_IN 0x0002 - -#define TASKFILE_OUT 0x0004 -#define TASKFILE_MULTI_OUT 0x0008 -#define TASKFILE_IN_OUT 0x0010 - -#define TASKFILE_IN_DMA 0x0020 -#define TASKFILE_OUT_DMA 0x0040 -#define TASKFILE_IN_DMAQ 0x0080 -#define TASKFILE_OUT_DMAQ 0x0100 - -#define TASKFILE_P_IN 0x0200 -#define TASKFILE_P_OUT 0x0400 -#define TASKFILE_P_IN_DMA 0x0800 -#define TASKFILE_P_OUT_DMA 0x1000 -#define TASKFILE_P_IN_DMAQ 0x2000 -#define TASKFILE_P_OUT_DMAQ 0x4000 - -/* ATA/ATAPI Commands pre T13 Spec */ -#define WIN_NOP 0x00 -#define CFA_REQ_EXT_ERROR_CODE 0x03 /* CFA Request Extended Error Code */ -#define WIN_SRST 0x08 /* ATAPI soft reset command */ -#define WIN_DEVICE_RESET 0x08 -#define WIN_RESTORE 0x10 -#define WIN_READ 0x20 /* 28-Bit */ -#define WIN_READ_EXT 0x24 /* 48-Bit */ -#define WIN_READDMA_EXT 0x25 /* 48-Bit */ -#define WIN_READDMA_QUEUED_EXT 0x26 /* 48-Bit */ -#define WIN_READ_NATIVE_MAX_EXT 0x27 /* 48-Bit */ -#define WIN_MULTREAD_EXT 0x29 /* 48-Bit */ -#define WIN_WRITE 0x30 /* 28-Bit */ -#define WIN_WRITE_EXT 0x34 /* 48-Bit */ -#define WIN_WRITEDMA_EXT 0x35 /* 48-Bit */ -#define WIN_WRITEDMA_QUEUED_EXT 0x36 /* 48-Bit */ -#define WIN_SET_MAX_EXT 0x37 /* 48-Bit */ -#define CFA_WRITE_SECT_WO_ERASE 0x38 /* CFA Write Sectors without erase */ -#define WIN_MULTWRITE_EXT 0x39 /* 48-Bit */ -#define WIN_WRITE_VERIFY 0x3C /* 28-Bit */ -#define WIN_VERIFY 0x40 /* 28-Bit - Read Verify Sectors */ -#define WIN_VERIFY_EXT 0x42 /* 48-Bit */ -#define WIN_FORMAT 0x50 -#define WIN_INIT 0x60 -#define WIN_SEEK 0x70 -#define CFA_TRANSLATE_SECTOR 0x87 /* CFA Translate Sector */ -#define WIN_DIAGNOSE 0x90 -#define WIN_SPECIFY 0x91 /* set drive geometry translation */ -#define WIN_DOWNLOAD_MICROCODE 0x92 -#define WIN_STANDBYNOW2 0x94 -#define WIN_SETIDLE2 0x97 -#define WIN_CHECKPOWERMODE2 0x98 -#define WIN_SLEEPNOW2 0x99 -#define WIN_PACKETCMD 0xA0 /* Send a packet command. */ -#define WIN_PIDENTIFY 0xA1 /* identify ATAPI device */ -#define WIN_QUEUED_SERVICE 0xA2 -#define WIN_SMART 0xB0 /* self-monitoring and reporting */ -#define CFA_ERASE_SECTORS 0xC0 -#define WIN_MULTREAD 0xC4 /* read sectors using multiple mode*/ -#define WIN_MULTWRITE 0xC5 /* write sectors using multiple mode */ -#define WIN_SETMULT 0xC6 /* enable/disable multiple mode */ -#define WIN_READDMA_QUEUED 0xC7 /* read sectors using Queued DMA transfers */ -#define WIN_READDMA 0xC8 /* read sectors using DMA transfers */ -#define WIN_WRITEDMA 0xCA /* write sectors using DMA transfers */ -#define WIN_WRITEDMA_QUEUED 0xCC /* write sectors using Queued DMA transfers */ -#define CFA_WRITE_MULTI_WO_ERASE 0xCD /* CFA Write multiple without erase */ -#define WIN_GETMEDIASTATUS 0xDA -#define WIN_DOORLOCK 0xDE /* lock door on removable drives */ -#define WIN_DOORUNLOCK 0xDF /* unlock door on removable drives */ -#define WIN_STANDBYNOW1 0xE0 -#define WIN_IDLEIMMEDIATE 0xE1 /* force drive to become "ready" */ -#define WIN_STANDBY 0xE2 /* Set device in Standby Mode */ -#define WIN_SETIDLE1 0xE3 -#define WIN_READ_BUFFER 0xE4 /* force read only 1 sector */ -#define WIN_CHECKPOWERMODE1 0xE5 -#define WIN_SLEEPNOW1 0xE6 -#define WIN_FLUSH_CACHE 0xE7 -#define WIN_WRITE_BUFFER 0xE8 /* force write only 1 sector */ -#define WIN_FLUSH_CACHE_EXT 0xEA /* 48-Bit */ -#define WIN_IDENTIFY 0xEC /* ask drive to identify itself */ -#define WIN_MEDIAEJECT 0xED -#define WIN_IDENTIFY_DMA 0xEE /* same as WIN_IDENTIFY, but DMA */ -#define WIN_SETFEATURES 0xEF /* set special drive features */ -#define EXABYTE_ENABLE_NEST 0xF0 -#define WIN_SECURITY_SET_PASS 0xF1 -#define WIN_SECURITY_UNLOCK 0xF2 -#define WIN_SECURITY_ERASE_PREPARE 0xF3 -#define WIN_SECURITY_ERASE_UNIT 0xF4 -#define WIN_SECURITY_FREEZE_LOCK 0xF5 -#define WIN_SECURITY_DISABLE 0xF6 -#define WIN_READ_NATIVE_MAX 0xF8 /* return the native maximum address */ -#define WIN_SET_MAX 0xF9 -#define DISABLE_SEAGATE 0xFB - -/* WIN_SMART sub-commands */ - -#define SMART_READ_VALUES 0xD0 -#define SMART_READ_THRESHOLDS 0xD1 -#define SMART_AUTOSAVE 0xD2 -#define SMART_SAVE 0xD3 -#define SMART_IMMEDIATE_OFFLINE 0xD4 -#define SMART_READ_LOG_SECTOR 0xD5 -#define SMART_WRITE_LOG_SECTOR 0xD6 -#define SMART_WRITE_THRESHOLDS 0xD7 -#define SMART_ENABLE 0xD8 -#define SMART_DISABLE 0xD9 -#define SMART_STATUS 0xDA -#define SMART_AUTO_OFFLINE 0xDB - -/* Password used in TF4 & TF5 executing SMART commands */ - -#define SMART_LCYL_PASS 0x4F -#define SMART_HCYL_PASS 0xC2 - -/* WIN_SETFEATURES sub-commands */ - -#define SETFEATURES_EN_WCACHE 0x02 /* Enable write cache */ -#define SETFEATURES_XFER 0x03 /* Set transfer mode */ -# define XFER_UDMA_7 0x47 /* 0100|0111 */ -# define XFER_UDMA_6 0x46 /* 0100|0110 */ -# define XFER_UDMA_5 0x45 /* 0100|0101 */ -# define XFER_UDMA_4 0x44 /* 0100|0100 */ -# define XFER_UDMA_3 0x43 /* 0100|0011 */ -# define XFER_UDMA_2 0x42 /* 0100|0010 */ -# define XFER_UDMA_1 0x41 /* 0100|0001 */ -# define XFER_UDMA_0 0x40 /* 0100|0000 */ -# define XFER_MW_DMA_2 0x22 /* 0010|0010 */ -# define XFER_MW_DMA_1 0x21 /* 0010|0001 */ -# define XFER_MW_DMA_0 0x20 /* 0010|0000 */ -# define XFER_SW_DMA_2 0x12 /* 0001|0010 */ -# define XFER_SW_DMA_1 0x11 /* 0001|0001 */ -# define XFER_SW_DMA_0 0x10 /* 0001|0000 */ -# define XFER_PIO_4 0x0C /* 0000|1100 */ -# define XFER_PIO_3 0x0B /* 0000|1011 */ -# define XFER_PIO_2 0x0A /* 0000|1010 */ -# define XFER_PIO_1 0x09 /* 0000|1001 */ -# define XFER_PIO_0 0x08 /* 0000|1000 */ -# define XFER_PIO_SLOW 0x00 /* 0000|0000 */ -#define SETFEATURES_DIS_DEFECT 0x04 /* Disable Defect Management */ -#define SETFEATURES_EN_APM 0x05 /* Enable advanced power management */ -#define SETFEATURES_DIS_MSN 0x31 /* Disable Media Status Notification */ -#define SETFEATURES_EN_AAM 0x42 /* Enable Automatic Acoustic Management */ -#define SETFEATURES_DIS_RLA 0x55 /* Disable read look-ahead feature */ -#define SETFEATURES_EN_RI 0x5D /* Enable release interrupt */ -#define SETFEATURES_EN_SI 0x5E /* Enable SERVICE interrupt */ -#define SETFEATURES_DIS_RPOD 0x66 /* Disable reverting to power on defaults */ -#define SETFEATURES_DIS_WCACHE 0x82 /* Disable write cache */ -#define SETFEATURES_EN_DEFECT 0x84 /* Enable Defect Management */ -#define SETFEATURES_DIS_APM 0x85 /* Disable advanced power management */ -#define SETFEATURES_EN_MSN 0x95 /* Enable Media Status Notification */ -#define SETFEATURES_EN_RLA 0xAA /* Enable read look-ahead feature */ -#define SETFEATURES_PREFETCH 0xAB /* Sets drive prefetch value */ -#define SETFEATURES_DIS_AAM 0xC2 /* Disable Automatic Acoustic Management */ -#define SETFEATURES_EN_RPOD 0xCC /* Enable reverting to power on defaults */ -#define SETFEATURES_DIS_RI 0xDD /* Disable release interrupt */ -#define SETFEATURES_DIS_SI 0xDE /* Disable SERVICE interrupt */ - -/* WIN_SECURITY sub-commands */ - -#define SECURITY_SET_PASSWORD 0xBA -#define SECURITY_UNLOCK 0xBB -#define SECURITY_ERASE_PREPARE 0xBC -#define SECURITY_ERASE_UNIT 0xBD -#define SECURITY_FREEZE_LOCK 0xBE -#define SECURITY_DISABLE_PASSWORD 0xBF - struct hd_geometry { - u8 heads; - u8 sectors; - u16 cylinders; + __u8 heads; + __u8 sectors; + __u16 cylinders; unsigned long start; }; -/* BIG GEOMETRY - dying, used only by HDIO_GETGEO_BIG_RAW */ -struct hd_big_geometry { - u8 heads; - u8 sectors; - u32 cylinders; - unsigned long start; -}; - /* hd/ide ctl's that pass (arg) ptrs to user space are numbered 0x030n/0x031n */ #define HDIO_GETGEO 0x0301 /* get device geometry */ #define HDIO_GET_UNMASKINTR 0x0302 /* get current unmask setting */ @@ -306,263 +45,8 @@ struct hd_big_geometry { #define HDIO_SET_QDMA 0x032e /* change use-qdma flag */ #define HDIO_SET_ADDRESS 0x032f /* change lba addressing modes */ -/* bus states */ -enum { - BUSSTATE_OFF = 0, - BUSSTATE_ON, - BUSSTATE_TRISTATE -}; - /* hd/ide ctl's that pass (arg) ptrs to user space are numbered 0x033n/0x033n */ /* 0x330 is reserved - used to be HDIO_GETGEO_BIG */ #define HDIO_GETGEO_BIG_RAW 0x0331 /* */ -#define __NEW_HD_DRIVE_ID - -/* - * Structure returned by HDIO_GET_IDENTITY, as per ANSI NCITS ATA6 rev.1b spec. - * - * If you change something here, please remember to update fix_driveid() in - * ide/probe.c. - */ -struct hd_driveid { - u16 config; /* lots of obsolete bit flags */ - u16 cyls; /* Obsolete, "physical" cyls */ - u16 reserved2; /* reserved (word 2) */ - u16 heads; /* Obsolete, "physical" heads */ - u16 track_bytes; /* unformatted bytes per track */ - u16 sector_bytes; /* unformatted bytes per sector */ - u16 sectors; /* Obsolete, "physical" sectors per track */ - u16 vendor0; /* vendor unique */ - u16 vendor1; /* vendor unique */ - u16 vendor2; /* Retired vendor unique */ - u8 serial_no[20]; /* 0 = not_specified */ - u16 buf_type; /* Retired */ - u16 buf_size; /* Retired, 512 byte increments - * 0 = not_specified - */ - u16 ecc_bytes; /* for r/w long cmds; 0 = not_specified */ - u8 fw_rev[8]; /* 0 = not_specified */ - char model[40]; /* 0 = not_specified */ - u8 max_multsect; /* 0=not_implemented */ - u8 vendor3; /* vendor unique */ - u16 dword_io; /* 0=not_implemented; 1=implemented */ - u8 vendor4; /* vendor unique */ - u8 capability; /* (upper byte of word 49) - * 3: IORDYsup - * 2: IORDYsw - * 1: LBA - * 0: DMA - */ - u16 reserved50; /* reserved (word 50) */ - u8 vendor5; /* Obsolete, vendor unique */ - u8 tPIO; /* Obsolete, 0=slow, 1=medium, 2=fast */ - u8 vendor6; /* Obsolete, vendor unique */ - u8 tDMA; /* Obsolete, 0=slow, 1=medium, 2=fast */ - u16 field_valid; /* (word 53) - * 2: ultra_ok word 88 - * 1: eide_ok words 64-70 - * 0: cur_ok words 54-58 - */ - u16 cur_cyls; /* Obsolete, logical cylinders */ - u16 cur_heads; /* Obsolete, l heads */ - u16 cur_sectors; /* Obsolete, l sectors per track */ - u16 cur_capacity0; /* Obsolete, l total sectors on drive */ - u16 cur_capacity1; /* Obsolete, (2 words, misaligned int) */ - u8 multsect; /* current multiple sector count */ - u8 multsect_valid; /* when (bit0==1) multsect is ok */ - u32 lba_capacity; /* Obsolete, total number of sectors */ - u16 dma_1word; /* Obsolete, single-word dma info */ - u16 dma_mword; /* multiple-word dma info */ - u16 eide_pio_modes; /* bits 0:mode3 1:mode4 */ - u16 eide_dma_min; /* min mword dma cycle time (ns) */ - u16 eide_dma_time; /* recommended mword dma cycle time (ns) */ - u16 eide_pio; /* min cycle time (ns), no IORDY */ - u16 eide_pio_iordy; /* min cycle time (ns), with IORDY */ - u16 words69_70[2]; /* reserved words 69-70 - * future command overlap and queuing - */ - /* HDIO_GET_IDENTITY currently returns only words 0 through 70 */ - u16 words71_74[4]; /* reserved words 71-74 - * for IDENTIFY PACKET DEVICE command - */ - u16 queue_depth; /* (word 75) - * 15:5 reserved - * 4:0 Maximum queue depth -1 - */ - u16 words76_79[4]; /* reserved words 76-79 */ - u16 major_rev_num; /* (word 80) */ - u16 minor_rev_num; /* (word 81) */ - u16 command_set_1; /* (word 82) supported - * 15: Obsolete - * 14: NOP command - * 13: READ_BUFFER - * 12: WRITE_BUFFER - * 11: Obsolete - * 10: Host Protected Area - * 9: DEVICE Reset - * 8: SERVICE Interrupt - * 7: Release Interrupt - * 6: look-ahead - * 5: write cache - * 4: PACKET Command - * 3: Power Management Feature Set - * 2: Removable Feature Set - * 1: Security Feature Set - * 0: SMART Feature Set - */ - u16 command_set_2; /* (word 83) - * 15: Shall be ZERO - * 14: Shall be ONE - * 13: FLUSH CACHE EXT - * 12: FLUSH CACHE - * 11: Device Configuration Overlay - * 10: 48-bit Address Feature Set - * 9: Automatic Acoustic Management - * 8: SET MAX security - * 7: reserved 1407DT PARTIES - * 6: SetF sub-command Power-Up - * 5: Power-Up in Standby Feature Set - * 4: Removable Media Notification - * 3: APM Feature Set - * 2: CFA Feature Set - * 1: READ/WRITE DMA QUEUED - * 0: Download MicroCode - */ - u16 cfsse; /* (word 84) - * cmd set-feature supported extensions - * 15: Shall be ZERO - * 14: Shall be ONE - * 13:3 reserved - * 2: Media Serial Number Valid - * 1: SMART selt-test supported - * 0: SMART error logging - */ - u16 cfs_enable_1; /* (word 85) - * command set-feature enabled - * 15: Obsolete - * 14: NOP command - * 13: READ_BUFFER - * 12: WRITE_BUFFER - * 11: Obsolete - * 10: Host Protected Area - * 9: DEVICE Reset - * 8: SERVICE Interrupt - * 7: Release Interrupt - * 6: look-ahead - * 5: write cache - * 4: PACKET Command - * 3: Power Management Feature Set - * 2: Removable Feature Set - * 1: Security Feature Set - * 0: SMART Feature Set - */ - u16 cfs_enable_2; /* (word 86) - * command set-feature enabled - * 15: Shall be ZERO - * 14: Shall be ONE - * 13: FLUSH CACHE EXT - * 12: FLUSH CACHE - * 11: Device Configuration Overlay - * 10: 48-bit Address Feature Set - * 9: Automatic Acoustic Management - * 8: SET MAX security - * 7: reserved 1407DT PARTIES - * 6: SetF sub-command Power-Up - * 5: Power-Up in Standby Feature Set - * 4: Removable Media Notification - * 3: APM Feature Set - * 2: CFA Feature Set - * 1: READ/WRITE DMA QUEUED - * 0: Download MicroCode - */ - u16 csf_default; /* (word 87) - * command set-feature default - * 15: Shall be ZERO - * 14: Shall be ONE - * 13:3 reserved - * 2: Media Serial Number Valid - * 1: SMART selt-test supported - * 0: SMART error logging - */ - u16 dma_ultra; /* (word 88) */ - u16 word89; /* reserved (word 89) */ - u16 word90; /* reserved (word 90) */ - u16 CurAPMvalues; /* current APM values */ - u16 word92; /* reserved (word 92) */ - u16 hw_config; /* hardware config (word 93) - * 15: - * 14: - * 13: - * 12: - * 11: - * 10: - * 9: - * 8: - * 7: - * 6: - * 5: - * 4: - * 3: - * 2: - * 1: - * 0: - */ - u16 acoustic; /* (word 94) - * 15:8 Vendor's recommended value - * 7:0 current value - */ - u16 words95_99[5]; /* reserved words 95-99 */ - u64 lba_capacity_2; /* 48-bit total number of sectors */ - u16 words104_125[22];/* reserved words 104-125 */ - u16 last_lun; /* (word 126) */ - u16 word127; /* (word 127) Feature Set - * Removable Media Notification - * 15:2 reserved - * 1:0 00 = not supported - * 01 = supported - * 10 = reserved - * 11 = reserved - */ - u16 dlf; /* (word 128) - * device lock function - * 15:9 reserved - * 8 security level 1:max 0:high - * 7:6 reserved - * 5 enhanced erase - * 4 expire - * 3 frozen - * 2 locked - * 1 en/disabled - * 0 capability - */ - u16 csfo; /* (word 129) - * current set features options - * 15:4 reserved - * 3: auto reassign - * 2: reverting - * 1: read-look-ahead - * 0: write cache - */ - u16 words130_155[26];/* reserved vendor words 130-155 */ - u16 word156; /* reserved vendor word 156 */ - u16 words157_159[3];/* reserved vendor words 157-159 */ - u16 cfa_power; /* (word 160) CFA Power Mode - * 15 word 160 supported - * 14 reserved - * 13 - * 12 - * 11:0 - */ - u16 words161_175[14];/* Reserved for CFA */ - u16 words176_205[31];/* Current Media Serial Number */ - u16 words206_254[48];/* reserved words 206-254 */ - u16 integrity_word; /* (word 255) - * 15:8 Checksum - * 7:0 Signature - */ -} __attribute__((packed)); - -#define IDE_NICE_DSC_OVERLAP (0) /* per the DSC overlap protocol */ - #endif diff --git a/include/linux/ide.h b/include/linux/ide.h index 8a41b3b2e74a..4dd795f055e6 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -8,7 +8,6 @@ #include <linux/config.h> #include <linux/init.h> #include <linux/ioport.h> -#include <linux/hdreg.h> #include <linux/hdsmart.h> #include <linux/blkdev.h> #include <linux/proc_fs.h> @@ -51,7 +50,460 @@ * "No user-serviceable parts" beyond this point *****************************************************************************/ -typedef unsigned char byte; /* used everywhere */ + +/* ATA/ATAPI Commands pre T13 Spec */ +#define WIN_NOP 0x00 +#define CFA_REQ_EXT_ERROR_CODE 0x03 /* CFA Request Extended Error Code */ +#define WIN_SRST 0x08 /* ATAPI soft reset command */ +#define WIN_DEVICE_RESET 0x08 +#define WIN_RESTORE 0x10 +#define WIN_READ 0x20 /* 28-Bit */ +#define WIN_READ_EXT 0x24 /* 48-Bit */ +#define WIN_READDMA_EXT 0x25 /* 48-Bit */ +#define WIN_READDMA_QUEUED_EXT 0x26 /* 48-Bit */ +#define WIN_READ_NATIVE_MAX_EXT 0x27 /* 48-Bit */ +#define WIN_MULTREAD_EXT 0x29 /* 48-Bit */ +#define WIN_WRITE 0x30 /* 28-Bit */ +#define WIN_WRITE_EXT 0x34 /* 48-Bit */ +#define WIN_WRITEDMA_EXT 0x35 /* 48-Bit */ +#define WIN_WRITEDMA_QUEUED_EXT 0x36 /* 48-Bit */ +#define WIN_SET_MAX_EXT 0x37 /* 48-Bit */ +#define CFA_WRITE_SECT_WO_ERASE 0x38 /* CFA Write Sectors without erase */ +#define WIN_MULTWRITE_EXT 0x39 /* 48-Bit */ +#define WIN_WRITE_VERIFY 0x3C /* 28-Bit */ +#define WIN_VERIFY 0x40 /* 28-Bit - Read Verify Sectors */ +#define WIN_VERIFY_EXT 0x42 /* 48-Bit */ +#define WIN_FORMAT 0x50 +#define WIN_INIT 0x60 +#define WIN_SEEK 0x70 +#define CFA_TRANSLATE_SECTOR 0x87 /* CFA Translate Sector */ +#define WIN_DIAGNOSE 0x90 +#define WIN_SPECIFY 0x91 /* set drive geometry translation */ +#define WIN_DOWNLOAD_MICROCODE 0x92 +#define WIN_STANDBYNOW2 0x94 +#define WIN_SETIDLE2 0x97 +#define WIN_CHECKPOWERMODE2 0x98 +#define WIN_SLEEPNOW2 0x99 +#define WIN_PACKETCMD 0xA0 /* Send a packet command. */ +#define WIN_PIDENTIFY 0xA1 /* identify ATAPI device */ +#define WIN_QUEUED_SERVICE 0xA2 +#define WIN_SMART 0xB0 /* self-monitoring and reporting */ +#define CFA_ERASE_SECTORS 0xC0 +#define WIN_MULTREAD 0xC4 /* read sectors using multiple mode*/ +#define WIN_MULTWRITE 0xC5 /* write sectors using multiple mode */ +#define WIN_SETMULT 0xC6 /* enable/disable multiple mode */ +#define WIN_READDMA_QUEUED 0xC7 /* read sectors using Queued DMA transfers */ +#define WIN_READDMA 0xC8 /* read sectors using DMA transfers */ +#define WIN_WRITEDMA 0xCA /* write sectors using DMA transfers */ +#define WIN_WRITEDMA_QUEUED 0xCC /* write sectors using Queued DMA transfers */ +#define CFA_WRITE_MULTI_WO_ERASE 0xCD /* CFA Write multiple without erase */ +#define WIN_GETMEDIASTATUS 0xDA +#define WIN_DOORLOCK 0xDE /* lock door on removable drives */ +#define WIN_DOORUNLOCK 0xDF /* unlock door on removable drives */ +#define WIN_STANDBYNOW1 0xE0 +#define WIN_IDLEIMMEDIATE 0xE1 /* force drive to become "ready" */ +#define WIN_STANDBY 0xE2 /* Set device in Standby Mode */ +#define WIN_SETIDLE1 0xE3 +#define WIN_READ_BUFFER 0xE4 /* force read only 1 sector */ +#define WIN_CHECKPOWERMODE1 0xE5 +#define WIN_SLEEPNOW1 0xE6 +#define WIN_FLUSH_CACHE 0xE7 +#define WIN_WRITE_BUFFER 0xE8 /* force write only 1 sector */ +#define WIN_FLUSH_CACHE_EXT 0xEA /* 48-Bit */ +#define WIN_IDENTIFY 0xEC /* ask drive to identify itself */ +#define WIN_MEDIAEJECT 0xED +#define WIN_IDENTIFY_DMA 0xEE /* same as WIN_IDENTIFY, but DMA */ +#define WIN_SETFEATURES 0xEF /* set special drive features */ +#define EXABYTE_ENABLE_NEST 0xF0 +#define WIN_SECURITY_SET_PASS 0xF1 +#define WIN_SECURITY_UNLOCK 0xF2 +#define WIN_SECURITY_ERASE_PREPARE 0xF3 +#define WIN_SECURITY_ERASE_UNIT 0xF4 +#define WIN_SECURITY_FREEZE_LOCK 0xF5 +#define WIN_SECURITY_DISABLE 0xF6 +#define WIN_READ_NATIVE_MAX 0xF8 /* return the native maximum address */ +#define WIN_SET_MAX 0xF9 +#define DISABLE_SEAGATE 0xFB + +/* WIN_SMART sub-commands */ + +#define SMART_READ_VALUES 0xD0 +#define SMART_READ_THRESHOLDS 0xD1 +#define SMART_AUTOSAVE 0xD2 +#define SMART_SAVE 0xD3 +#define SMART_IMMEDIATE_OFFLINE 0xD4 +#define SMART_READ_LOG_SECTOR 0xD5 +#define SMART_WRITE_LOG_SECTOR 0xD6 +#define SMART_WRITE_THRESHOLDS 0xD7 +#define SMART_ENABLE 0xD8 +#define SMART_DISABLE 0xD9 +#define SMART_STATUS 0xDA +#define SMART_AUTO_OFFLINE 0xDB + +/* Password used in TF4 & TF5 executing SMART commands */ + +#define SMART_LCYL_PASS 0x4F +#define SMART_HCYL_PASS 0xC2 + +/* WIN_SETFEATURES sub-commands */ + +#define SETFEATURES_EN_WCACHE 0x02 /* Enable write cache */ + +#define SETFEATURES_XFER 0x03 /* Set transfer mode */ +# define XFER_UDMA_7 0x47 /* 0100|0111 */ +# define XFER_UDMA_6 0x46 /* 0100|0110 */ +# define XFER_UDMA_5 0x45 /* 0100|0101 */ +# define XFER_UDMA_4 0x44 /* 0100|0100 */ +# define XFER_UDMA_3 0x43 /* 0100|0011 */ +# define XFER_UDMA_2 0x42 /* 0100|0010 */ +# define XFER_UDMA_1 0x41 /* 0100|0001 */ +# define XFER_UDMA_0 0x40 /* 0100|0000 */ +# define XFER_MW_DMA_2 0x22 /* 0010|0010 */ +# define XFER_MW_DMA_1 0x21 /* 0010|0001 */ +# define XFER_MW_DMA_0 0x20 /* 0010|0000 */ +# define XFER_SW_DMA_2 0x12 /* 0001|0010 */ +# define XFER_SW_DMA_1 0x11 /* 0001|0001 */ +# define XFER_SW_DMA_0 0x10 /* 0001|0000 */ +# define XFER_PIO_4 0x0C /* 0000|1100 */ +# define XFER_PIO_3 0x0B /* 0000|1011 */ +# define XFER_PIO_2 0x0A /* 0000|1010 */ +# define XFER_PIO_1 0x09 /* 0000|1001 */ +# define XFER_PIO_0 0x08 /* 0000|1000 */ +# define XFER_PIO_SLOW 0x00 /* 0000|0000 */ + +#define SETFEATURES_DIS_DEFECT 0x04 /* Disable Defect Management */ +#define SETFEATURES_EN_APM 0x05 /* Enable advanced power management */ +#define SETFEATURES_DIS_MSN 0x31 /* Disable Media Status Notification */ +#define SETFEATURES_EN_AAM 0x42 /* Enable Automatic Acoustic Management */ +#define SETFEATURES_DIS_RLA 0x55 /* Disable read look-ahead feature */ +#define SETFEATURES_EN_RI 0x5D /* Enable release interrupt */ +#define SETFEATURES_EN_SI 0x5E /* Enable SERVICE interrupt */ +#define SETFEATURES_DIS_RPOD 0x66 /* Disable reverting to power on defaults */ +#define SETFEATURES_DIS_WCACHE 0x82 /* Disable write cache */ +#define SETFEATURES_EN_DEFECT 0x84 /* Enable Defect Management */ +#define SETFEATURES_DIS_APM 0x85 /* Disable advanced power management */ +#define SETFEATURES_EN_MSN 0x95 /* Enable Media Status Notification */ +#define SETFEATURES_EN_RLA 0xAA /* Enable read look-ahead feature */ +#define SETFEATURES_PREFETCH 0xAB /* Sets drive prefetch value */ +#define SETFEATURES_DIS_AAM 0xC2 /* Disable Automatic Acoustic Management */ +#define SETFEATURES_EN_RPOD 0xCC /* Enable reverting to power on defaults */ +#define SETFEATURES_DIS_RI 0xDD /* Disable release interrupt */ +#define SETFEATURES_DIS_SI 0xDE /* Disable SERVICE interrupt */ + +/* WIN_SECURITY sub-commands */ + +#define SECURITY_SET_PASSWORD 0xBA +#define SECURITY_UNLOCK 0xBB +#define SECURITY_ERASE_PREPARE 0xBC +#define SECURITY_ERASE_UNIT 0xBD +#define SECURITY_FREEZE_LOCK 0xBE +#define SECURITY_DISABLE_PASSWORD 0xBF + + +/* Taskfile related constants. + */ +#define IDE_DRIVE_TASK_INVALID -1 +#define IDE_DRIVE_TASK_NO_DATA 0 +#define IDE_DRIVE_TASK_SET_XFER 1 + +#define IDE_DRIVE_TASK_IN 2 + +#define IDE_DRIVE_TASK_OUT 3 +#define IDE_DRIVE_TASK_RAW_WRITE 4 + +struct hd_drive_task_hdr { + u8 feature; + u8 sector_count; + u8 sector_number; + u8 low_cylinder; + u8 high_cylinder; + u8 device_head; +} __attribute__((packed)); + +/* + * Define standard taskfile in/out register + */ +#define IDE_TASKFILE_STD_OUT_FLAGS 0xFE +#define IDE_TASKFILE_STD_IN_FLAGS 0xFE +#define IDE_HOB_STD_OUT_FLAGS 0xC0 +#define IDE_HOB_STD_IN_FLAGS 0xC0 + +#define TASKFILE_INVALID 0x7fff +#define TASKFILE_48 0x8000 + +#define TASKFILE_NO_DATA 0x0000 + +#define TASKFILE_IN 0x0001 +#define TASKFILE_MULTI_IN 0x0002 + +#define TASKFILE_OUT 0x0004 +#define TASKFILE_MULTI_OUT 0x0008 +#define TASKFILE_IN_OUT 0x0010 + +#define TASKFILE_IN_DMA 0x0020 +#define TASKFILE_OUT_DMA 0x0040 +#define TASKFILE_IN_DMAQ 0x0080 +#define TASKFILE_OUT_DMAQ 0x0100 + +#define TASKFILE_P_IN 0x0200 +#define TASKFILE_P_OUT 0x0400 +#define TASKFILE_P_IN_DMA 0x0800 +#define TASKFILE_P_OUT_DMA 0x1000 +#define TASKFILE_P_IN_DMAQ 0x2000 +#define TASKFILE_P_OUT_DMAQ 0x4000 + +/* bus states */ +enum { + BUSSTATE_OFF = 0, + BUSSTATE_ON, + BUSSTATE_TRISTATE +}; + +/* + * Structure returned by HDIO_GET_IDENTITY, as per ANSI NCITS ATA6 rev.1b spec. + * + * If you change something here, please remember to update fix_driveid() in + * ide/probe.c. + */ +struct hd_driveid { + u16 config; /* lots of obsolete bit flags */ + u16 cyls; /* Obsolete, "physical" cyls */ + u16 reserved2; /* reserved (word 2) */ + u16 heads; /* Obsolete, "physical" heads */ + u16 track_bytes; /* unformatted bytes per track */ + u16 sector_bytes; /* unformatted bytes per sector */ + u16 sectors; /* Obsolete, "physical" sectors per track */ + u16 vendor0; /* vendor unique */ + u16 vendor1; /* vendor unique */ + u16 vendor2; /* Retired vendor unique */ + u8 serial_no[20]; /* 0 = not_specified */ + u16 buf_type; /* Retired */ + u16 buf_size; /* Retired, 512 byte increments + * 0 = not_specified + */ + u16 ecc_bytes; /* for r/w long cmds; 0 = not_specified */ + u8 fw_rev[8]; /* 0 = not_specified */ + char model[40]; /* 0 = not_specified */ + u8 max_multsect; /* 0=not_implemented */ + u8 vendor3; /* vendor unique */ + u16 dword_io; /* 0=not_implemented; 1=implemented */ + u8 vendor4; /* vendor unique */ + u8 capability; /* (upper byte of word 49) + * 3: IORDYsup + * 2: IORDYsw + * 1: LBA + * 0: DMA + */ + u16 reserved50; /* reserved (word 50) */ + u8 vendor5; /* Obsolete, vendor unique */ + u8 tPIO; /* Obsolete, 0=slow, 1=medium, 2=fast */ + u8 vendor6; /* Obsolete, vendor unique */ + u8 tDMA; /* Obsolete, 0=slow, 1=medium, 2=fast */ + u16 field_valid; /* (word 53) + * 2: ultra_ok word 88 + * 1: eide_ok words 64-70 + * 0: cur_ok words 54-58 + */ + u16 cur_cyls; /* Obsolete, logical cylinders */ + u16 cur_heads; /* Obsolete, l heads */ + u16 cur_sectors; /* Obsolete, l sectors per track */ + u16 cur_capacity0; /* Obsolete, l total sectors on drive */ + u16 cur_capacity1; /* Obsolete, (2 words, misaligned int) */ + u8 multsect; /* current multiple sector count */ + u8 multsect_valid; /* when (bit0==1) multsect is ok */ + u32 lba_capacity; /* Obsolete, total number of sectors */ + u16 dma_1word; /* Obsolete, single-word dma info */ + u16 dma_mword; /* multiple-word dma info */ + u16 eide_pio_modes; /* bits 0:mode3 1:mode4 */ + u16 eide_dma_min; /* min mword dma cycle time (ns) */ + u16 eide_dma_time; /* recommended mword dma cycle time (ns) */ + u16 eide_pio; /* min cycle time (ns), no IORDY */ + u16 eide_pio_iordy; /* min cycle time (ns), with IORDY */ + u16 words69_70[2]; /* reserved words 69-70 + * future command overlap and queuing + */ + /* HDIO_GET_IDENTITY currently returns only words 0 through 70 */ + u16 words71_74[4]; /* reserved words 71-74 + * for IDENTIFY PACKET DEVICE command + */ + u16 queue_depth; /* (word 75) + * 15:5 reserved + * 4:0 Maximum queue depth -1 + */ + u16 words76_79[4]; /* reserved words 76-79 */ + u16 major_rev_num; /* (word 80) */ + u16 minor_rev_num; /* (word 81) */ + u16 command_set_1; /* (word 82) supported + * 15: Obsolete + * 14: NOP command + * 13: READ_BUFFER + * 12: WRITE_BUFFER + * 11: Obsolete + * 10: Host Protected Area + * 9: DEVICE Reset + * 8: SERVICE Interrupt + * 7: Release Interrupt + * 6: look-ahead + * 5: write cache + * 4: PACKET Command + * 3: Power Management Feature Set + * 2: Removable Feature Set + * 1: Security Feature Set + * 0: SMART Feature Set + */ + u16 command_set_2; /* (word 83) + * 15: Shall be ZERO + * 14: Shall be ONE + * 13: FLUSH CACHE EXT + * 12: FLUSH CACHE + * 11: Device Configuration Overlay + * 10: 48-bit Address Feature Set + * 9: Automatic Acoustic Management + * 8: SET MAX security + * 7: reserved 1407DT PARTIES + * 6: SetF sub-command Power-Up + * 5: Power-Up in Standby Feature Set + * 4: Removable Media Notification + * 3: APM Feature Set + * 2: CFA Feature Set + * 1: READ/WRITE DMA QUEUED + * 0: Download MicroCode + */ + u16 cfsse; /* (word 84) + * cmd set-feature supported extensions + * 15: Shall be ZERO + * 14: Shall be ONE + * 13:3 reserved + * 2: Media Serial Number Valid + * 1: SMART selt-test supported + * 0: SMART error logging + */ + u16 cfs_enable_1; /* (word 85) + * command set-feature enabled + * 15: Obsolete + * 14: NOP command + * 13: READ_BUFFER + * 12: WRITE_BUFFER + * 11: Obsolete + * 10: Host Protected Area + * 9: DEVICE Reset + * 8: SERVICE Interrupt + * 7: Release Interrupt + * 6: look-ahead + * 5: write cache + * 4: PACKET Command + * 3: Power Management Feature Set + * 2: Removable Feature Set + * 1: Security Feature Set + * 0: SMART Feature Set + */ + u16 cfs_enable_2; /* (word 86) + * command set-feature enabled + * 15: Shall be ZERO + * 14: Shall be ONE + * 13: FLUSH CACHE EXT + * 12: FLUSH CACHE + * 11: Device Configuration Overlay + * 10: 48-bit Address Feature Set + * 9: Automatic Acoustic Management + * 8: SET MAX security + * 7: reserved 1407DT PARTIES + * 6: SetF sub-command Power-Up + * 5: Power-Up in Standby Feature Set + * 4: Removable Media Notification + * 3: APM Feature Set + * 2: CFA Feature Set + * 1: READ/WRITE DMA QUEUED + * 0: Download MicroCode + */ + u16 csf_default; /* (word 87) + * command set-feature default + * 15: Shall be ZERO + * 14: Shall be ONE + * 13:3 reserved + * 2: Media Serial Number Valid + * 1: SMART selt-test supported + * 0: SMART error logging + */ + u16 dma_ultra; /* (word 88) */ + u16 word89; /* reserved (word 89) */ + u16 word90; /* reserved (word 90) */ + u16 CurAPMvalues; /* current APM values */ + u16 word92; /* reserved (word 92) */ + u16 hw_config; /* hardware config (word 93) + * 15: + * 14: + * 13: + * 12: + * 11: + * 10: + * 9: + * 8: + * 7: + * 6: + * 5: + * 4: + * 3: + * 2: + * 1: + * 0: + */ + u16 acoustic; /* (word 94) + * 15:8 Vendor's recommended value + * 7:0 current value + */ + u16 words95_99[5]; /* reserved words 95-99 */ + u64 lba_capacity_2; /* 48-bit total number of sectors */ + u16 words104_125[22];/* reserved words 104-125 */ + u16 last_lun; /* (word 126) */ + u16 word127; /* (word 127) Feature Set + * Removable Media Notification + * 15:2 reserved + * 1:0 00 = not supported + * 01 = supported + * 10 = reserved + * 11 = reserved + */ + u16 dlf; /* (word 128) + * device lock function + * 15:9 reserved + * 8 security level 1:max 0:high + * 7:6 reserved + * 5 enhanced erase + * 4 expire + * 3 frozen + * 2 locked + * 1 en/disabled + * 0 capability + */ + u16 csfo; /* (word 129) + * current set features options + * 15:4 reserved + * 3: auto reassign + * 2: reverting + * 1: read-look-ahead + * 0: write cache + */ + u16 words130_155[26];/* reserved vendor words 130-155 */ + u16 word156; /* reserved vendor word 156 */ + u16 words157_159[3];/* reserved vendor words 157-159 */ + u16 cfa_power; /* (word 160) CFA Power Mode + * 15 word 160 supported + * 14 reserved + * 13 + * 12 + * 11:0 + */ + u16 words161_175[14];/* Reserved for CFA */ + u16 words176_205[31];/* Current Media Serial Number */ + u16 words206_254[48];/* reserved words 206-254 */ + u16 integrity_word; /* (word 255) + * 15:8 Checksum + * 7:0 Signature + */ +} __attribute__((packed)); + +#define IDE_NICE_DSC_OVERLAP (0) /* per the DSC overlap protocol */ /* * Probably not wise to fiddle with these @@ -105,6 +557,35 @@ enum { #define GET_ALTSTAT() IN_BYTE(drive->channel->io_ports[IDE_CONTROL_OFFSET]) #define GET_FEAT() IN_BYTE(IDE_NSECTOR_REG) +/* Bits of HD_STATUS */ +#define ERR_STAT 0x01 +#define INDEX_STAT 0x02 +#define ECC_STAT 0x04 /* Corrected error */ +#define DRQ_STAT 0x08 +#define SEEK_STAT 0x10 +#define SERVICE_STAT SEEK_STAT +#define WRERR_STAT 0x20 +#define READY_STAT 0x40 +#define BUSY_STAT 0x80 + +/* Bits for HD_ERROR */ +#define MARK_ERR 0x01 /* Bad address mark */ +#define TRK0_ERR 0x02 /* couldn't find track 0 */ +#define ABRT_ERR 0x04 /* Command aborted */ +#define MCR_ERR 0x08 /* media change request */ +#define ID_ERR 0x10 /* ID field not found */ +#define MC_ERR 0x20 /* media changed */ +#define ECC_ERR 0x40 /* Uncorrectable ECC error */ +#define BBD_ERR 0x80 /* pre-EIDE meaning: block marked bad */ +#define ICRC_ERR 0x80 /* new meaning: CRC error during transfer */ + +/* + * sector count bits + */ +#define NSEC_CD 0x01 +#define NSEC_IO 0x02 +#define NSEC_REL 0x04 + #define BAD_R_STAT (BUSY_STAT | ERR_STAT) #define BAD_W_STAT (BAD_R_STAT | WRERR_STAT) #define BAD_STAT (BAD_R_STAT | DRQ_STAT) @@ -665,23 +1146,23 @@ extern struct block_device_operations ide_fops[]; */ extern int ideprobe_init(void); #ifdef CONFIG_BLK_DEV_IDEDISK -extern int idedisk_init (void); +extern int idedisk_init(void); #endif #ifdef CONFIG_BLK_DEV_IDECD -extern int ide_cdrom_init (void); +extern int ide_cdrom_init(void); #endif #ifdef CONFIG_BLK_DEV_IDETAPE -extern int idetape_init (void); +extern int idetape_init(void); #endif #ifdef CONFIG_BLK_DEV_IDEFLOPPY -extern int idefloppy_init (void); +extern int idefloppy_init(void); #endif #ifdef CONFIG_BLK_DEV_IDESCSI -extern int idescsi_init (void); +extern int idescsi_init(void); #endif -extern int ide_register_subdriver(struct ata_device *, struct ata_operations *); -extern int ide_unregister_subdriver(struct ata_device *drive); +extern int ata_register_device(struct ata_device *, struct ata_operations *); +extern int ata_unregister_device(struct ata_device *drive); extern int ata_revalidate(kdev_t i_rdev); extern void ide_driver_module(void); diff --git a/kernel/fork.c b/kernel/fork.c index dee7097ba082..d40d246ec1df 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -608,22 +608,20 @@ static inline void copy_flags(unsigned long clone_flags, struct task_struct *p) } /* - * Ok, this is the main fork-routine. It copies the system process - * information (task[nr]) and sets up the necessary registers. It also - * copies the data segment in its entirety. The "stack_start" and - * "stack_top" arguments are simply passed along to the platform - * specific copy_thread() routine. Most platforms ignore stack_top. - * For an example that's using stack_top, see - * arch/ia64/kernel/process.c. + * This creates a new process as a copy of the old one, + * but does not actually start it yet. + * + * It copies the registers, and all the appropriate + * parts of the process environment (as per the clone + * flags). The actual kick-off is left to the caller. */ -struct task_struct *do_fork(unsigned long clone_flags, +static struct task_struct *copy_process(unsigned long clone_flags, unsigned long stack_start, struct pt_regs *regs, unsigned long stack_size) { int retval; struct task_struct *p = NULL; - struct completion vfork; if ((clone_flags & (CLONE_NEWNS|CLONE_FS)) == (CLONE_NEWNS|CLONE_FS)) return ERR_PTR(-EINVAL); @@ -680,10 +678,6 @@ struct task_struct *do_fork(unsigned long clone_flags, INIT_LIST_HEAD(&p->sibling); init_waitqueue_head(&p->wait_chldexit); p->vfork_done = NULL; - if (clone_flags & CLONE_VFORK) { - p->vfork_done = &vfork; - init_completion(&vfork); - } spin_lock_init(&p->alloc_lock); spin_lock_init(&p->switch_lock); @@ -803,20 +797,6 @@ struct task_struct *do_fork(unsigned long clone_flags, hash_pid(p); nr_threads++; write_unlock_irq(&tasklist_lock); - - if (p->ptrace & PT_PTRACED) - send_sig(SIGSTOP, p, 1); - - wake_up_forked_process(p); /* do this last */ - ++total_forks; - if (clone_flags & CLONE_VFORK) - wait_for_completion(&vfork); - else - /* - * Let the child process run first, to avoid most of the - * COW overhead when the child exec()s afterwards. - */ - set_need_resched(); retval = 0; fork_out: @@ -850,6 +830,45 @@ bad_fork_free: goto fork_out; } +/* + * Ok, this is the main fork-routine. + * + * It copies the process, and if successful kick-starts + * it and waits for it to finish using the VM if required. + */ +struct task_struct *do_fork(unsigned long clone_flags, + unsigned long stack_start, + struct pt_regs *regs, + unsigned long stack_size) +{ + struct task_struct *p; + + p = copy_process(clone_flags, stack_start, regs, stack_size); + if (!IS_ERR(p)) { + struct completion vfork; + + if (clone_flags & CLONE_VFORK) { + p->vfork_done = &vfork; + init_completion(&vfork); + } + + if (p->ptrace & PT_PTRACED) + send_sig(SIGSTOP, p, 1); + + wake_up_forked_process(p); /* do this last */ + ++total_forks; + if (clone_flags & CLONE_VFORK) + wait_for_completion(&vfork); + else + /* + * Let the child process run first, to avoid most of the + * COW overhead when the child exec()s afterwards. + */ + set_need_resched(); + } + return p; +} + /* SLAB cache for signal_struct structures (tsk->sig) */ kmem_cache_t *sigact_cachep; |
