Commit 916c2ff4 authored by Patrick Mochel's avatar Patrick Mochel

Merge bk://ldm@bkbits.net/linux-2.5-driverfs

into osdl.org:/home/mochel/src/kernel/devel/linux-2.5-driverfs
parents f42ba7ce 9fb72010
...@@ -1337,6 +1337,12 @@ S: 998 East 900 South, Suite 26 ...@@ -1337,6 +1337,12 @@ S: 998 East 900 South, Suite 26
S: Provo, Utah 84606-5607 S: Provo, Utah 84606-5607
S: USA 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 N: Rob W. W. Hooft
E: hooft@EMBL-Heidelberg.DE E: hooft@EMBL-Heidelberg.DE
D: Shared libs for graphics-tools and for the f2c compiler D: Shared libs for graphics-tools and for the f2c compiler
......
Information regarding the Enhanced IDE drive in Linux 2.5 Information regarding the Enhanced IDE drive in Linux 2.5
============================================================================== ==============================================================================
...@@ -301,6 +298,53 @@ There may be more options than shown -- use the source, Luke! ...@@ -301,6 +298,53 @@ There may be more options than shown -- use the source, Luke!
Everything else is rejected with a "BAD OPTION" message. 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 Some Terminology
......
...@@ -270,6 +270,12 @@ M: maxk@qualcomm.com ...@@ -270,6 +270,12 @@ M: maxk@qualcomm.com
W: http://bluez.sf.net W: http://bluez.sf.net
S: Maintained 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 BTTV VIDEO4LINUX DRIVER
P: Gerd Knorr P: Gerd Knorr
M: kraxel@bytesex.org M: kraxel@bytesex.org
......
...@@ -62,6 +62,20 @@ CONFIG_BLUEZ_HCIDTL1 ...@@ -62,6 +62,20 @@ CONFIG_BLUEZ_HCIDTL1
Say Y here to compile support for HCI DTL1 devices into the Say Y here to compile support for HCI DTL1 devices into the
kernel or say M to compile it as module (dtl1_cs.o). 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 HCI BlueCard (PC Card) device driver
CONFIG_BLUEZ_HCIBLUECARD CONFIG_BLUEZ_HCIBLUECARD
Bluetooth HCI BlueCard (PC Card) driver. Bluetooth HCI BlueCard (PC Card) driver.
......
...@@ -14,6 +14,8 @@ fi ...@@ -14,6 +14,8 @@ fi
dep_tristate 'HCI DTL1 (PC Card) driver' CONFIG_BLUEZ_HCIDTL1 $CONFIG_PCMCIA $CONFIG_BLUEZ 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 BlueCard (PC Card) driver' CONFIG_BLUEZ_HCIBLUECARD $CONFIG_PCMCIA $CONFIG_BLUEZ
dep_tristate 'HCI VHCI (Virtual HCI device) driver' CONFIG_BLUEZ_HCIVHCI $CONFIG_BLUEZ dep_tristate 'HCI VHCI (Virtual HCI device) driver' CONFIG_BLUEZ_HCIVHCI $CONFIG_BLUEZ
......
...@@ -6,6 +6,7 @@ obj-$(CONFIG_BLUEZ_HCIUSB) += hci_usb.o ...@@ -6,6 +6,7 @@ obj-$(CONFIG_BLUEZ_HCIUSB) += hci_usb.o
obj-$(CONFIG_BLUEZ_HCIVHCI) += hci_vhci.o obj-$(CONFIG_BLUEZ_HCIVHCI) += hci_vhci.o
obj-$(CONFIG_BLUEZ_HCIUART) += hci_uart.o obj-$(CONFIG_BLUEZ_HCIUART) += hci_uart.o
obj-$(CONFIG_BLUEZ_HCIDTL1) += dtl1_cs.o obj-$(CONFIG_BLUEZ_HCIDTL1) += dtl1_cs.o
obj-$(CONFIG_BLUEZ_HCIBT3C) += bt3c_cs.o
obj-$(CONFIG_BLUEZ_HCIBLUECARD) += bluecard_cs.o obj-$(CONFIG_BLUEZ_HCIBLUECARD) += bluecard_cs.o
hci_uart-y := hci_ldisc.o hci_uart-y := hci_ldisc.o
......
...@@ -89,16 +89,16 @@ typedef struct bluecard_info_t { ...@@ -89,16 +89,16 @@ typedef struct bluecard_info_t {
} 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); 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"; static dev_info_t dev_info = "bluecard_cs";
dev_link_t *bluecard_attach(void); dev_link_t *bluecard_attach(void);
void bluecard_detach(dev_link_t *); 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 */ /* Default baud rate: 57600, 115200, 230400 or 460800 */
...@@ -171,7 +171,7 @@ dev_link_t *dev_list = NULL; ...@@ -171,7 +171,7 @@ dev_link_t *dev_list = NULL;
void bluecard_activity_led_timeout(u_long arg) 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; unsigned int iobase = info->link.io.BasePort1;
if (test_bit(CARD_HAS_ACTIVITY_LED, &(info->hw_state))) { if (test_bit(CARD_HAS_ACTIVITY_LED, &(info->hw_state))) {
...@@ -184,7 +184,7 @@ void bluecard_activity_led_timeout(u_long arg) ...@@ -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; unsigned int iobase = info->link.io.BasePort1;
...@@ -208,8 +208,7 @@ static void bluecard_enable_activity_led(bluecard_info_t * info) ...@@ -208,8 +208,7 @@ static void bluecard_enable_activity_led(bluecard_info_t * info)
/* ======================== Interrupt handling ======================== */ /* ======================== Interrupt handling ======================== */
static int bluecard_write(unsigned int iobase, unsigned int offset, static int bluecard_write(unsigned int iobase, unsigned int offset, __u8 *buf, int len)
__u8 * buf, int len)
{ {
int i, actual; int i, actual;
...@@ -224,7 +223,7 @@ static int bluecard_write(unsigned int iobase, unsigned int offset, ...@@ -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) { if (!info) {
printk(KERN_WARNING "bluecard_cs: Call of write_wakeup for unknown device.\n"); 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) ...@@ -253,15 +252,13 @@ static void bluecard_write_wakeup(bluecard_info_t * info)
return; return;
if (test_bit(XMIT_BUFFER_NUMBER, &(info->tx_state))) { if (test_bit(XMIT_BUFFER_NUMBER, &(info->tx_state))) {
if (!test_bit if (!test_bit(XMIT_BUF_TWO_READY, &(info->tx_state)))
(XMIT_BUF_TWO_READY, &(info->tx_state)))
break; break;
offset = 0x10; offset = 0x10;
command = REG_COMMAND_TX_BUF_TWO; command = REG_COMMAND_TX_BUF_TWO;
ready_bit = XMIT_BUF_TWO_READY; ready_bit = XMIT_BUF_TWO_READY;
} else { } else {
if (!test_bit if (!test_bit(XMIT_BUF_ONE_READY, &(info->tx_state)))
(XMIT_BUF_ONE_READY, &(info->tx_state)))
break; break;
offset = 0x00; offset = 0x00;
command = REG_COMMAND_TX_BUF_ONE; command = REG_COMMAND_TX_BUF_ONE;
...@@ -272,11 +269,9 @@ static void bluecard_write_wakeup(bluecard_info_t * info) ...@@ -272,11 +269,9 @@ static void bluecard_write_wakeup(bluecard_info_t * info)
break; break;
if (skb->pkt_type & 0x80) { if (skb->pkt_type & 0x80) {
/* Disable RTS */ /* Disable RTS */
info->ctrl_reg |= REG_CONTROL_RTS; info->ctrl_reg |= REG_CONTROL_RTS;
outb(info->ctrl_reg, iobase + REG_CONTROL); outb(info->ctrl_reg, iobase + REG_CONTROL);
} }
/* Activate LED */ /* Activate LED */
...@@ -349,8 +344,7 @@ static void bluecard_write_wakeup(bluecard_info_t * info) ...@@ -349,8 +344,7 @@ static void bluecard_write_wakeup(bluecard_info_t * info)
} }
static int bluecard_read(unsigned int iobase, unsigned int offset, static int bluecard_read(unsigned int iobase, unsigned int offset, __u8 *buf, int size)
__u8 * buf, int size)
{ {
int i, n, len; int i, n, len;
...@@ -378,7 +372,7 @@ static int bluecard_read(unsigned int iobase, unsigned int offset, ...@@ -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 int iobase;
unsigned char buf[31]; unsigned char buf[31];
...@@ -410,7 +404,7 @@ static void bluecard_receive(bluecard_info_t * info, unsigned int offset) ...@@ -410,7 +404,7 @@ static void bluecard_receive(bluecard_info_t * info, unsigned int offset)
if (info->rx_state == RECV_WAIT_PACKET_TYPE) { 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]; info->rx_skb->pkt_type = buf[i];
switch (info->rx_skb->pkt_type) { switch (info->rx_skb->pkt_type) {
...@@ -469,20 +463,20 @@ static void bluecard_receive(bluecard_info_t * info, unsigned int offset) ...@@ -469,20 +463,20 @@ static void bluecard_receive(bluecard_info_t * info, unsigned int offset)
switch (info->rx_state) { switch (info->rx_state) {
case RECV_WAIT_EVENT_HEADER: 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_state = RECV_WAIT_DATA;
info->rx_count = eh->plen; info->rx_count = eh->plen;
break; break;
case RECV_WAIT_ACL_HEADER: 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); dlen = __le16_to_cpu(ah->dlen);
info->rx_state = RECV_WAIT_DATA; info->rx_state = RECV_WAIT_DATA;
info->rx_count = dlen; info->rx_count = dlen;
break; break;
case RECV_WAIT_SCO_HEADER: 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_state = RECV_WAIT_DATA;
info->rx_count = sh->dlen; info->rx_count = sh->dlen;
break; break;
...@@ -571,9 +565,8 @@ void bluecard_interrupt(int irq, void *dev_inst, struct pt_regs *regs) ...@@ -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) 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; struct sk_buff *skb;
int i;
/* Ericsson baud rate command */ /* Ericsson baud rate command */
unsigned char cmd[] = { HCI_COMMAND_PKT, 0x09, 0xfc, 0x01, 0x03 }; 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) ...@@ -604,8 +597,7 @@ static int bluecard_hci_set_baud_rate(struct hci_dev *hdev, int baud)
break; break;
} }
for (i = 0; i < sizeof(cmd); i++) memcpy(skb_put(skb, sizeof(cmd)), cmd, sizeof(cmd));
*skb_put(skb, 1) = cmd[i];
skb_queue_tail(&(info->txq), skb); skb_queue_tail(&(info->txq), skb);
...@@ -621,7 +613,7 @@ static int bluecard_hci_set_baud_rate(struct hci_dev *hdev, int baud) ...@@ -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) 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 */ /* Drop TX queue */
skb_queue_purge(&(info->txq)); skb_queue_purge(&(info->txq));
...@@ -632,7 +624,7 @@ static int bluecard_hci_flush(struct hci_dev *hdev) ...@@ -632,7 +624,7 @@ static int bluecard_hci_flush(struct hci_dev *hdev)
static int bluecard_hci_open(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; unsigned int iobase = info->link.io.BasePort1;
bluecard_hci_set_baud_rate(hdev, DEFAULT_BAUD_RATE); bluecard_hci_set_baud_rate(hdev, DEFAULT_BAUD_RATE);
...@@ -649,7 +641,7 @@ static int bluecard_hci_open(struct hci_dev *hdev) ...@@ -649,7 +641,7 @@ static int bluecard_hci_open(struct hci_dev *hdev)
static int bluecard_hci_close(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; unsigned int iobase = info->link.io.BasePort1;
if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags))) if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags)))
...@@ -667,14 +659,14 @@ static int bluecard_hci_close(struct hci_dev *hdev) ...@@ -667,14 +659,14 @@ static int bluecard_hci_close(struct hci_dev *hdev)
static int bluecard_hci_send_frame(struct sk_buff *skb) static int bluecard_hci_send_frame(struct sk_buff *skb)
{ {
bluecard_info_t *info; bluecard_info_t *info;
struct hci_dev *hdev = (struct hci_dev *) (skb->dev); struct hci_dev *hdev = (struct hci_dev *)(skb->dev);
if (!hdev) { if (!hdev) {
printk(KERN_WARNING "bluecard_cs: Frame for unknown HCI device (hdev=NULL)."); printk(KERN_WARNING "bluecard_cs: Frame for unknown HCI device (hdev=NULL).");
return -ENODEV; return -ENODEV;
} }
info = (bluecard_info_t *) (hdev->driver_data); info = (bluecard_info_t *)(hdev->driver_data);
switch (skb->pkt_type) { switch (skb->pkt_type) {
case HCI_COMMAND_PKT: case HCI_COMMAND_PKT:
...@@ -703,8 +695,7 @@ static void bluecard_hci_destruct(struct hci_dev *hdev) ...@@ -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, static int bluecard_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
unsigned long arg)
{ {
return -ENOIOCTLCMD; return -ENOIOCTLCMD;
} }
...@@ -714,7 +705,7 @@ static int bluecard_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, ...@@ -714,7 +705,7 @@ static int bluecard_hci_ioctl(struct hci_dev *hdev, unsigned int cmd,
/* ======================== Card services HCI interaction ======================== */ /* ======================== 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; unsigned int iobase = info->link.io.BasePort1;
struct hci_dev *hdev; struct hci_dev *hdev;
...@@ -724,7 +715,7 @@ int bluecard_open(bluecard_info_t * info) ...@@ -724,7 +715,7 @@ int bluecard_open(bluecard_info_t * info)
init_timer(&(info->timer)); init_timer(&(info->timer));
info->timer.function = &bluecard_activity_led_timeout; 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)); skb_queue_head_init(&(info->txq));
...@@ -781,7 +772,8 @@ int bluecard_open(bluecard_info_t * info) ...@@ -781,7 +772,8 @@ int bluecard_open(bluecard_info_t * info)
/* Timeout before it is safe to send the first HCI packet */ /* Timeout before it is safe to send the first HCI packet */
set_current_state(TASK_INTERRUPTIBLE); 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 */ /* Initialize and register HCI device */
...@@ -806,7 +798,7 @@ int bluecard_open(bluecard_info_t * info) ...@@ -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; unsigned int iobase = info->link.io.BasePort1;
struct hci_dev *hdev = &(info->hdev); struct hci_dev *hdev = &(info->hdev);
...@@ -858,7 +850,7 @@ dev_link_t *bluecard_attach(void) ...@@ -858,7 +850,7 @@ dev_link_t *bluecard_attach(void)
link->priv = info; link->priv = info;
link->release.function = &bluecard_release; 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.Attributes1 = IO_DATA_PATH_WIDTH_8;
link->io.NumPorts1 = 8; link->io.NumPorts1 = 8;
link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
...@@ -883,9 +875,9 @@ dev_link_t *bluecard_attach(void) ...@@ -883,9 +875,9 @@ dev_link_t *bluecard_attach(void)
client_reg.dev_info = &dev_info; client_reg.dev_info = &dev_info;
client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
client_reg.EventMask = client_reg.EventMask =
CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
client_reg.event_handler = &bluecard_event; client_reg.event_handler = &bluecard_event;
client_reg.Version = 0x0210; client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link; client_reg.event_callback_args.client_data = link;
...@@ -901,7 +893,7 @@ dev_link_t *bluecard_attach(void) ...@@ -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; bluecard_info_t *info = link->priv;
dev_link_t **linkp; dev_link_t **linkp;
...@@ -917,7 +909,7 @@ void bluecard_detach(dev_link_t * link) ...@@ -917,7 +909,7 @@ void bluecard_detach(dev_link_t * link)
del_timer(&link->release); del_timer(&link->release);
if (link->state & DEV_CONFIG) if (link->state & DEV_CONFIG)
bluecard_release((u_long) link); bluecard_release((u_long)link);
if (link->handle) { if (link->handle) {
ret = CardServices(DeregisterClient, link->handle); ret = CardServices(DeregisterClient, link->handle);
...@@ -932,8 +924,7 @@ void bluecard_detach(dev_link_t * link) ...@@ -932,8 +924,7 @@ void bluecard_detach(dev_link_t * link)
} }
static int get_tuple(int fn, client_handle_t handle, tuple_t * tuple, static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, cisparse_t *parse)
cisparse_t * parse)
{ {
int i; int i;
...@@ -952,7 +943,7 @@ static int get_tuple(int fn, client_handle_t handle, tuple_t * tuple, ...@@ -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 first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c)
#define next_tuple(a, b, c) get_tuple(GetNextTuple, 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; client_handle_t handle = link->handle;
bluecard_info_t *info = link->priv; bluecard_info_t *info = link->priv;
...@@ -962,7 +953,7 @@ void bluecard_config(dev_link_t * link) ...@@ -962,7 +953,7 @@ void bluecard_config(dev_link_t * link)
config_info_t config; config_info_t config;
int i, n, last_ret, last_fn; int i, n, last_ret, last_fn;
tuple.TupleData = (cisdata_t *) buf; tuple.TupleData = (cisdata_t *)buf;
tuple.TupleOffset = 0; tuple.TupleOffset = 0;
tuple.TupleDataMax = 255; tuple.TupleDataMax = 255;
tuple.Attributes = 0; tuple.Attributes = 0;
...@@ -1010,12 +1001,12 @@ void bluecard_config(dev_link_t * link) ...@@ -1010,12 +1001,12 @@ void bluecard_config(dev_link_t * link)
goto failed; goto failed;
} }
MOD_INC_USE_COUNT; MOD_INC_USE_COUNT;
if (bluecard_open(info) != 0) if (bluecard_open(info) != 0)
goto failed; goto failed;
strcpy(info->node.dev_name, info->hdev.name);
link->dev = &info->node; link->dev = &info->node;
link->state &= ~DEV_CONFIG_PENDING; link->state &= ~DEV_CONFIG_PENDING;
...@@ -1025,13 +1016,13 @@ void bluecard_config(dev_link_t * link) ...@@ -1025,13 +1016,13 @@ void bluecard_config(dev_link_t * link)
cs_error(link->handle, last_fn, last_ret); cs_error(link->handle, last_fn, last_ret);
failed: failed:
bluecard_release((u_long) link); bluecard_release((u_long)link);
} }
void bluecard_release(u_long arg) 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; bluecard_info_t *info = link->priv;
if (link->state & DEV_PRESENT) if (link->state & DEV_PRESENT)
...@@ -1049,8 +1040,7 @@ void bluecard_release(u_long arg) ...@@ -1049,8 +1040,7 @@ void bluecard_release(u_long arg)
} }
int bluecard_event(event_t event, int priority, int bluecard_event(event_t event, int priority, event_callback_args_t *args)
event_callback_args_t * args)
{ {
dev_link_t *link = args->client_data; dev_link_t *link = args->client_data;
bluecard_info_t *info = link->priv; bluecard_info_t *info = link->priv;
...@@ -1079,8 +1069,7 @@ int bluecard_event(event_t event, int priority, ...@@ -1079,8 +1069,7 @@ int bluecard_event(event_t event, int priority,
/* Fall through... */ /* Fall through... */
case CS_EVENT_CARD_RESET: case CS_EVENT_CARD_RESET:
if (DEV_OK(link)) if (DEV_OK(link))
CardServices(RequestConfiguration, link->handle, CardServices(RequestConfiguration, link->handle, &link->conf);
&link->conf);
break; break;
} }
......
/*
*
* 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(&current->sigmask_lock);
tmpsig = current->blocked;
siginitsetinv(&current->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP));
recalc_sigpending();
spin_unlock_irq(&current->sigmask_lock);
result = waitpid(pid, NULL, __WCLONE);
/* Allow signals again */
spin_lock_irq(&current->sigmask_lock);
current->blocked = tmpsig;
recalc_sigpending();
spin_unlock_irq(&current->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);
...@@ -75,23 +75,22 @@ MODULE_LICENSE("GPL"); ...@@ -75,23 +75,22 @@ MODULE_LICENSE("GPL");
typedef struct dtl1_info_t { typedef struct dtl1_info_t {
dev_link_t link; dev_link_t link;
dev_node_t node; 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 */ unsigned long flowmask; /* HCI flow mask */
int ri_latch; int ri_latch;
struct sk_buff_head txq; struct sk_buff_head txq;
unsigned long tx_state; unsigned long tx_state;
unsigned long rx_state;
unsigned long rx_count;
struct sk_buff *rx_skb;
unsigned long rx_state;
unsigned long rx_count;
struct sk_buff *rx_skb;
} dtl1_info_t; } dtl1_info_t;
...@@ -104,7 +103,7 @@ static dev_info_t dev_info = "dtl1_cs"; ...@@ -104,7 +103,7 @@ static dev_info_t dev_info = "dtl1_cs";
dev_link_t *dtl1_attach(void); dev_link_t *dtl1_attach(void);
void dtl1_detach(dev_link_t *); void dtl1_detach(dev_link_t *);
dev_link_t *dev_list = NULL; static dev_link_t *dev_list = NULL;
/* Transmit states */ /* Transmit states */
...@@ -118,282 +117,253 @@ dev_link_t *dev_list = NULL; ...@@ -118,282 +117,253 @@ dev_link_t *dev_list = NULL;
typedef struct { typedef struct {
u8 type; u8 type;
u8 zero; u8 zero;
u16 len; u16 len;
} __attribute__ ((packed)) nsh_t; /* Nokia Specific Header */ } __attribute__ ((packed)) nsh_t; /* Nokia Specific Header */
#define NSHL 4 /* Nokia Specific Header Length */ #define NSHL 4 /* Nokia Specific Header Length */
/* ======================== Interrupt handling ======================== */ /* ======================== Interrupt handling ======================== */
static int dtl1_write(unsigned int iobase, int fifo_size, __u8 *buf, int len) { static int dtl1_write(unsigned int iobase, int fifo_size, __u8 *buf, int len)
{
int actual = 0; int actual = 0;
/* Tx FIFO should be empty */
if (!(inb(iobase + UART_LSR) & UART_LSR_THRE))
return 0;
/* Fill FIFO with current frame */ /* Tx FIFO should be empty */
while ((fifo_size-- > 0) && (actual < len)) { if (!(inb(iobase + UART_LSR) & UART_LSR_THRE))
/* Transmit next byte */ return 0;
outb(buf[actual], iobase + UART_TX);
actual++;
}
/* 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) { static void dtl1_write_wakeup(dtl1_info_t *info)
{
if (!info) { if (!info) {
printk(KERN_WARNING "dtl1_cs: Call of write_wakeup for unknown device.\n"); printk(KERN_WARNING "dtl1_cs: Call of write_wakeup for unknown device.\n");
return; 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;
}
if (test_bit(XMIT_WAITING, &(info->tx_state))) {
set_bit(XMIT_WAKEUP, &(info->tx_state));
return;
}
do { if (test_and_set_bit(XMIT_SENDING, &(info->tx_state))) {
register unsigned int iobase = info->link.io.BasePort1; set_bit(XMIT_WAKEUP, &(info->tx_state));
register struct sk_buff *skb; return;
register int len; }
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)) clear_bit(XMIT_WAKEUP, &(info->tx_state));
return;
if (!(info->link.state & DEV_PRESENT))
return;
if (!(skb = skb_dequeue(&(info->txq)))) if (!(skb = skb_dequeue(&(info->txq))))
break; break;
/* Send frame */
len = dtl1_write(iobase, 32, skb->data, skb->len);
/* Send frame */ if (len == skb->len) {
len = dtl1_write(iobase, 32, skb->data, 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) { info->hdev.stat.byte_tx += 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; } while (test_bit(XMIT_WAKEUP, &(info->tx_state)));
} while (test_bit(XMIT_WAKEUP, &(info->tx_state)));
clear_bit(XMIT_SENDING, &(info->tx_state));
clear_bit(XMIT_SENDING, &(info->tx_state));
} }
static void dtl1_control(dtl1_info_t *info, struct sk_buff *skb) { static void dtl1_control(dtl1_info_t *info, struct sk_buff *skb)
{
u8 flowmask = *(u8 *)skb->data; u8 flowmask = *(u8 *)skb->data;
int i; int i;
printk(KERN_INFO "dtl1_cs: Nokia control data = "); printk(KERN_INFO "dtl1_cs: Nokia control data = ");
for (i = 0; i < skb->len; i++) { for (i = 0; i < skb->len; i++) {
printk("%02x ", skb->data[i]); printk("%02x ", skb->data[i]);
} }
printk("\n"); 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 */ info->flowmask = flowmask;
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);
kfree_skb(skb);
} }
static void dtl1_receive(dtl1_info_t *info) { static void dtl1_receive(dtl1_info_t *info)
{
unsigned int iobase; unsigned int iobase;
nsh_t *nsh; nsh_t *nsh;
int boguscount = 0; int boguscount = 0;
if (!info) {
if (!info) { printk(KERN_WARNING "dtl1_cs: Call of receive for unknown device.\n");
printk(KERN_WARNING "dtl1_cs: Call of receive for unknown device.\n"); return;
return; }
}
iobase = info->link.io.BasePort1;
iobase = info->link.io.BasePort1; do {
info->hdev.stat.byte_rx++;
do {
info->hdev.stat.byte_rx++; /* Allocate packet */
if (info->rx_skb == NULL)
/* Allocate packet */ if (!(info->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
if (info->rx_skb == NULL) printk(KERN_WARNING "dtl1_cs: Can't allocate mem for new packet.\n");
if (!(info->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) { info->rx_state = RECV_WAIT_NSH;
printk(KERN_WARNING "dtl1_cs: Can't allocate mem for new packet.\n"); info->rx_count = NSHL;
info->rx_state = RECV_WAIT_NSH; return;
info->rx_count = NSHL; }
return;
} *skb_put(info->rx_skb, 1) = inb(iobase + UART_RX);
nsh = (nsh_t *)info->rx_skb->data;
*skb_put(info->rx_skb, 1) = inb(iobase + UART_RX); info->rx_count--;
nsh = (nsh_t *)info->rx_skb->data;
if (info->rx_count == 0) {
info->rx_count--;
switch (info->rx_state) {
case RECV_WAIT_NSH:
if (info->rx_count == 0) { info->rx_state = RECV_WAIT_DATA;
info->rx_count = nsh->len + (nsh->len & 0x0001);
switch (info->rx_state) { break;
case RECV_WAIT_NSH: case RECV_WAIT_DATA:
info->rx_state = RECV_WAIT_DATA; info->rx_skb->pkt_type = nsh->type;
info->rx_count = nsh->len + (nsh->len & 0x0001);
break; /* remove PAD byte if it exists */
case RECV_WAIT_DATA: if (nsh->len & 0x0001) {
info->rx_skb->pkt_type = nsh->type; info->rx_skb->tail--;
info->rx_skb->len--;
/* remove PAD byte if it exists */ }
if (nsh->len & 0x0001) {
info->rx_skb->tail--; /* remove NSH */
info->rx_skb->len--; skb_pull(info->rx_skb, NSHL);
}
switch (info->rx_skb->pkt_type) {
/* remove NSH */ case 0x80:
skb_pull(info->rx_skb, NSHL); /* control data for the Nokia Card */
dtl1_control(info, info->rx_skb);
break;
switch (info->rx_skb->pkt_type) { case 0x82:
case 0x80: case 0x83:
/* control data for the Nokia Card */ case 0x84:
dtl1_control(info, info->rx_skb); /* send frame to the HCI layer */
break; info->rx_skb->dev = (void *)&(info->hdev);
case 0x82: info->rx_skb->pkt_type &= 0x0f;
case 0x83: hci_recv_frame(info->rx_skb);
case 0x84: break;
/* send frame to the HCI layer */ default:
info->rx_skb->dev = (void *)&(info->hdev); /* unknown packet */
info->rx_skb->pkt_type &= 0x0f; printk(KERN_WARNING "dtl1_cs: Unknown HCI packet with type 0x%02x received.\n", info->rx_skb->pkt_type);
hci_recv_frame(info->rx_skb); kfree_skb(info->rx_skb);
break; break;
default: }
/* unknown packet */
printk(KERN_WARNING "dtl1_cs: Unknown HCI packet with type 0x%02x received.\n", info->rx_skb->pkt_type); info->rx_state = RECV_WAIT_NSH;
kfree_skb(info->rx_skb); info->rx_count = NSHL;
break; info->rx_skb = NULL;
} break;
}
info->rx_state = RECV_WAIT_NSH; }
info->rx_count = NSHL;
info->rx_skb = NULL; /* Make sure we don't stay here to long */
break; if (boguscount++ > 32)
} break;
} } while (inb(iobase + UART_LSR) & UART_LSR_DR);
/* 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) { void dtl1_interrupt(int irq, void *dev_inst, struct pt_regs *regs)
{
dtl1_info_t *info = dev_inst; dtl1_info_t *info = dev_inst;
unsigned int iobase; unsigned int iobase;
unsigned char msr; unsigned char msr;
int boguscount = 0; int boguscount = 0;
int iir, lsr; int iir, lsr;
if (!info) {
if (!info) { printk(KERN_WARNING "dtl1_cs: Call of irq %d for unknown device.\n", irq);
printk(KERN_WARNING "dtl1_cs: Call of irq %d for unknown device.\n", irq); return;
return; }
}
iobase = info->link.io.BasePort1;
iobase = info->link.io.BasePort1; spin_lock(&(info->lock));
iir = inb(iobase + UART_IIR) & UART_IIR_ID;
spin_lock(&(info->lock)); while (iir) {
iir = inb(iobase + UART_IIR) & UART_IIR_ID; /* Clear interrupt */
while (iir) { lsr = inb(iobase + UART_LSR);
/* Clear interrupt */ switch (iir) {
lsr = inb(iobase + UART_LSR); case UART_IIR_RLSI:
printk(KERN_NOTICE "dtl1_cs: RLSI\n");
switch (iir) { break;
case UART_IIR_RLSI: case UART_IIR_RDI:
printk(KERN_NOTICE "dtl1_cs: RLSI\n"); /* Receive interrupt */
break; dtl1_receive(info);
case UART_IIR_RDI: break;
/* Receive interrupt */ case UART_IIR_THRI:
dtl1_receive(info); if (lsr & UART_LSR_THRE) {
break; /* Transmitter ready for data */
case UART_IIR_THRI: dtl1_write_wakeup(info);
if (lsr & UART_LSR_THRE) { }
/* Transmitter ready for data */ break;
dtl1_write_wakeup(info); default:
} printk(KERN_NOTICE "dtl1_cs: Unhandled IIR=%#x\n", iir);
break; 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;
/* Make sure we don't stay here to long */
if (boguscount++ > 100) iir = inb(iobase + UART_IIR) & UART_IIR_ID;
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;
msr = inb(iobase + UART_MSR); clear_bit(XMIT_WAITING, &(info->tx_state));
dtl1_write_wakeup(info);
if (info->ri_latch ^ (msr & UART_MSR_RI)) { }
info->ri_latch = msr & UART_MSR_RI;
clear_bit(XMIT_WAITING, &(info->tx_state)); spin_unlock(&(info->lock));
dtl1_write_wakeup(info);
}
spin_unlock(&(info->lock));
} }
...@@ -401,107 +371,94 @@ void dtl1_interrupt(int irq, void *dev_inst, struct pt_regs *regs) { ...@@ -401,107 +371,94 @@ void dtl1_interrupt(int irq, void *dev_inst, struct pt_regs *regs) {
/* ======================== HCI interface ======================== */ /* ======================== HCI interface ======================== */
static int dtl1_hci_open(struct hci_dev *hdev) { static int dtl1_hci_open(struct hci_dev *hdev)
{
set_bit(HCI_RUNNING, &(hdev->flags)); set_bit(HCI_RUNNING, &(hdev->flags));
return 0;
return 0;
} }
static int dtl1_hci_flush(struct hci_dev *hdev) { static int dtl1_hci_flush(struct hci_dev *hdev)
{
dtl1_info_t *info = (dtl1_info_t *)(hdev->driver_data); dtl1_info_t *info = (dtl1_info_t *)(hdev->driver_data);
/* Drop TX queue */
skb_queue_purge(&(info->txq));
/* Drop TX queue */ return 0;
skb_queue_purge(&(info->txq));
return 0;
} }
static int dtl1_hci_close(struct hci_dev *hdev) { static int dtl1_hci_close(struct hci_dev *hdev)
{
if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags))) if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags)))
return 0; return 0;
dtl1_hci_flush(hdev); dtl1_hci_flush(hdev);
return 0;
return 0;
} }
static int dtl1_hci_send_frame(struct sk_buff *skb) { static int dtl1_hci_send_frame(struct sk_buff *skb)
{
dtl1_info_t *info; dtl1_info_t *info;
struct hci_dev* hdev = (struct hci_dev *)(skb->dev); struct hci_dev *hdev = (struct hci_dev *)(skb->dev);
struct sk_buff *s; struct sk_buff *s;
nsh_t nsh; nsh_t nsh;
if (!hdev) {
if (!hdev) { printk(KERN_WARNING "dtl1_cs: Frame for unknown HCI device (hdev=NULL).");
printk(KERN_WARNING "dtl1_cs: Frame for unknown HCI device (hdev=NULL)."); return -ENODEV;
return -ENODEV; }
}
info = (dtl1_info_t *)(hdev->driver_data);
info = (dtl1_info_t *)(hdev->driver_data);
switch (skb->pkt_type) {
case HCI_COMMAND_PKT:
switch (skb->pkt_type) { hdev->stat.cmd_tx++;
case HCI_COMMAND_PKT: nsh.type = 0x81;
hdev->stat.cmd_tx++; break;
nsh.type = 0x81; case HCI_ACLDATA_PKT:
break; hdev->stat.acl_tx++;
case HCI_ACLDATA_PKT: nsh.type = 0x82;
hdev->stat.acl_tx++; break;
nsh.type = 0x82; case HCI_SCODATA_PKT:
break; hdev->stat.sco_tx++;
case HCI_SCODATA_PKT: nsh.type = 0x83;
hdev->stat.sco_tx++; break;
nsh.type = 0x83; };
break;
}; nsh.zero = 0;
nsh.len = skb->len;
nsh.zero = 0;
nsh.len = skb->len; s = bluez_skb_alloc(NSHL + skb->len + 1, GFP_ATOMIC);
skb_reserve(s, NSHL);
s = bluez_skb_alloc(NSHL + skb->len + 1, GFP_ATOMIC); memcpy(skb_put(s, skb->len), skb->data, skb->len);
skb_reserve(s, NSHL); if (skb->len & 0x0001)
memcpy(skb_put(s, skb->len), skb->data, skb->len); *skb_put(s, 1) = 0; /* PAD */
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);
/* Prepend skb with Nokia frame header and queue */ skb_queue_tail(&(info->txq), s);
memcpy(skb_push(s, NSHL), &nsh, NSHL);
skb_queue_tail(&(info->txq), s); dtl1_write_wakeup(info);
kfree_skb(skb);
dtl1_write_wakeup(info);
return 0;
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) { static int dtl1_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
{
return -ENOIOCTLCMD; return -ENOIOCTLCMD;
} }
...@@ -509,101 +466,91 @@ static int dtl1_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long ...@@ -509,101 +466,91 @@ static int dtl1_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long
/* ======================== Card services HCI interaction ======================== */ /* ======================== Card services HCI interaction ======================== */
int dtl1_open(dtl1_info_t *info) { int dtl1_open(dtl1_info_t *info)
{
unsigned long flags; unsigned long flags;
unsigned int iobase = info->link.io.BasePort1; unsigned int iobase = info->link.io.BasePort1;
struct hci_dev *hdev; 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; set_bit(XMIT_WAITING, &(info->tx_state));
info->rx_count = NSHL;
info->rx_skb = NULL;
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 */ /* Initialize UART */
outb(0, iobase + UART_MCR); 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 */ info->ri_latch = inb(info->link.io.BasePort1 + UART_MSR) & UART_MSR_RI;
outb(0, iobase + UART_IER);
/* Initialize UART */ /* Turn on interrupts */
outb(UART_LCR_WLEN8, iobase + UART_LCR); /* Reset DLAB */ outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER);
outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase + UART_MCR);
info->ri_latch = inb(info->link.io.BasePort1 + UART_MSR) & UART_MSR_RI; spin_unlock_irqrestore(&(info->lock), flags);
/* Turn on interrupts */ /* Timeout before it is safe to send the first HCI packet */
outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER); 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 */ hdev = &(info->hdev);
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(HZ * 2);
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); if (hci_register_dev(hdev) < 0) {
printk(KERN_WARNING "dtl1_cs: Can't register HCI device %s.\n", hdev->name);
hdev->type = HCI_PCCARD; return -ENODEV;
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;
return 0;
} }
int dtl1_close(dtl1_info_t *info) { int dtl1_close(dtl1_info_t *info)
{
unsigned long flags; unsigned long flags;
unsigned int iobase = info->link.io.BasePort1; unsigned int iobase = info->link.io.BasePort1;
struct hci_dev *hdev = &(info->hdev); struct hci_dev *hdev = &(info->hdev);
dtl1_hci_close(hdev);
spin_lock_irqsave(&(info->lock), flags);
/* Reset UART */ dtl1_hci_close(hdev);
outb(0, iobase + UART_MCR);
/* Turn off interrupts */ spin_lock_irqsave(&(info->lock), flags);
outb(0, iobase + UART_IER);
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) spin_unlock_irqrestore(&(info->lock), flags);
printk(KERN_WARNING "dtl1_cs: Can't unregister HCI device %s.\n", hdev->name);
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) { ...@@ -611,291 +558,267 @@ int dtl1_close(dtl1_info_t *info) {
/* ======================== Card services ======================== */ /* ======================== Card services ======================== */
static void cs_error(client_handle_t handle, int func, int ret) { static void cs_error(client_handle_t handle, int func, int ret)
{
error_info_t err = { func, ret }; error_info_t err = { func, ret };
CardServices(ReportError, handle, &err);
CardServices(ReportError, handle, &err);
} }
dev_link_t *dtl1_attach(void) { dev_link_t *dtl1_attach(void)
{
dtl1_info_t *info; dtl1_info_t *info;
client_reg_t client_reg; client_reg_t client_reg;
dev_link_t *link; dev_link_t *link;
int i, ret; int i, ret;
/* Create new info device */
/* Create new info device */ info = kmalloc(sizeof(*info), GFP_KERNEL);
info = kmalloc(sizeof(*info), GFP_KERNEL); if (!info)
if (!info) return NULL;
return NULL; memset(info, 0, sizeof(*info));
memset(info, 0, sizeof(*info));
link = &info->link;
link->priv = info;
link = &info->link;
link->priv = info; link->release.function = &dtl1_release;
link->release.data = (u_long)link;
link->release.function = &dtl1_release; link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
link->release.data = (u_long)link; link->io.NumPorts1 = 8;
link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
link->io.NumPorts1 = 8; link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
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;
if (irq_list[0] == -1) else
link->irq.IRQInfo2 = irq_mask; for (i = 0; i < 4; i++)
else link->irq.IRQInfo2 |= 1 << irq_list[i];
for (i = 0; i < 4; i++)
link->irq.IRQInfo2 |= 1 << irq_list[i]; link->irq.Handler = dtl1_interrupt;
link->irq.Instance = info;
link->irq.Handler = dtl1_interrupt;
link->irq.Instance = info; link->conf.Attributes = CONF_ENABLE_IRQ;
link->conf.Vcc = 50;
link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.IntType = INT_MEMORY_AND_IO;
link->conf.Vcc = 50;
link->conf.IntType = INT_MEMORY_AND_IO; /* Register with Card Services */
link->next = dev_list;
dev_list = link;
/* Register with Card Services */ client_reg.dev_info = &dev_info;
link->next = dev_list; client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
dev_list = link; client_reg.EventMask =
client_reg.dev_info = &dev_info; CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
client_reg.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | client_reg.event_handler = &dtl1_event;
CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; client_reg.Version = 0x0210;
client_reg.event_handler = &dtl1_event; client_reg.event_callback_args.client_data = link;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link; ret = CardServices(RegisterClient, &link->handle, &client_reg);
if (ret != CS_SUCCESS) {
ret = CardServices(RegisterClient, &link->handle, &client_reg); cs_error(link->handle, RegisterClient, ret);
if (ret != CS_SUCCESS) { dtl1_detach(link);
cs_error(link->handle, RegisterClient, ret); return NULL;
dtl1_detach(link); }
return NULL;
} return link;
return link;
} }
void dtl1_detach(dev_link_t *link) { void dtl1_detach(dev_link_t *link)
{
dtl1_info_t *info = link->priv; dtl1_info_t *info = link->priv;
dev_link_t **linkp; dev_link_t **linkp;
int ret; int ret;
/* Locate device structure */
for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
if (*linkp == link)
break;
/* Locate device structure */ if (*linkp == NULL)
for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) return;
if (*linkp == link)
break;
if (*linkp == NULL) del_timer(&link->release);
return; 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); /* Unlink device structure, free bits */
if (link->state & DEV_CONFIG) *linkp = link->next;
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);
kfree(info);
} }
static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, cisparse_t *parse)
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); return CardServices(ParseTuple, handle, tuple, parse);
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 first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c)
#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c) #define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c)
void dtl1_config(dev_link_t *link) { void dtl1_config(dev_link_t *link)
{
client_handle_t handle = link->handle; client_handle_t handle = link->handle;
dtl1_info_t *info = link->priv; dtl1_info_t *info = link->priv;
tuple_t tuple; tuple_t tuple;
u_short buf[256]; u_short buf[256];
cisparse_t parse; cisparse_t parse;
cistpl_cftable_entry_t *cf = &parse.cftable_entry; cistpl_cftable_entry_t *cf = &parse.cftable_entry;
config_info_t config; config_info_t config;
int i, last_ret, last_fn; int i, last_ret, last_fn;
tuple.TupleData = (cisdata_t *)buf;
tuple.TupleData = (cisdata_t *)buf; tuple.TupleOffset = 0;
tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
tuple.TupleDataMax = 255; tuple.Attributes = 0;
tuple.Attributes = 0;
/* Get configuration register information */
/* Get configuration register information */ tuple.DesiredTuple = CISTPL_CONFIG;
tuple.DesiredTuple = CISTPL_CONFIG; last_ret = first_tuple(handle, &tuple, &parse);
last_ret = first_tuple(handle, &tuple, &parse); if (last_ret != CS_SUCCESS) {
if (last_ret != CS_SUCCESS) { last_fn = ParseTuple;
last_fn = ParseTuple; goto cs_failed;
goto cs_failed; }
} link->conf.ConfigBase = parse.config.base;
link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0];
link->conf.Present = parse.config.rmask[0];
/* Configure card */
link->state |= DEV_CONFIG;
/* Configure card */ i = CardServices(GetConfigurationInfo, handle, &config);
link->state |= DEV_CONFIG; link->conf.Vcc = config.Vcc;
i = CardServices(GetConfigurationInfo, handle, &config);
link->conf.Vcc = config.Vcc; tuple.TupleData = (cisdata_t *)buf;
tuple.TupleOffset = 0;
tuple.TupleData = (cisdata_t *)buf; tuple.TupleDataMax = 255;
tuple.TupleOffset = 0; tuple.TupleDataMax = 255; tuple.Attributes = 0;
tuple.Attributes = 0; tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
/* Look for a generic full-sized window */
/* Look for a generic full-sized window */ link->io.NumPorts1 = 8;
link->io.NumPorts1 = 8; i = first_tuple(handle, &tuple, &parse);
i = first_tuple(handle, &tuple, &parse); while (i != CS_NO_MORE_ITEMS) {
while (i != CS_NO_MORE_ITEMS) { if ((i == CS_SUCCESS) && (cf->io.nwin == 1) && (cf->io.win[0].len > 8)) {
if ((i == CS_SUCCESS) && (cf->io.nwin == 1) && (cf->io.win[0].len > 8)) { link->conf.ConfigIndex = cf->index;
link->conf.ConfigIndex = cf->index; link->io.BasePort1 = cf->io.win[0].base;
link->io.BasePort1 = cf->io.win[0].base; link->io.NumPorts1 = cf->io.win[0].len; /*yo */
link->io.NumPorts1 = cf->io.win[0].len; /*yo*/ link->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK;
link->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK; i = CardServices(RequestIO, link->handle, &link->io);
i = CardServices(RequestIO, link->handle, &link->io); if (i == CS_SUCCESS)
if (i == CS_SUCCESS) break;
break; }
} i = next_tuple(handle, &tuple, &parse);
i = next_tuple(handle, &tuple, &parse); }
}
if (i != CS_SUCCESS) {
if (i != CS_SUCCESS) { cs_error(link->handle, RequestIO, i);
cs_error(link->handle, RequestIO, i); goto failed;
goto failed; }
}
i = CardServices(RequestIRQ, link->handle, &link->irq);
i = CardServices(RequestIRQ, link->handle, &link->irq); if (i != CS_SUCCESS) {
if (i != CS_SUCCESS) { cs_error(link->handle, RequestIRQ, i);
cs_error(link->handle, RequestIRQ, i); link->irq.AssignedIRQ = 0;
link->irq.AssignedIRQ = 0; }
}
i = CardServices(RequestConfiguration, link->handle, &link->conf);
i = CardServices(RequestConfiguration, link->handle, &link->conf); if (i != CS_SUCCESS) {
if (i != CS_SUCCESS) { cs_error(link->handle, RequestConfiguration, i);
cs_error(link->handle, RequestConfiguration, i); goto failed;
goto failed; }
}
MOD_INC_USE_COUNT;
MOD_INC_USE_COUNT; if (dtl1_open(info) != 0)
goto failed;
if (dtl1_open(info) != 0)
goto failed; strcpy(info->node.dev_name, info->hdev.name);
link->dev = &info->node;
link->state &= ~DEV_CONFIG_PENDING;
link->dev = &info->node;
link->state &= ~DEV_CONFIG_PENDING; return;
return;
cs_failed: cs_failed:
cs_error(link->handle, last_fn, last_ret); cs_error(link->handle, last_fn, last_ret);
failed:
dtl1_release((u_long)link);
failed:
dtl1_release((u_long)link);
} }
void dtl1_release(u_long arg) { void dtl1_release(u_long arg)
{
dev_link_t *link = (dev_link_t *)arg; dev_link_t *link = (dev_link_t *)arg;
dtl1_info_t *info = link->priv; dtl1_info_t *info = link->priv;
if (link->state & DEV_PRESENT)
dtl1_close(info);
if (link->state & DEV_PRESENT) MOD_DEC_USE_COUNT;
dtl1_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->dev = NULL; link->state &= ~DEV_CONFIG;
CardServices(ReleaseConfiguration, link->handle);
CardServices(ReleaseIO, link->handle, &link->io);
CardServices(ReleaseIRQ, link->handle, &link->irq);
link->state &= ~DEV_CONFIG;
} }
int dtl1_event(event_t event, int priority, event_callback_args_t *args) { int dtl1_event(event_t event, int priority, event_callback_args_t *args)
{
dev_link_t *link = args->client_data; dev_link_t *link = args->client_data;
dtl1_info_t *info = link->priv; dtl1_info_t *info = link->priv;
switch (event) {
switch (event) { case CS_EVENT_CARD_REMOVAL:
case CS_EVENT_CARD_REMOVAL: link->state &= ~DEV_PRESENT;
link->state &= ~DEV_PRESENT; if (link->state & DEV_CONFIG) {
if (link->state & DEV_CONFIG) { dtl1_close(info);
dtl1_close(info); mod_timer(&link->release, jiffies + HZ / 20);
mod_timer(&link->release, jiffies + HZ/20); }
} break;
break; case CS_EVENT_CARD_INSERTION:
case CS_EVENT_CARD_INSERTION: link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; dtl1_config(link);
dtl1_config(link); break;
break; case CS_EVENT_PM_SUSPEND:
case CS_EVENT_PM_SUSPEND: link->state |= DEV_SUSPEND;
link->state |= DEV_SUSPEND; /* Fall through... */
/* Fall through... */ case CS_EVENT_RESET_PHYSICAL:
case CS_EVENT_RESET_PHYSICAL: if (link->state & DEV_CONFIG)
if (link->state & DEV_CONFIG) CardServices(ReleaseConfiguration, link->handle);
CardServices(ReleaseConfiguration, link->handle); break;
break; case CS_EVENT_PM_RESUME:
case CS_EVENT_PM_RESUME: link->state &= ~DEV_SUSPEND;
link->state &= ~DEV_SUSPEND; /* Fall through... */
/* Fall through... */ case CS_EVENT_CARD_RESET:
case CS_EVENT_CARD_RESET: if (DEV_OK(link))
if (DEV_OK(link)) CardServices(RequestConfiguration, link->handle, &link->conf);
CardServices(RequestConfiguration, link->handle, &link->conf); break;
break; }
}
return 0;
return 0;
} }
...@@ -903,33 +826,29 @@ int dtl1_event(event_t event, int priority, event_callback_args_t *args) { ...@@ -903,33 +826,29 @@ int dtl1_event(event_t event, int priority, event_callback_args_t *args) {
/* ======================== Module initialization ======================== */ /* ======================== Module initialization ======================== */
int __init init_dtl1_cs(void) { int __init init_dtl1_cs(void)
{
servinfo_t serv; servinfo_t serv;
int err; 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); err = register_pccard_driver(&dev_info, &dtl1_attach, &dtl1_detach);
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;
return err;
} }
void __exit exit_dtl1_cs(void) {
unregister_pccard_driver(&dev_info);
while (dev_list != NULL) void __exit exit_dtl1_cs(void)
dtl1_detach(dev_list); {
unregister_pccard_driver(&dev_info);
while (dev_list != NULL)
dtl1_detach(dev_list);
} }
......
...@@ -107,13 +107,14 @@ static inline void out_reg(u8 data, u8 reg) ...@@ -107,13 +107,14 @@ static inline void out_reg(u8 data, u8 reg)
* Set PIO mode for the specified drive. * Set PIO mode for the specified drive.
* This function computes timing parameters * This function computes timing parameters
* and sets controller registers accordingly. * 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) static void ali14xx_tune_drive(struct ata_device *drive, u8 pio)
{ {
int drive_num; int drive_num;
int time1, time2; int time1, time2;
u8 param1, param2, param3, param4; u8 param1, param2, param3, param4;
unsigned long flags;
struct ata_timing *t; struct ata_timing *t;
if (pio == 255) if (pio == 255)
...@@ -140,15 +141,12 @@ static void ali14xx_tune_drive(struct ata_device *drive, u8 pio) ...@@ -140,15 +141,12 @@ static void ali14xx_tune_drive(struct ata_device *drive, u8 pio)
/* stuff timing parameters into controller registers */ /* stuff timing parameters into controller registers */
drive_num = (drive->channel->index << 1) + drive->select.b.unit; drive_num = (drive->channel->index << 1) + drive->select.b.unit;
save_flags(flags); /* all CPUs */
cli(); /* all CPUs */
outb_p(reg_on, base_port); outb_p(reg_on, base_port);
out_reg(param1, reg_tab[drive_num].reg1); out_reg(param1, reg_tab[drive_num].reg1);
out_reg(param2, reg_tab[drive_num].reg2); out_reg(param2, reg_tab[drive_num].reg2);
out_reg(param3, reg_tab[drive_num].reg3); out_reg(param3, reg_tab[drive_num].reg3);
out_reg(param4, reg_tab[drive_num].reg4); out_reg(param4, reg_tab[drive_num].reg4);
outb_p(reg_off, base_port); outb_p(reg_off, base_port);
restore_flags(flags); /* all CPUs */
} }
/* /*
......
...@@ -218,6 +218,7 @@ static unsigned int __init pci_init_cs5530(struct pci_dev *dev) ...@@ -218,6 +218,7 @@ static unsigned int __init pci_init_cs5530(struct pci_dev *dev)
} }
} }
} }
if (!master_0) { if (!master_0) {
printk("%s: unable to locate PCI MASTER function\n", dev->name); printk("%s: unable to locate PCI MASTER function\n", dev->name);
return 0; return 0;
...@@ -227,15 +228,13 @@ static unsigned int __init pci_init_cs5530(struct pci_dev *dev) ...@@ -227,15 +228,13 @@ static unsigned int __init pci_init_cs5530(struct pci_dev *dev)
return 0; return 0;
} }
save_flags(flags);
cli(); /* all CPUs (there should only be one CPU with this chipset) */
/* /*
* Enable BusMaster and MemoryWriteAndInvalidate for the cs5530: * Enable BusMaster and MemoryWriteAndInvalidate for the cs5530:
* --> OR 0x14 into 16-bit PCI COMMAND reg of function 0 of 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: * Set PCI CacheLineSize to 16-bytes:
...@@ -274,8 +273,6 @@ static unsigned int __init pci_init_cs5530(struct pci_dev *dev) ...@@ -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, 0x42, 0x00);
pci_write_config_byte(master_0, 0x43, 0xc1); pci_write_config_byte(master_0, 0x43, 0xc1);
restore_flags(flags);
return 0; return 0;
} }
......
...@@ -66,21 +66,18 @@ static void sub22 (char b, char 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) 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; pio = ata_timing_mode(drive, XFER_PIO | XFER_EPIO) - XFER_PIO_0;
if (pio >= 3) { if (pio >= 3) {
save_flags(flags); /* all CPUs */
cli(); /* all CPUs */
/* /*
* This enables PIO mode4 (3?) on the first interface * This enables PIO mode4 (3?) on the first interface
*/ */
sub22(1,0xc3); sub22(1,0xc3);
sub22(0,0xa0); sub22(0,0xa0);
restore_flags(flags); /* all CPUs */
} else { } else {
/* we don't know how to set it back again.. */ /* we don't know how to set it back again.. */
} }
......
/* /*
* linux/drivers/ide/hd.c
*
* Copyright (C) 1991, 1992 Linus Torvalds * Copyright (C) 1991, 1992 Linus Torvalds
*/ *
/*
* This is the low-level hd interrupt support. It traverses the * This is the low-level hd interrupt support. It traverses the
* request-list, using interrupts to jump between functions. As * request-list, using interrupts to jump between functions. As
* all the functions are called within interrupts, we may not * all the functions are called within interrupts, we may not
* sleep. Special care is recommended. * sleep. Special care is recommended.
* *
* modified by Drew Eckhardt to check nr of hd's from the CMOS. * 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 * Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug
...@@ -26,10 +22,10 @@ ...@@ -26,10 +22,10 @@
* Bugfix: max_sectors must be <= 255 or the wheels tend to come * 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 * off in a hurry once you queue things up - Paul G. 02/2001
*/ */
/* Uncomment the following if you want verbose error reports. */ /* Uncomment the following if you want verbose error reports. */
/* #define VERBOSE_ERRORS */ /* #define VERBOSE_ERRORS */
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/signal.h> #include <linux/signal.h>
#include <linux/sched.h> #include <linux/sched.h>
...@@ -37,7 +33,6 @@ ...@@ -37,7 +33,6 @@
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/devfs_fs_kernel.h> #include <linux/devfs_fs_kernel.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/hdreg.h>
#include <linux/genhd.h> #include <linux/genhd.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/string.h> #include <linux/string.h>
...@@ -45,6 +40,7 @@ ...@@ -45,6 +40,7 @@
#include <linux/mc146818rtc.h> /* CMOS defines */ #include <linux/mc146818rtc.h> /* CMOS defines */
#include <linux/init.h> #include <linux/init.h>
#include <linux/blkpg.h> #include <linux/blkpg.h>
#include <linux/hdreg.h>
#define REALLY_SLOW_IO #define REALLY_SLOW_IO
#include <asm/system.h> #include <asm/system.h>
...@@ -55,6 +51,15 @@ ...@@ -55,6 +51,15 @@
#define DEVICE_NR(device) (minor(device)>>6) #define DEVICE_NR(device) (minor(device)>>6)
#include <linux/blk.h> #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__ #ifdef __arm__
#undef HD_IRQ #undef HD_IRQ
#endif #endif
...@@ -63,6 +68,45 @@ ...@@ -63,6 +68,45 @@
#define HD_IRQ IRQ_HARDDISK #define HD_IRQ IRQ_HARDDISK
#endif #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 spinlock_t hd_lock = SPIN_LOCK_UNLOCKED;
static int revalidate_hddisk(kdev_t, int); static int revalidate_hddisk(kdev_t, int);
...@@ -162,12 +206,9 @@ void __init hd_setup(char *str, int *ints) ...@@ -162,12 +206,9 @@ void __init hd_setup(char *str, int *ints)
static void dump_status (const char *msg, unsigned int stat) static void dump_status (const char *msg, unsigned int stat)
{ {
unsigned long flags;
char devc; char devc;
devc = !blk_queue_empty(QUEUE) ? 'a' + DEVICE_NR(CURRENT->rq_dev) : '?'; devc = !blk_queue_empty(QUEUE) ? 'a' + DEVICE_NR(CURRENT->rq_dev) : '?';
save_flags (flags);
sti();
#ifdef VERBOSE_ERRORS #ifdef VERBOSE_ERRORS
printk("hd%c: %s: status=0x%02x { ", devc, msg, stat & 0xff); printk("hd%c: %s: status=0x%02x { ", devc, msg, stat & 0xff);
if (stat & BUSY_STAT) printk("Busy "); if (stat & BUSY_STAT) printk("Busy ");
...@@ -207,8 +248,7 @@ static void dump_status (const char *msg, unsigned int stat) ...@@ -207,8 +248,7 @@ static void dump_status (const char *msg, unsigned int stat)
hd_error = inb(HD_ERROR); hd_error = inb(HD_ERROR);
printk("hd%c: %s: error=0x%02x.\n", devc, msg, hd_error & 0xff); printk("hd%c: %s: error=0x%02x.\n", devc, msg, hd_error & 0xff);
} }
#endif /* verbose errors */ #endif
restore_flags (flags);
} }
void check_status(void) void check_status(void)
...@@ -467,7 +507,7 @@ static void write_intr(void) ...@@ -467,7 +507,7 @@ static void write_intr(void)
if (i > 0) { if (i > 0) {
SET_HANDLER(&write_intr); SET_HANDLER(&write_intr);
outsw(HD_DATA,CURRENT->buffer,256); outsw(HD_DATA,CURRENT->buffer,256);
sti(); local_irq_enable();
} else { } else {
#if (HD_DELAY > 0) #if (HD_DELAY > 0)
last_req = read_timer(); last_req = read_timer();
...@@ -500,7 +540,7 @@ static void hd_times_out(unsigned long dummy) ...@@ -500,7 +540,7 @@ static void hd_times_out(unsigned long dummy)
return; return;
disable_irq(HD_IRQ); disable_irq(HD_IRQ);
sti(); local_irq_enable();
reset = 1; reset = 1;
dev = DEVICE_NR(CURRENT->rq_dev); dev = DEVICE_NR(CURRENT->rq_dev);
printk("hd%c: timeout\n", dev+'a'); printk("hd%c: timeout\n", dev+'a');
...@@ -510,7 +550,7 @@ static void hd_times_out(unsigned long dummy) ...@@ -510,7 +550,7 @@ static void hd_times_out(unsigned long dummy)
#endif #endif
end_request(CURRENT, 0); end_request(CURRENT, 0);
} }
cli(); local_irq_disable();
hd_request(); hd_request();
enable_irq(HD_IRQ); enable_irq(HD_IRQ);
} }
...@@ -548,7 +588,7 @@ static void hd_request(void) ...@@ -548,7 +588,7 @@ static void hd_request(void)
return; return;
repeat: repeat:
del_timer(&device_timer); del_timer(&device_timer);
sti(); local_irq_enable();
if (blk_queue_empty(QUEUE)) { if (blk_queue_empty(QUEUE)) {
do_hd = NULL; do_hd = NULL;
...@@ -556,7 +596,7 @@ static void hd_request(void) ...@@ -556,7 +596,7 @@ static void hd_request(void)
} }
if (reset) { if (reset) {
cli(); local_irq_disable();
reset_hd(); reset_hd();
return; return;
} }
...@@ -688,7 +728,7 @@ static void hd_interrupt(int irq, void *dev_id, struct pt_regs *regs) ...@@ -688,7 +728,7 @@ static void hd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
if (!handler) if (!handler)
handler = unexpected_hd_interrupt; handler = unexpected_hd_interrupt;
handler(); handler();
sti(); local_irq_enable();
} }
static struct block_device_operations hd_fops = { static struct block_device_operations hd_fops = {
......
...@@ -249,12 +249,8 @@ static u8 ht_pio2timings(struct ata_device *drive, u8 pio) ...@@ -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) static void ht_set_prefetch(struct ata_device *drive, u8 state)
{ {
unsigned long flags;
int t = HT_PREFETCH_MODE << 8; int t = HT_PREFETCH_MODE << 8;
save_flags (flags); /* all CPUs */
cli(); /* all CPUs */
/* /*
* Prefetch mode and unmask irq seems to conflict * Prefetch mode and unmask irq seems to conflict
*/ */
...@@ -267,16 +263,16 @@ static void ht_set_prefetch(struct ata_device *drive, u8 state) ...@@ -267,16 +263,16 @@ static void ht_set_prefetch(struct ata_device *drive, u8 state)
drive->channel->no_unmask = 0; drive->channel->no_unmask = 0;
} }
restore_flags (flags); /* all CPUs */
#ifdef DEBUG #ifdef DEBUG
printk("ht6560b: drive %s prefetch mode %sabled\n", drive->name, (state ? "en" : "dis")); printk("ht6560b: drive %s prefetch mode %sabled\n", drive->name, (state ? "en" : "dis"));
#endif #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) static void tune_ht6560b(struct ata_device *drive, u8 pio)
{ {
unsigned long flags;
u8 timing; u8 timing;
switch (pio) { switch (pio) {
...@@ -288,14 +284,9 @@ static void tune_ht6560b(struct ata_device *drive, u8 pio) ...@@ -288,14 +284,9 @@ static void tune_ht6560b(struct ata_device *drive, u8 pio)
timing = ht_pio2timings(drive, pio); timing = ht_pio2timings(drive, pio);
save_flags (flags); /* all CPUs */
cli(); /* all CPUs */
drive->drive_data &= 0xff00; drive->drive_data &= 0xff00;
drive->drive_data |= timing; drive->drive_data |= timing;
restore_flags (flags); /* all CPUs */
#ifdef DEBUG #ifdef DEBUG
printk("ht6560b: drive %s tuned to pio mode %#x timing=%#x\n", drive->name, pio, timing); printk("ht6560b: drive %s tuned to pio mode %#x timing=%#x\n", drive->name, pio, timing);
#endif #endif
......
...@@ -305,8 +305,9 @@ ...@@ -305,8 +305,9 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/cdrom.h> #include <linux/cdrom.h>
#include <linux/ide.h>
#include <linux/completion.h> #include <linux/completion.h>
#include <linux/hdreg.h>
#include <linux/ide.h>
#include <asm/irq.h> #include <asm/irq.h>
#include <asm/io.h> #include <asm/io.h>
...@@ -2914,7 +2915,7 @@ int ide_cdrom_cleanup(struct ata_device *drive) ...@@ -2914,7 +2915,7 @@ int ide_cdrom_cleanup(struct ata_device *drive)
struct cdrom_info *info = drive->driver_data; struct cdrom_info *info = drive->driver_data;
struct cdrom_device_info *devinfo = &info->devinfo; struct cdrom_device_info *devinfo = &info->devinfo;
if (ide_unregister_subdriver (drive)) if (ata_unregister_device(drive))
return 1; return 1;
if (info->buffer != NULL) if (info->buffer != NULL)
kfree(info->buffer); kfree(info->buffer);
...@@ -2973,7 +2974,7 @@ static void ide_cdrom_attach(struct ata_device *drive) ...@@ -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); printk(KERN_ERR "%s: Can't allocate a cdrom structure\n", drive->name);
return; 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); printk(KERN_ERR "%s: Failed to register the driver with ide.c\n", drive->name);
kfree (info); kfree (info);
return; return;
......
...@@ -1279,7 +1279,7 @@ static int idedisk_cleanup(struct ata_device *drive) ...@@ -1279,7 +1279,7 @@ static int idedisk_cleanup(struct ata_device *drive)
printk (KERN_INFO "%s: Write Cache FAILED Flushing!\n", printk (KERN_INFO "%s: Write Cache FAILED Flushing!\n",
drive->name); 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 /* FIXME: This is killing the kernel with BUG 185 at asm/spinlocks.h
* horribly. Check whatever we did REGISTER the device properly * horribly. Check whatever we did REGISTER the device properly
...@@ -1471,8 +1471,8 @@ static void idedisk_attach(struct ata_device *drive) ...@@ -1471,8 +1471,8 @@ static void idedisk_attach(struct ata_device *drive)
if (req[0] != '\0' && strcmp(req, "ide-disk")) if (req[0] != '\0' && strcmp(req, "ide-disk"))
return; return;
if (ide_register_subdriver(drive, &idedisk_driver)) { if (ata_register_device(drive, &idedisk_driver)) {
printk (KERN_ERR "ide-disk: %s: Failed to register the driver with ide.c\n", drive->name); printk(KERN_ERR "%s: Failed to register the driver with ide.c\n", drive->name);
return; return;
} }
......
...@@ -94,9 +94,10 @@ ...@@ -94,9 +94,10 @@
#include <linux/genhd.h> #include <linux/genhd.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/cdrom.h> #include <linux/cdrom.h>
#include <linux/buffer_head.h>
#include <linux/hdreg.h>
#include <linux/ide.h> #include <linux/ide.h>
#include <linux/atapi.h> #include <linux/atapi.h>
#include <linux/buffer_head.h>
#include <asm/byteorder.h> #include <asm/byteorder.h>
#include <asm/irq.h> #include <asm/irq.h>
...@@ -1722,10 +1723,10 @@ static int idefloppy_cleanup(struct ata_device *drive) ...@@ -1722,10 +1723,10 @@ static int idefloppy_cleanup(struct ata_device *drive)
{ {
idefloppy_floppy_t *floppy = drive->driver_data; idefloppy_floppy_t *floppy = drive->driver_data;
if (ide_unregister_subdriver (drive)) if (ata_unregister_device(drive))
return 1; return 1;
drive->driver_data = NULL; drive->driver_data = NULL;
kfree (floppy); kfree(floppy);
return 0; return 0;
} }
...@@ -1779,7 +1780,7 @@ static void idefloppy_attach(struct ata_device *drive) ...@@ -1779,7 +1780,7 @@ static void idefloppy_attach(struct ata_device *drive)
drive->name); drive->name);
return; 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); printk(KERN_ERR "ide-floppy: %s: Failed to register the driver with ide.c\n", drive->name);
kfree (floppy); kfree (floppy);
return; return;
......
...@@ -550,7 +550,8 @@ static void __init hpt374_device_order_fixup (struct pci_dev *dev, struct ata_pc ...@@ -550,7 +550,8 @@ static void __init hpt374_device_order_fixup (struct pci_dev *dev, struct ata_pc
if (!dev2) { if (!dev2) {
return; return;
} else { } 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(dev, PCI_INTERRUPT_LINE, &irq);
pci_read_config_byte(dev2, PCI_INTERRUPT_LINE, &irq2); pci_read_config_byte(dev2, PCI_INTERRUPT_LINE, &irq2);
if (irq != irq2) { if (irq != irq2) {
......
...@@ -7,401 +7,18 @@ ...@@ -7,401 +7,18 @@
* *
* It is hereby placed under the terms of the GNU general public license. * It is hereby placed under the terms of the GNU general public license.
* (See linux/COPYING). * (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 * Contributors:
* 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.
* *
* You can enable/disable/tune the pipelined operation mode by adjusting * Oct 1999 Arnold Niessen, <niessen@iae.nl>, <arnold.niessen@philips.com>
* the compile time parameters below. * Nov 2000, Jan 2001 Marcel Mol, <marcel@mesa.nl>
* Apr 2001 Willem Riede, <osst@riede.org>
*/ */
/* /*
* Possible improvements. * FIXME: clean tape->spinlock locking --bzolnier
*
* 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.
*/ */
#define IDETAPE_VERSION "1.17a"
#include <linux/config.h> #include <linux/config.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/types.h> #include <linux/types.h>
...@@ -419,9 +36,10 @@ ...@@ -419,9 +36,10 @@
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <linux/completion.h> #include <linux/completion.h>
#include <linux/buffer_head.h>
#include <linux/hdreg.h>
#include <linux/ide.h> #include <linux/ide.h>
#include <linux/atapi.h> #include <linux/atapi.h>
#include <linux/buffer_head.h>
#include <asm/byteorder.h> #include <asm/byteorder.h>
#include <asm/irq.h> #include <asm/irq.h>
...@@ -445,6 +63,7 @@ ...@@ -445,6 +63,7 @@
#define OS_DATA_STARTFRAME1 20 #define OS_DATA_STARTFRAME1 20
#define OS_DATA_ENDFRAME1 2980 #define OS_DATA_ENDFRAME1 2980
/* /*
* partition * partition
*/ */
...@@ -1249,7 +868,7 @@ char *idetape_sense_key_verbose(u8 idetape_sense_key) ...@@ -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) { switch (idetape_command_key) {
case IDETAPE_TEST_UNIT_READY_CMD: return("TEST_UNIT_READY_CMD"); 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_ ...@@ -1439,7 +1058,7 @@ static void idetape_analyze_error(struct ata_device *drive, atapi_request_sense_
# if IDETAPE_DEBUG_LOG_VERBOSE # if IDETAPE_DEBUG_LOG_VERBOSE
if (tape->debug_level >= 1) if (tape->debug_level >= 1)
printk (KERN_INFO "ide-tape: pc = %s, sense key = %x, asc = %x, ascq = %x\n", 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->sense_key,
result->asc, result->asc,
result->ascq); result->ascq);
...@@ -2166,7 +1785,7 @@ static void idetape_pc_callback(struct ata_device *drive, struct request *rq) ...@@ -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. * 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); atapi_init_pc(pc);
pc->c[0] = IDETAPE_MODE_SENSE_CMD; pc->c[0] = IDETAPE_MODE_SENSE_CMD;
...@@ -3225,7 +2844,7 @@ static int __idetape_discard_read_pipeline(struct ata_device *drive) ...@@ -3225,7 +2844,7 @@ static int __idetape_discard_read_pipeline(struct ata_device *drive)
* of the request queue and wait for their completion. * 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; idetape_tape_t *tape = drive->driver_data;
int retval; int retval;
...@@ -3981,7 +3600,7 @@ static int idetape_add_chrdev_read_request(struct ata_device *drive,int blocks) ...@@ -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"); printk (KERN_ERR "ide-tape: bug: trying to return more bytes than requested\n");
bytes_read=blocks*tape->tape_block_size; bytes_read=blocks*tape->tape_block_size;
} }
#endif /* IDETAPE_DEBUG_BUGS */ #endif
return (bytes_read); return (bytes_read);
} }
...@@ -5892,18 +5511,17 @@ static int idetape_cleanup(struct ata_device *drive) ...@@ -5892,18 +5511,17 @@ static int idetape_cleanup(struct ata_device *drive)
int minor = tape->minor; int minor = tape->minor;
unsigned long flags; unsigned long flags;
save_flags (flags); /* all CPUs (overkill?) */ spin_lock_irqsave (&tape->spinlock, flags); /* overkill? */
cli(); /* all CPUs (overkill?) */
if (test_bit (IDETAPE_BUSY, &tape->flags) || tape->first_stage != NULL || tape->merge_stage_size || drive->usage) { 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; return 1;
} }
idetape_chrdevs[minor].drive = NULL; idetape_chrdevs[minor].drive = NULL;
restore_flags (flags); /* all CPUs (overkill?) */ spin_unlock_irqrestore(&tape->spinlock, flags);
MOD_DEC_USE_COUNT; MOD_DEC_USE_COUNT;
ide_unregister_subdriver (drive); ata_unregister_device(drive);
drive->driver_data = NULL; drive->driver_data = NULL;
devfs_unregister (tape->de_r); devfs_unregister (tape->de_r);
devfs_unregister (tape->de_n); devfs_unregister (tape->de_n);
...@@ -5992,11 +5610,11 @@ static void idetape_attach(struct ata_device *drive) ...@@ -5992,11 +5610,11 @@ static void idetape_attach(struct ata_device *drive)
} }
tape = (idetape_tape_t *) kmalloc (sizeof (idetape_tape_t), GFP_KERNEL); tape = (idetape_tape_t *) kmalloc (sizeof (idetape_tape_t), GFP_KERNEL);
if (!tape) { 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; return;
} }
if (ide_register_subdriver (drive, &idetape_driver)) { if (ata_register_device(drive, &idetape_driver)) {
printk (KERN_ERR "ide-tape: %s: Failed to register the driver with ide.c\n", drive->name); printk(KERN_ERR "ide-tape: %s: Failed to register the driver with ide.c\n", drive->name);
kfree (tape); kfree (tape);
return; return;
} }
......
...@@ -33,6 +33,15 @@ ...@@ -33,6 +33,15 @@
#include "ioctl.h" #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 * Implement generic ioctls invoked from userspace to imlpement specific
* functionality. * functionality.
......
...@@ -89,10 +89,7 @@ static void it8172_tune_drive (struct ata_device *drive, u8 pio) ...@@ -89,10 +89,7 @@ static void it8172_tune_drive (struct ata_device *drive, u8 pio)
drive_enables |= 0x0006; drive_enables |= 0x0006;
} }
save_flags(flags);
cli();
pci_write_config_word(dev, master_port, master_data); pci_write_config_word(dev, master_port, master_data);
restore_flags(flags);
} }
#if defined(CONFIG_BLK_DEV_IDEDMA) && defined(CONFIG_IT8172_TUNING) #if defined(CONFIG_BLK_DEV_IDEDMA) && defined(CONFIG_IT8172_TUNING)
......
...@@ -191,7 +191,11 @@ static void init_hwif_data(struct ata_channel *ch, unsigned int index) ...@@ -191,7 +191,11 @@ static void init_hwif_data(struct ata_channel *ch, unsigned int index)
ch->noprobe = !ch->io_ports[IDE_DATA_OFFSET]; ch->noprobe = !ch->io_ports[IDE_DATA_OFFSET];
#ifdef CONFIG_BLK_DEV_HD #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() */ ch->noprobe = 1; /* may be overridden by ide_setup() */
#endif #endif
...@@ -361,7 +365,7 @@ void ide_unregister(struct ata_channel *ch) ...@@ -361,7 +365,7 @@ void ide_unregister(struct ata_channel *ch)
if (ata_ops(drive)->cleanup(drive)) if (ata_ops(drive)->cleanup(drive))
goto abort; goto abort;
} else } else
ide_unregister_subdriver(drive); ata_unregister_device(drive);
} }
} }
ch->present = 0; ch->present = 0;
...@@ -701,79 +705,46 @@ static void __init init_global_data(void) ...@@ -701,79 +705,46 @@ static void __init init_global_data(void)
/* /*
* This gets called VERY EARLY during initialization, to handle kernel "command * This gets called VERY EARLY during initialization, to handle kernel "command
* line" strings beginning with "hdx=" or "ide".It gets called even before the * line" strings beginning with "hdx=". It gets called even before the actual
* actual module gets initialized. * module gets initialized.
* *
* Please look at Documentation/ide.txt to see the complete list of supported * Please look at Documentation/ide.txt to see the complete list of supported
* options. * options.
*/ */
int __init ide_setup(char *s) static int __init ata_hd_setup(char *s)
{ {
int i, vals[4]; int vals[4];
struct ata_channel *ch; struct ata_channel *ch; /* FIXME: Channel parms should not be accessed in ata_hd_setup */
struct ata_device *drive; struct ata_device *drive;
unsigned int hw, unit; unsigned int hw, unit;
const char max_drive = 'a' + ((MAX_HWIFS * MAX_DRIVES) - 1); 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; return 0;
if (strncmp(s,"ide",3) && printk(KERN_INFO "hd%s", s);
strncmp(s,"hd",2)) /* hdx= & hdxlun= */
return 0;
printk(KERN_INFO "ide_setup: %s", s);
init_global_data(); init_global_data();
#ifdef CONFIG_BLK_DEV_IDEDOUBLER if (s[0] >= 'a' && s[0] <= max_drive) {
if (!strcmp(s, "ide=doubler")) { static const char *hd_words[] = {"none", "noprobe", "nowerr", "cdrom",
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",
"serialize", "autotune", "noautotune", "serialize", "autotune", "noautotune",
"slow", "flash", "remap", "noremap", "scsi", NULL}; "slow", "flash", "remap", "noremap", "scsi", NULL};
unit = s[2] - 'a'; unit = s[0] - 'a';
hw = unit / MAX_DRIVES; hw = unit / MAX_DRIVES;
unit = unit % MAX_DRIVES; unit = unit % MAX_DRIVES;
ch = &ide_hwifs[hw]; ch = &ide_hwifs[hw];
drive = &ch->drives[unit]; 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; goto done;
} }
/* /*
* Look for last lun option: "hdxlun=" * Look for last lun option: "hdxlun="
*/ */
if (!strncmp(s+3, "lun=", 4)) { if (!strncmp(s+1, "lun=", 4)) {
if (*get_options(s+7, 2, vals) || vals[0]!=1) if (*get_options(s+5, 2, vals) || vals[0]!=1)
goto bad_option; goto bad_option;
if (vals[1] >= 0 && vals[1] <= 7) { if (vals[1] >= 0 && vals[1] <= 7) {
drive->last_lun = vals[1]; drive->last_lun = vals[1];
...@@ -782,7 +753,7 @@ int __init ide_setup(char *s) ...@@ -782,7 +753,7 @@ int __init ide_setup(char *s)
printk(" -- BAD LAST LUN! Expected value from 0 to 7"); printk(" -- BAD LAST LUN! Expected value from 0 to 7");
goto done; goto done;
} }
switch (match_parm(s+3, hd_words, vals, 3)) { switch (match_parm(s+1, hd_words, vals, 3)) {
case -1: /* "none" */ case -1: /* "none" */
drive->nobios = 1; /* drop into "noprobe" */ drive->nobios = 1; /* drop into "noprobe" */
case -2: /* "noprobe" */ case -2: /* "noprobe" */
...@@ -790,16 +761,16 @@ int __init ide_setup(char *s) ...@@ -790,16 +761,16 @@ int __init ide_setup(char *s)
goto done; goto done;
case -3: /* "nowerr" */ case -3: /* "nowerr" */
drive->bad_wstat = BAD_R_STAT; drive->bad_wstat = BAD_R_STAT;
ch->noprobe = 0; ch->noprobe = 0; /* FIXME: Channel parm */
goto done; goto done;
case -4: /* "cdrom" */ case -4: /* "cdrom" */
drive->present = 1; drive->present = 1;
drive->type = ATA_ROM; drive->type = ATA_ROM;
ch->noprobe = 0; ch->noprobe = 0; /* FIXME: Channel parm */
goto done; goto done;
case -5: /* "serialize" */ case -5: /* "serialize" */
printk(" -- USE \"ide%d=serialize\" INSTEAD", hw); printk(" -- USE \"ide%d=serialize\" INSTEAD", hw);
goto do_serialize; goto bad_option;
case -6: /* "autotune" */ case -6: /* "autotune" */
drive->autotune = 1; drive->autotune = 1;
goto done; goto done;
...@@ -807,7 +778,7 @@ int __init ide_setup(char *s) ...@@ -807,7 +778,7 @@ int __init ide_setup(char *s)
drive->autotune = 2; drive->autotune = 2;
goto done; goto done;
case -8: /* "slow" */ case -8: /* "slow" */
ch->slow = 1; ch->slow = 1; /* FIXME: Channel parm */
goto done; goto done;
case -9: /* "flash" */ case -9: /* "flash" */
drive->ata_flash = 1; drive->ata_flash = 1;
...@@ -840,11 +811,63 @@ int __init ide_setup(char *s) ...@@ -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=" * Look for bus speed option: "idebus="
*/ */
if (!strncmp(s, "idebus=", 7)) { if (!strncmp(s, "bus=", 4)) {
if (*get_options(s+7, 2, vals) || vals[0] != 1) if (*get_options(s+4, 2, vals) || vals[0] != 1)
goto bad_option; goto bad_option;
idebus_parameter = vals[1]; idebus_parameter = vals[1];
goto done; goto done;
...@@ -853,7 +876,7 @@ int __init ide_setup(char *s) ...@@ -853,7 +876,7 @@ int __init ide_setup(char *s)
/* /*
* Look for interface options: "idex=" * 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 * Be VERY CAREFUL changing this: note hardcoded indexes below
*/ */
...@@ -861,11 +884,11 @@ int __init ide_setup(char *s) ...@@ -861,11 +884,11 @@ int __init ide_setup(char *s)
"noprobe", "serialize", "autotune", "noautotune", "reset", "dma", "ata66", NULL }; "noprobe", "serialize", "autotune", "noautotune", "reset", "dma", "ata66", NULL };
const char *ide_words[] = { const char *ide_words[] = {
"qd65xx", "ht6560b", "cmd640_vlb", "dtc2278", "umc8672", "ali14xx", "dc4030", NULL }; "qd65xx", "ht6560b", "cmd640_vlb", "dtc2278", "umc8672", "ali14xx", "dc4030", NULL };
hw = s[3] - '0'; hw = s[0] - '0';
ch = &ide_hwifs[hw]; 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 */ case -7: /* ata66 */
#ifdef CONFIG_PCI #ifdef CONFIG_PCI
ch->udma_four = 1; ch->udma_four = 1;
...@@ -889,7 +912,6 @@ int __init ide_setup(char *s) ...@@ -889,7 +912,6 @@ int __init ide_setup(char *s)
ch->drives[1].autotune = 1; ch->drives[1].autotune = 1;
goto done; goto done;
case -2: /* "serialize" */ case -2: /* "serialize" */
do_serialize:
{ {
struct ata_channel *mate; struct ata_channel *mate;
...@@ -904,7 +926,10 @@ int __init ide_setup(char *s) ...@@ -904,7 +926,10 @@ int __init ide_setup(char *s)
goto done; 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: * Cryptic check to ensure chipset not already set for a channel:
...@@ -913,7 +938,7 @@ int __init ide_setup(char *s) ...@@ -913,7 +938,7 @@ int __init ide_setup(char *s)
if (ide_hwifs[hw].chipset != ide_unknown) if (ide_hwifs[hw].chipset != ide_unknown)
goto bad_option; /* chipset already specified */ goto bad_option; /* chipset already specified */
if (i != -7 && hw != 0) 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) if (i != -7 && ide_hwifs[1].chipset != ide_unknown)
goto bad_option; /* chipset for 2nd port already specified */ goto bad_option; /* chipset for 2nd port already specified */
printk("\n"); printk("\n");
...@@ -1012,10 +1037,7 @@ int __init ide_setup(char *s) ...@@ -1012,10 +1037,7 @@ int __init ide_setup(char *s)
/****************************************************************************/ /****************************************************************************/
/* int ata_register_device(struct ata_device *drive, struct ata_operations *driver)
* This is in fact registering a device not a driver.
*/
int ide_register_subdriver(struct ata_device *drive, struct ata_operations *driver)
{ {
unsigned long flags; unsigned long flags;
...@@ -1027,12 +1049,9 @@ int ide_register_subdriver(struct ata_device *drive, struct ata_operations *driv ...@@ -1027,12 +1049,9 @@ int ide_register_subdriver(struct ata_device *drive, struct ata_operations *driv
return 1; 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; drive->driver = driver;
spin_unlock_irqrestore(&ide_lock, flags); spin_unlock_irqrestore(&ide_lock, flags);
/* Default autotune or requested autotune */ /* Default autotune or requested autotune */
if (drive->autotune != 2) { if (drive->autotune != 2) {
struct ata_channel *ch = drive->channel; struct ata_channel *ch = drive->channel;
...@@ -1046,11 +1065,13 @@ int ide_register_subdriver(struct ata_device *drive, struct ata_operations *driv ...@@ -1046,11 +1065,13 @@ int ide_register_subdriver(struct ata_device *drive, struct ata_operations *driv
* PARANOIA!!! * PARANOIA!!!
*/ */
spin_lock_irqsave(ch->lock, flags);
udma_enable(drive, 0, 0); udma_enable(drive, 0, 0);
ch->udma_setup(drive, ch->modes_map); ch->udma_setup(drive, ch->modes_map);
#ifdef CONFIG_BLK_DEV_IDE_TCQ_DEFAULT #ifdef CONFIG_BLK_DEV_IDE_TCQ_DEFAULT
udma_tcq_enable(drive, 1); udma_tcq_enable(drive, 1);
#endif #endif
spin_unlock_irqrestore(ch->lock, flags);
} }
/* Only CD-ROMs and tape drives support DSC overlap. But only /* 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 ...@@ -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!. * 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)) if (drive->usage || drive->busy || !ata_ops(drive))
return 1; return 1;
...@@ -1156,8 +1172,8 @@ EXPORT_SYMBOL(ide_lock); ...@@ -1156,8 +1172,8 @@ EXPORT_SYMBOL(ide_lock);
devfs_handle_t ide_devfs_handle; devfs_handle_t ide_devfs_handle;
EXPORT_SYMBOL(ide_register_subdriver); EXPORT_SYMBOL(ata_register_device);
EXPORT_SYMBOL(ide_unregister_subdriver); EXPORT_SYMBOL(ata_unregister_device);
EXPORT_SYMBOL(ata_revalidate); EXPORT_SYMBOL(ata_revalidate);
EXPORT_SYMBOL(ide_register_hw); EXPORT_SYMBOL(ide_register_hw);
EXPORT_SYMBOL(ide_unregister); EXPORT_SYMBOL(ide_unregister);
...@@ -1432,8 +1448,14 @@ static int __init init_ata(void) ...@@ -1432,8 +1448,14 @@ static int __init init_ata(void)
while ((options = next) != NULL) { while ((options = next) != NULL) {
if ((next = strchr(options,' ')) != NULL) if ((next = strchr(options,' ')) != NULL)
*next++ = 0; *next++ = 0;
if (!ide_setup(options)) if (!strncmp(options,"hd",2)) {
printk(KERN_ERR "Unknown option '%s'\n", options); 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(); return ata_module_init();
...@@ -1457,6 +1479,7 @@ module_exit(cleanup_ata); ...@@ -1457,6 +1479,7 @@ module_exit(cleanup_ata);
#ifndef MODULE #ifndef MODULE
/* command line option parser */ /* command line option parser */
__setup("", ide_setup); __setup("ide", ide_setup);
__setup("hd", ata_hd_setup);
#endif #endif
...@@ -244,13 +244,15 @@ static void compute_clocks(int pio, pio_clocks_t *clks) ...@@ -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) static void opti621_tune_drive(struct ata_device *drive, u8 pio)
{ {
/* primary and secondary drives share some registers, /* primary and secondary drives share some registers,
* so we have to program both drives * so we have to program both drives
*/ */
unsigned long flags;
u8 pio1, pio2; u8 pio1, pio2;
pio_clocks_t first, second; pio_clocks_t first, second;
int ax, drdy; int ax, drdy;
...@@ -281,9 +283,6 @@ static void opti621_tune_drive(struct ata_device *drive, u8 pio) ...@@ -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); hwif->name, ax, second.data_time, second.recovery_time, drdy);
#endif #endif
save_flags(flags); /* all CPUs */
cli(); /* all CPUs */
reg_base = hwif->io_ports[IDE_DATA_OFFSET]; reg_base = hwif->io_ports[IDE_DATA_OFFSET];
outb(0xc0, reg_base+CNTRL_REG); /* allow Register-B */ outb(0xc0, reg_base+CNTRL_REG); /* allow Register-B */
outb(0xff, reg_base+5); /* hmm, setupvic.exe does this ;-) */ 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) ...@@ -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, */ write_reg(misc, MISC_REG); /* set address setup, DRDY timings, */
/* and read prefetch for both drives */ /* and read prefetch for both drives */
restore_flags(flags); /* all CPUs */
} }
/* /*
......
...@@ -1082,7 +1082,12 @@ static void channel_init(struct ata_channel *ch) ...@@ -1082,7 +1082,12 @@ static void channel_init(struct ata_channel *ch)
} }
} }
#ifdef CONFIG_BLK_DEV_HD #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); printk("%s: CANNOT SHARE IRQ WITH OLD HARDDISK DRIVER (hd.c)\n", ch->name);
return; return;
......
/* /*
* Copyright (C) 1996-2001 Linus Torvalds & author (see below) * Copyright (C) 1996-2001 Linus Torvalds & author (see below)
*/ *
/*
* Version 0.03 Cleaned auto-tune, added probe * Version 0.03 Cleaned auto-tune, added probe
* Version 0.04 Added second channel tuning * Version 0.04 Added second channel tuning
* Version 0.05 Enhanced tuning ; added qd6500 support * Version 0.05 Enhanced tuning ; added qd6500 support
...@@ -81,36 +79,12 @@ ...@@ -81,36 +79,12 @@
* bit 5 : status, but of what ? * bit 5 : status, but of what ?
* bit 6 : always set 1 by dos driver * bit 6 : always set 1 by dos driver
* bit 7 : set 1 for non-ATAPI devices on primary port * 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 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. * 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) ...@@ -120,12 +94,10 @@ static void qd_select(struct ata_device *drive)
(QD_TIMREG(drive) & 0x02); (QD_TIMREG(drive) & 0x02);
if (timings[index] != QD_TIMING(drive)) 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 * computes the timing value where
* lower nibble represents active time, in count of VLB clocks * lower nibble represents active time, in count of VLB clocks
* upper nibble represents recovery 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 ...@@ -147,8 +119,6 @@ static u8 qd6500_compute_timing(struct ata_channel *hwif, int active_time, int r
} }
/* /*
* qd6580_compute_timing
*
* idem for qd6580 * idem for qd6580
*/ */
...@@ -161,8 +131,6 @@ static u8 qd6580_compute_timing(int active_time, int recovery_time) ...@@ -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 * tries to find timing from dos driver's table
*/ */
...@@ -187,8 +155,6 @@ static int qd_find_disk_type(struct ata_device *drive, ...@@ -187,8 +155,6 @@ static int qd_find_disk_type(struct ata_device *drive,
} }
/* /*
* qd_timing_ok:
*
* check whether timings don't conflict * check whether timings don't conflict
*/ */
...@@ -201,8 +167,6 @@ static int qd_timing_ok(struct ata_device drives[]) ...@@ -201,8 +167,6 @@ static int qd_timing_ok(struct ata_device drives[])
} }
/* /*
* qd_set_timing:
*
* records the timing, and enables selectproc as needed * records the timing, and enables selectproc as needed
*/ */
...@@ -221,10 +185,6 @@ static void qd_set_timing(struct ata_device *drive, u8 timing) ...@@ -221,10 +185,6 @@ static void qd_set_timing(struct ata_device *drive, u8 timing)
printk(KERN_DEBUG "%s: %#x\n", drive->name, timing); printk(KERN_DEBUG "%s: %#x\n", drive->name, timing);
} }
/*
* qd6500_tune_drive
*/
static void qd6500_tune_drive(struct ata_device *drive, u8 pio) static void qd6500_tune_drive(struct ata_device *drive, u8 pio)
{ {
int active_time = 175; int active_time = 175;
...@@ -242,10 +202,6 @@ static void qd6500_tune_drive(struct ata_device *drive, u8 pio) ...@@ -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)); 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) static void qd6580_tune_drive(struct ata_device *drive, u8 pio)
{ {
struct ata_timing *t; struct ata_timing *t;
...@@ -291,7 +247,7 @@ static void qd6580_tune_drive(struct ata_device *drive, u8 pio) ...@@ -291,7 +247,7 @@ static void qd6580_tune_drive(struct ata_device *drive, u8 pio)
} }
if (!drive->channel->unit && drive->type != ATA_DISK) { 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); 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) ...@@ -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 * tests if the given port is a register
*/ */
...@@ -329,8 +283,6 @@ static int __init qd_testreg(int port) ...@@ -329,8 +283,6 @@ static int __init qd_testreg(int port)
} }
/* /*
* qd_setup:
*
* called to setup an ata channel : adjusts attributes & links for tuning * 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 ...@@ -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 * called to unsetup an ata channel : back to default values, unlinks tuning
*/ */
void __init qd_unsetup(int unit) { void __init qd_unsetup(int unit) {
...@@ -368,13 +318,13 @@ void __init qd_unsetup(int unit) { ...@@ -368,13 +318,13 @@ void __init qd_unsetup(int unit) {
if (tuneproc == (void *) qd6500_tune_drive) { if (tuneproc == (void *) qd6500_tune_drive) {
// will do it for both // 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) { } else if (tuneproc == (void *) qd6580_tune_drive) {
if (QD_CONTROL(hwif) & QD_CONTR_SEC_DISABLED) { if (QD_CONTROL(hwif) & QD_CONTR_SEC_DISABLED) {
qd_write_reg(QD6580_DEF_DATA, QD_TIMREG(&hwif->drives[0])); outb(QD6580_DEF_DATA, QD_TIMREG(&hwif->drives[0]));
qd_write_reg(QD6580_DEF_DATA2, QD_TIMREG(&hwif->drives[1])); outb(QD6580_DEF_DATA2, QD_TIMREG(&hwif->drives[1]));
} else { } 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 { } else {
printk(KERN_WARNING "Unknown qd65xx tuning fonction !\n"); printk(KERN_WARNING "Unknown qd65xx tuning fonction !\n");
...@@ -383,8 +333,6 @@ void __init qd_unsetup(int unit) { ...@@ -383,8 +333,6 @@ void __init qd_unsetup(int unit) {
} }
/* /*
* qd_probe:
*
* looks at the specified baseport, and if qd found, registers & initialises it * looks at the specified baseport, and if qd found, registers & initialises it
* return 1 if another qd may be probed * return 1 if another qd may be probed
*/ */
...@@ -394,7 +342,7 @@ int __init qd_probe(int base) ...@@ -394,7 +342,7 @@ int __init qd_probe(int base)
u8 config; u8 config;
int unit; int unit;
config = qd_read_reg(QD_CONFIG_PORT); config = inb(QD_CONFIG_PORT);
if (! ((config & QD_CONFIG_BASEPORT) >> 1 == (base == 0xb0)) ) return 1; if (! ((config & QD_CONFIG_BASEPORT) >> 1 == (base == 0xb0)) ) return 1;
...@@ -425,7 +373,7 @@ int __init qd_probe(int base) ...@@ -425,7 +373,7 @@ int __init qd_probe(int base)
/* qd6580 found */ /* qd6580 found */
control = qd_read_reg(QD_CONTROL_PORT); control = inb(QD_CONTROL_PORT);
printk(KERN_NOTICE "qd6580 at %#x\n", base); printk(KERN_NOTICE "qd6580 at %#x\n", base);
printk(KERN_DEBUG "qd6580: config=%#x, control=%#x, ID3=%u\n", config, control, QD_ID3); 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) ...@@ -434,7 +382,7 @@ int __init qd_probe(int base)
/* secondary disabled */ /* secondary disabled */
printk(KERN_INFO "%s: qd6580: single IDE board\n", ide_hwifs[unit].name); 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_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; return 1;
} else { } else {
...@@ -443,7 +391,7 @@ int __init qd_probe(int base) ...@@ -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_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_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 */ return 0; /* no other qd65xx possible */
} }
...@@ -454,8 +402,6 @@ int __init qd_probe(int base) ...@@ -454,8 +402,6 @@ int __init qd_probe(int base)
#ifndef MODULE #ifndef MODULE
/* /*
* init_qd65xx:
*
* called by ide.c when parsing command line * called by ide.c when parsing command line
*/ */
......
/* /*
* Copyright (C) 1996 - 1999 Gadi Oxman <gadio@netvision.net.il> * Copyright (C) 1996 - 1999 Gadi Oxman <gadio@netvision.net.il>
*/ *
/*
* Emulation of a SCSI host adapter for IDE ATAPI devices. * Emulation of a SCSI host adapter for IDE ATAPI devices.
* *
* With this driver, one can use the Linux SCSI drivers instead of the * With this driver, one can use the Linux SCSI drivers instead of the
* native IDE ATAPI drivers. * 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/module.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/string.h> #include <linux/string.h>
...@@ -495,9 +474,8 @@ static void idescsi_release(struct inode *inode, struct file *filp, struct ata_d ...@@ -495,9 +474,8 @@ static void idescsi_release(struct inode *inode, struct file *filp, struct ata_d
static Scsi_Host_Template template; static Scsi_Host_Template template;
static int idescsi_cleanup (struct ata_device *drive) static int idescsi_cleanup (struct ata_device *drive)
{ {
if (ide_unregister_subdriver (drive)) { if (ata_unregister_device(drive))
return 1; return 1;
}
scsi_unregister_host(&template); scsi_unregister_host(&template);
return 0; return 0;
...@@ -762,7 +740,7 @@ static void idescsi_attach(struct ata_device *drive) ...@@ -762,7 +740,7 @@ static void idescsi_attach(struct ata_device *drive)
host = scsi_register(&template, sizeof(idescsi_scsi_t)); host = scsi_register(&template, sizeof(idescsi_scsi_t));
if (!host) { if (!host) {
printk (KERN_ERR printk(KERN_ERR
"ide-scsi: %s: Can't allocate a scsi host structure\n", "ide-scsi: %s: Can't allocate a scsi host structure\n",
drive->name); drive->name);
return; return;
...@@ -771,8 +749,8 @@ static void idescsi_attach(struct ata_device *drive) ...@@ -771,8 +749,8 @@ static void idescsi_attach(struct ata_device *drive)
host->max_lun = drive->last_lun + 1; host->max_lun = drive->last_lun + 1;
host->max_id = 1; host->max_id = 1;
if (ide_register_subdriver(drive, &ata_ops)) { if (ata_register_device(drive, &ata_ops)) {
printk (KERN_ERR "ide-scsi: %s: Failed to register the driver with ide.c\n", drive->name); printk(KERN_ERR "ide-scsi: %s: Failed to register the driver with ide.c\n", drive->name);
scsi_unregister(host); scsi_unregister(host);
return; return;
} }
......
...@@ -40,43 +40,47 @@ ...@@ -40,43 +40,47 @@
static void pdump (void *, int); static void pdump (void *, int);
#endif #endif
/* Bits of HD_STATUS */
#define ERR_STAT 0x01
#define DRQ_STAT 0x08
struct freecom_udata { struct freecom_udata {
__u8 buffer[64]; /* Common command block. */ u8 buffer[64]; /* Common command block. */
}; };
typedef struct freecom_udata *freecom_udata_t; typedef struct freecom_udata *freecom_udata_t;
/* All of the outgoing packets are 64 bytes long. */ /* All of the outgoing packets are 64 bytes long. */
struct freecom_cb_wrap { struct freecom_cb_wrap {
__u8 Type; /* Command type. */ u8 Type; /* Command type. */
__u8 Timeout; /* Timeout in seconds. */ u8 Timeout; /* Timeout in seconds. */
__u8 Atapi[12]; /* An ATAPI packet. */ u8 Atapi[12]; /* An ATAPI packet. */
__u8 Filler[50]; /* Padding Data. */ u8 Filler[50]; /* Padding Data. */
}; };
struct freecom_xfer_wrap { struct freecom_xfer_wrap {
__u8 Type; /* Command type. */ u8 Type; /* Command type. */
__u8 Timeout; /* Timeout in seconds. */ u8 Timeout; /* Timeout in seconds. */
__u32 Count; /* Number of bytes to transfer. */ u32 Count; /* Number of bytes to transfer. */
__u8 Pad[58]; u8 Pad[58];
} __attribute__ ((packed)); } __attribute__ ((packed));
struct freecom_ide_out { struct freecom_ide_out {
__u8 Type; /* Type + IDE register. */ u8 Type; /* Type + IDE register. */
__u8 Pad; u8 Pad;
__u16 Value; /* Value to write. */ u16 Value; /* Value to write. */
__u8 Pad2[60]; u8 Pad2[60];
}; };
struct freecom_ide_in { struct freecom_ide_in {
__u8 Type; /* Type | IDE register. */ u8 Type; /* Type | IDE register. */
__u8 Pad[63]; u8 Pad[63];
}; };
struct freecom_status { struct freecom_status {
__u8 Status; u8 Status;
__u8 Reason; u8 Reason;
__u16 Count; u16 Count;
__u8 Pad[60]; u8 Pad[60];
}; };
/* Freecom stuffs the interrupt status in the INDEX_STAT bit of the ide /* Freecom stuffs the interrupt status in the INDEX_STAT bit of the ide
......
#ifndef _LINUX_HDREG_H #ifndef _LINUX_HDREG_H
#define _LINUX_HDREG_H #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 * Command Header sizes for IOCTL commands
*/ */
#define HDIO_DRIVE_CMD_HDR_SIZE (4 * sizeof(u8)) #define HDIO_DRIVE_CMD_HDR_SIZE (4 * sizeof(u8))
#define HDIO_DRIVE_HOB_HDR_SIZE (8 * 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 { struct hd_geometry {
u8 heads; __u8 heads;
u8 sectors; __u8 sectors;
u16 cylinders; __u16 cylinders;
unsigned long start; 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 */ /* hd/ide ctl's that pass (arg) ptrs to user space are numbered 0x030n/0x031n */
#define HDIO_GETGEO 0x0301 /* get device geometry */ #define HDIO_GETGEO 0x0301 /* get device geometry */
#define HDIO_GET_UNMASKINTR 0x0302 /* get current unmask setting */ #define HDIO_GET_UNMASKINTR 0x0302 /* get current unmask setting */
...@@ -306,263 +45,8 @@ struct hd_big_geometry { ...@@ -306,263 +45,8 @@ struct hd_big_geometry {
#define HDIO_SET_QDMA 0x032e /* change use-qdma flag */ #define HDIO_SET_QDMA 0x032e /* change use-qdma flag */
#define HDIO_SET_ADDRESS 0x032f /* change lba addressing modes */ #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 */ /* hd/ide ctl's that pass (arg) ptrs to user space are numbered 0x033n/0x033n */
/* 0x330 is reserved - used to be HDIO_GETGEO_BIG */ /* 0x330 is reserved - used to be HDIO_GETGEO_BIG */
#define HDIO_GETGEO_BIG_RAW 0x0331 /* */ #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 #endif
...@@ -8,7 +8,6 @@ ...@@ -8,7 +8,6 @@
#include <linux/config.h> #include <linux/config.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/hdreg.h>
#include <linux/hdsmart.h> #include <linux/hdsmart.h>
#include <linux/blkdev.h> #include <linux/blkdev.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
...@@ -51,7 +50,460 @@ ...@@ -51,7 +50,460 @@
* "No user-serviceable parts" beyond this point * "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 * Probably not wise to fiddle with these
...@@ -105,6 +557,35 @@ enum { ...@@ -105,6 +557,35 @@ enum {
#define GET_ALTSTAT() IN_BYTE(drive->channel->io_ports[IDE_CONTROL_OFFSET]) #define GET_ALTSTAT() IN_BYTE(drive->channel->io_ports[IDE_CONTROL_OFFSET])
#define GET_FEAT() IN_BYTE(IDE_NSECTOR_REG) #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_R_STAT (BUSY_STAT | ERR_STAT)
#define BAD_W_STAT (BAD_R_STAT | WRERR_STAT) #define BAD_W_STAT (BAD_R_STAT | WRERR_STAT)
#define BAD_STAT (BAD_R_STAT | DRQ_STAT) #define BAD_STAT (BAD_R_STAT | DRQ_STAT)
...@@ -665,23 +1146,23 @@ extern struct block_device_operations ide_fops[]; ...@@ -665,23 +1146,23 @@ extern struct block_device_operations ide_fops[];
*/ */
extern int ideprobe_init(void); extern int ideprobe_init(void);
#ifdef CONFIG_BLK_DEV_IDEDISK #ifdef CONFIG_BLK_DEV_IDEDISK
extern int idedisk_init (void); extern int idedisk_init(void);
#endif #endif
#ifdef CONFIG_BLK_DEV_IDECD #ifdef CONFIG_BLK_DEV_IDECD
extern int ide_cdrom_init (void); extern int ide_cdrom_init(void);
#endif #endif
#ifdef CONFIG_BLK_DEV_IDETAPE #ifdef CONFIG_BLK_DEV_IDETAPE
extern int idetape_init (void); extern int idetape_init(void);
#endif #endif
#ifdef CONFIG_BLK_DEV_IDEFLOPPY #ifdef CONFIG_BLK_DEV_IDEFLOPPY
extern int idefloppy_init (void); extern int idefloppy_init(void);
#endif #endif
#ifdef CONFIG_BLK_DEV_IDESCSI #ifdef CONFIG_BLK_DEV_IDESCSI
extern int idescsi_init (void); extern int idescsi_init(void);
#endif #endif
extern int ide_register_subdriver(struct ata_device *, struct ata_operations *); extern int ata_register_device(struct ata_device *, struct ata_operations *);
extern int ide_unregister_subdriver(struct ata_device *drive); extern int ata_unregister_device(struct ata_device *drive);
extern int ata_revalidate(kdev_t i_rdev); extern int ata_revalidate(kdev_t i_rdev);
extern void ide_driver_module(void); extern void ide_driver_module(void);
......
...@@ -608,22 +608,20 @@ static inline void copy_flags(unsigned long clone_flags, struct task_struct *p) ...@@ -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 * This creates a new process as a copy of the old one,
* information (task[nr]) and sets up the necessary registers. It also * but does not actually start it yet.
* copies the data segment in its entirety. The "stack_start" and *
* "stack_top" arguments are simply passed along to the platform * It copies the registers, and all the appropriate
* specific copy_thread() routine. Most platforms ignore stack_top. * parts of the process environment (as per the clone
* For an example that's using stack_top, see * flags). The actual kick-off is left to the caller.
* arch/ia64/kernel/process.c.
*/ */
struct task_struct *do_fork(unsigned long clone_flags, static struct task_struct *copy_process(unsigned long clone_flags,
unsigned long stack_start, unsigned long stack_start,
struct pt_regs *regs, struct pt_regs *regs,
unsigned long stack_size) unsigned long stack_size)
{ {
int retval; int retval;
struct task_struct *p = NULL; struct task_struct *p = NULL;
struct completion vfork;
if ((clone_flags & (CLONE_NEWNS|CLONE_FS)) == (CLONE_NEWNS|CLONE_FS)) if ((clone_flags & (CLONE_NEWNS|CLONE_FS)) == (CLONE_NEWNS|CLONE_FS))
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
...@@ -680,10 +678,6 @@ struct task_struct *do_fork(unsigned long clone_flags, ...@@ -680,10 +678,6 @@ struct task_struct *do_fork(unsigned long clone_flags,
INIT_LIST_HEAD(&p->sibling); INIT_LIST_HEAD(&p->sibling);
init_waitqueue_head(&p->wait_chldexit); init_waitqueue_head(&p->wait_chldexit);
p->vfork_done = NULL; 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->alloc_lock);
spin_lock_init(&p->switch_lock); spin_lock_init(&p->switch_lock);
...@@ -803,20 +797,6 @@ struct task_struct *do_fork(unsigned long clone_flags, ...@@ -803,20 +797,6 @@ struct task_struct *do_fork(unsigned long clone_flags,
hash_pid(p); hash_pid(p);
nr_threads++; nr_threads++;
write_unlock_irq(&tasklist_lock); 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; retval = 0;
fork_out: fork_out:
...@@ -850,6 +830,45 @@ struct task_struct *do_fork(unsigned long clone_flags, ...@@ -850,6 +830,45 @@ struct task_struct *do_fork(unsigned long clone_flags,
goto fork_out; 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) */ /* SLAB cache for signal_struct structures (tsk->sig) */
kmem_cache_t *sigact_cachep; kmem_cache_t *sigact_cachep;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment