diff options
Diffstat (limited to 'drivers')
80 files changed, 6747 insertions, 2399 deletions
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 4672066167e3..33f5eb038773 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig | |||
| @@ -272,6 +272,15 @@ config PATA_CS5535 | |||
| 272 | 272 | ||
| 273 | If unsure, say N. | 273 | If unsure, say N. |
| 274 | 274 | ||
| 275 | config PATA_CS5536 | ||
| 276 | tristate "CS5536 PATA support (Experimental)" | ||
| 277 | depends on PCI && X86 && !X86_64 && EXPERIMENTAL | ||
| 278 | help | ||
| 279 | This option enables support for the AMD CS5536 | ||
| 280 | companion chip used with the Geode LX processor family. | ||
| 281 | |||
| 282 | If unsure, say N. | ||
| 283 | |||
| 275 | config PATA_CYPRESS | 284 | config PATA_CYPRESS |
| 276 | tristate "Cypress CY82C693 PATA support (Very Experimental)" | 285 | tristate "Cypress CY82C693 PATA support (Very Experimental)" |
| 277 | depends on PCI && EXPERIMENTAL | 286 | depends on PCI && EXPERIMENTAL |
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index 2a63645003eb..6bdc307649e6 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile | |||
| @@ -28,6 +28,7 @@ obj-$(CONFIG_PATA_CMD64X) += pata_cmd64x.o | |||
| 28 | obj-$(CONFIG_PATA_CS5520) += pata_cs5520.o | 28 | obj-$(CONFIG_PATA_CS5520) += pata_cs5520.o |
| 29 | obj-$(CONFIG_PATA_CS5530) += pata_cs5530.o | 29 | obj-$(CONFIG_PATA_CS5530) += pata_cs5530.o |
| 30 | obj-$(CONFIG_PATA_CS5535) += pata_cs5535.o | 30 | obj-$(CONFIG_PATA_CS5535) += pata_cs5535.o |
| 31 | obj-$(CONFIG_PATA_CS5536) += pata_cs5536.o | ||
| 31 | obj-$(CONFIG_PATA_CYPRESS) += pata_cypress.o | 32 | obj-$(CONFIG_PATA_CYPRESS) += pata_cypress.o |
| 32 | obj-$(CONFIG_PATA_EFAR) += pata_efar.o | 33 | obj-$(CONFIG_PATA_EFAR) += pata_efar.o |
| 33 | obj-$(CONFIG_PATA_HPT366) += pata_hpt366.o | 34 | obj-$(CONFIG_PATA_HPT366) += pata_hpt366.o |
diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index 9ce4aa9c2f25..3c6f43e381f4 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c | |||
| @@ -130,6 +130,7 @@ enum { | |||
| 130 | ich8_sata_ahci = 9, | 130 | ich8_sata_ahci = 9, |
| 131 | piix_pata_mwdma = 10, /* PIIX3 MWDMA only */ | 131 | piix_pata_mwdma = 10, /* PIIX3 MWDMA only */ |
| 132 | tolapai_sata_ahci = 11, | 132 | tolapai_sata_ahci = 11, |
| 133 | ich9_2port_sata = 12, | ||
| 133 | 134 | ||
| 134 | /* constants for mapping table */ | 135 | /* constants for mapping table */ |
| 135 | P0 = 0, /* port 0 */ | 136 | P0 = 0, /* port 0 */ |
| @@ -238,19 +239,19 @@ static const struct pci_device_id piix_pci_tbl[] = { | |||
| 238 | /* SATA Controller 1 IDE (ICH8) */ | 239 | /* SATA Controller 1 IDE (ICH8) */ |
| 239 | { 0x8086, 0x2820, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci }, | 240 | { 0x8086, 0x2820, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci }, |
| 240 | /* SATA Controller 2 IDE (ICH8) */ | 241 | /* SATA Controller 2 IDE (ICH8) */ |
| 241 | { 0x8086, 0x2825, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci }, | 242 | { 0x8086, 0x2825, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich9_2port_sata }, |
| 242 | /* Mobile SATA Controller IDE (ICH8M) */ | 243 | /* Mobile SATA Controller IDE (ICH8M) */ |
| 243 | { 0x8086, 0x2828, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci }, | 244 | { 0x8086, 0x2828, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci }, |
| 244 | /* SATA Controller IDE (ICH9) */ | 245 | /* SATA Controller IDE (ICH9) */ |
| 245 | { 0x8086, 0x2920, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci }, | 246 | { 0x8086, 0x2920, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci }, |
| 246 | /* SATA Controller IDE (ICH9) */ | 247 | /* SATA Controller IDE (ICH9) */ |
| 247 | { 0x8086, 0x2921, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci }, | 248 | { 0x8086, 0x2921, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich9_2port_sata }, |
| 248 | /* SATA Controller IDE (ICH9) */ | 249 | /* SATA Controller IDE (ICH9) */ |
| 249 | { 0x8086, 0x2926, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci }, | 250 | { 0x8086, 0x2926, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich9_2port_sata }, |
| 250 | /* SATA Controller IDE (ICH9M) */ | 251 | /* SATA Controller IDE (ICH9M) */ |
| 251 | { 0x8086, 0x2928, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci }, | 252 | { 0x8086, 0x2928, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich9_2port_sata }, |
| 252 | /* SATA Controller IDE (ICH9M) */ | 253 | /* SATA Controller IDE (ICH9M) */ |
| 253 | { 0x8086, 0x292d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci }, | 254 | { 0x8086, 0x292d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich9_2port_sata }, |
| 254 | /* SATA Controller IDE (ICH9M) */ | 255 | /* SATA Controller IDE (ICH9M) */ |
| 255 | { 0x8086, 0x292e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci }, | 256 | { 0x8086, 0x292e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci }, |
| 256 | /* SATA Controller IDE (Tolapai) */ | 257 | /* SATA Controller IDE (Tolapai) */ |
| @@ -448,6 +449,18 @@ static const struct piix_map_db tolapai_map_db = { | |||
| 448 | }, | 449 | }, |
| 449 | }; | 450 | }; |
| 450 | 451 | ||
| 452 | static const struct piix_map_db ich9_2port_map_db = { | ||
| 453 | .mask = 0x3, | ||
| 454 | .port_enable = 0x3, | ||
| 455 | .map = { | ||
| 456 | /* PM PS SM SS MAP */ | ||
| 457 | { P0, NA, P1, NA }, /* 00b */ | ||
| 458 | { RV, RV, RV, RV }, /* 01b */ | ||
| 459 | { RV, RV, RV, RV }, /* 10b */ | ||
| 460 | { RV, RV, RV, RV }, | ||
| 461 | }, | ||
| 462 | }; | ||
| 463 | |||
| 451 | static const struct piix_map_db *piix_map_db_table[] = { | 464 | static const struct piix_map_db *piix_map_db_table[] = { |
| 452 | [ich5_sata] = &ich5_map_db, | 465 | [ich5_sata] = &ich5_map_db, |
| 453 | [ich6_sata] = &ich6_map_db, | 466 | [ich6_sata] = &ich6_map_db, |
| @@ -455,6 +468,7 @@ static const struct piix_map_db *piix_map_db_table[] = { | |||
| 455 | [ich6m_sata_ahci] = &ich6m_map_db, | 468 | [ich6m_sata_ahci] = &ich6m_map_db, |
| 456 | [ich8_sata_ahci] = &ich8_map_db, | 469 | [ich8_sata_ahci] = &ich8_map_db, |
| 457 | [tolapai_sata_ahci] = &tolapai_map_db, | 470 | [tolapai_sata_ahci] = &tolapai_map_db, |
| 471 | [ich9_2port_sata] = &ich9_2port_map_db, | ||
| 458 | }; | 472 | }; |
| 459 | 473 | ||
| 460 | static struct ata_port_info piix_port_info[] = { | 474 | static struct ata_port_info piix_port_info[] = { |
| @@ -570,6 +584,17 @@ static struct ata_port_info piix_port_info[] = { | |||
| 570 | .udma_mask = ATA_UDMA6, | 584 | .udma_mask = ATA_UDMA6, |
| 571 | .port_ops = &piix_sata_ops, | 585 | .port_ops = &piix_sata_ops, |
| 572 | }, | 586 | }, |
| 587 | |||
| 588 | [ich9_2port_sata] = | ||
| 589 | { | ||
| 590 | .sht = &piix_sht, | ||
| 591 | .flags = PIIX_SATA_FLAGS | PIIX_FLAG_SCR | | ||
| 592 | PIIX_FLAG_AHCI, | ||
| 593 | .pio_mask = 0x1f, /* pio0-4 */ | ||
| 594 | .mwdma_mask = 0x07, /* mwdma0-2 */ | ||
| 595 | .udma_mask = ATA_UDMA6, | ||
| 596 | .port_ops = &piix_sata_ops, | ||
| 597 | }, | ||
| 573 | }; | 598 | }; |
| 574 | 599 | ||
| 575 | static struct pci_bits piix_enable_bits[] = { | 600 | static struct pci_bits piix_enable_bits[] = { |
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index b05384a8c326..68699b3e7998 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c | |||
| @@ -3984,6 +3984,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { | |||
| 3984 | { "ST9120822AS", "3.CLF", ATA_HORKAGE_NONCQ, }, | 3984 | { "ST9120822AS", "3.CLF", ATA_HORKAGE_NONCQ, }, |
| 3985 | { "ST9160821AS", "3.CLF", ATA_HORKAGE_NONCQ, }, | 3985 | { "ST9160821AS", "3.CLF", ATA_HORKAGE_NONCQ, }, |
| 3986 | { "ST9160821AS", "3.ALD", ATA_HORKAGE_NONCQ, }, | 3986 | { "ST9160821AS", "3.ALD", ATA_HORKAGE_NONCQ, }, |
| 3987 | { "ST9160821AS", "3.CCD", ATA_HORKAGE_NONCQ, }, | ||
| 3987 | { "ST3160812AS", "3.ADJ", ATA_HORKAGE_NONCQ, }, | 3988 | { "ST3160812AS", "3.ADJ", ATA_HORKAGE_NONCQ, }, |
| 3988 | { "ST980813AS", "3.ADB", ATA_HORKAGE_NONCQ, }, | 3989 | { "ST980813AS", "3.ADB", ATA_HORKAGE_NONCQ, }, |
| 3989 | { "SAMSUNG HD401LJ", "ZZ100-15", ATA_HORKAGE_NONCQ, }, | 3990 | { "SAMSUNG HD401LJ", "ZZ100-15", ATA_HORKAGE_NONCQ, }, |
| @@ -4013,8 +4014,14 @@ int strn_pattern_cmp(const char *patt, const char *name, int wildchar) | |||
| 4013 | p = strchr(patt, wildchar); | 4014 | p = strchr(patt, wildchar); |
| 4014 | if (p && ((*(p + 1)) == 0)) | 4015 | if (p && ((*(p + 1)) == 0)) |
| 4015 | len = p - patt; | 4016 | len = p - patt; |
| 4016 | else | 4017 | else { |
| 4017 | len = strlen(name); | 4018 | len = strlen(name); |
| 4019 | if (!len) { | ||
| 4020 | if (!*patt) | ||
| 4021 | return 0; | ||
| 4022 | return -1; | ||
| 4023 | } | ||
| 4024 | } | ||
| 4018 | 4025 | ||
| 4019 | return strncmp(patt, name, len); | 4026 | return strncmp(patt, name, len); |
| 4020 | } | 4027 | } |
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index ea53e6a570b4..d63c81ed084f 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c | |||
| @@ -1363,6 +1363,7 @@ nothing_to_do: | |||
| 1363 | static void ata_scsi_qc_complete(struct ata_queued_cmd *qc) | 1363 | static void ata_scsi_qc_complete(struct ata_queued_cmd *qc) |
| 1364 | { | 1364 | { |
| 1365 | struct ata_port *ap = qc->ap; | 1365 | struct ata_port *ap = qc->ap; |
| 1366 | struct ata_eh_info *ehi = &qc->dev->link->eh_info; | ||
| 1366 | struct scsi_cmnd *cmd = qc->scsicmd; | 1367 | struct scsi_cmnd *cmd = qc->scsicmd; |
| 1367 | u8 *cdb = cmd->cmnd; | 1368 | u8 *cdb = cmd->cmnd; |
| 1368 | int need_sense = (qc->err_mask != 0); | 1369 | int need_sense = (qc->err_mask != 0); |
| @@ -1376,14 +1377,14 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc) | |||
| 1376 | case ATA_CMD_SET_FEATURES: | 1377 | case ATA_CMD_SET_FEATURES: |
| 1377 | if ((qc->tf.feature == SETFEATURES_WC_ON) || | 1378 | if ((qc->tf.feature == SETFEATURES_WC_ON) || |
| 1378 | (qc->tf.feature == SETFEATURES_WC_OFF)) { | 1379 | (qc->tf.feature == SETFEATURES_WC_OFF)) { |
| 1379 | ap->link.eh_info.action |= ATA_EH_REVALIDATE; | 1380 | ehi->action |= ATA_EH_REVALIDATE; |
| 1380 | ata_port_schedule_eh(ap); | 1381 | ata_port_schedule_eh(ap); |
| 1381 | } | 1382 | } |
| 1382 | break; | 1383 | break; |
| 1383 | 1384 | ||
| 1384 | case ATA_CMD_INIT_DEV_PARAMS: /* CHS translation changed */ | 1385 | case ATA_CMD_INIT_DEV_PARAMS: /* CHS translation changed */ |
| 1385 | case ATA_CMD_SET_MULTI: /* multi_count changed */ | 1386 | case ATA_CMD_SET_MULTI: /* multi_count changed */ |
| 1386 | ap->link.eh_info.action |= ATA_EH_REVALIDATE; | 1387 | ehi->action |= ATA_EH_REVALIDATE; |
| 1387 | ata_port_schedule_eh(ap); | 1388 | ata_port_schedule_eh(ap); |
| 1388 | break; | 1389 | break; |
| 1389 | } | 1390 | } |
diff --git a/drivers/ata/pata_cs5536.c b/drivers/ata/pata_cs5536.c new file mode 100644 index 000000000000..21405bf14837 --- /dev/null +++ b/drivers/ata/pata_cs5536.c | |||
| @@ -0,0 +1,346 @@ | |||
| 1 | /* | ||
| 2 | * pata_cs5536.c - CS5536 PATA for new ATA layer | ||
| 3 | * (C) 2007 Martin K. Petersen <mkp@mkp.net> | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License version 2 as | ||
| 7 | * published by the Free Software Foundation. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License | ||
| 15 | * along with this program; if not, write to the Free Software | ||
| 16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 17 | * | ||
| 18 | * Documentation: | ||
| 19 | * Available from AMD web site. | ||
| 20 | * | ||
| 21 | * The IDE timing registers for the CS5536 live in the Geode Machine | ||
| 22 | * Specific Register file and not PCI config space. Most BIOSes | ||
| 23 | * virtualize the PCI registers so the chip looks like a standard IDE | ||
| 24 | * controller. Unfortunately not all implementations get this right. | ||
| 25 | * In particular some have problems with unaligned accesses to the | ||
| 26 | * virtualized PCI registers. This driver always does full dword | ||
| 27 | * writes to work around the issue. Also, in case of a bad BIOS this | ||
| 28 | * driver can be loaded with the "msr=1" parameter which forces using | ||
| 29 | * the Machine Specific Registers to configure the device. | ||
| 30 | */ | ||
| 31 | |||
| 32 | #include <linux/kernel.h> | ||
| 33 | #include <linux/module.h> | ||
| 34 | #include <linux/pci.h> | ||
| 35 | #include <linux/init.h> | ||
| 36 | #include <linux/blkdev.h> | ||
| 37 | #include <linux/delay.h> | ||
| 38 | #include <linux/libata.h> | ||
| 39 | #include <scsi/scsi_host.h> | ||
| 40 | #include <asm/msr.h> | ||
| 41 | |||
| 42 | #define DRV_NAME "pata_cs5536" | ||
| 43 | #define DRV_VERSION "0.0.5" | ||
| 44 | |||
| 45 | enum { | ||
| 46 | CFG = 0, | ||
| 47 | DTC = 1, | ||
| 48 | CAST = 2, | ||
| 49 | ETC = 3, | ||
| 50 | |||
| 51 | MSR_IDE_BASE = 0x51300000, | ||
| 52 | MSR_IDE_CFG = (MSR_IDE_BASE + 0x10), | ||
| 53 | MSR_IDE_DTC = (MSR_IDE_BASE + 0x12), | ||
| 54 | MSR_IDE_CAST = (MSR_IDE_BASE + 0x13), | ||
| 55 | MSR_IDE_ETC = (MSR_IDE_BASE + 0x14), | ||
| 56 | |||
| 57 | PCI_IDE_CFG = 0x40, | ||
| 58 | PCI_IDE_DTC = 0x48, | ||
| 59 | PCI_IDE_CAST = 0x4c, | ||
| 60 | PCI_IDE_ETC = 0x50, | ||
| 61 | |||
| 62 | IDE_CFG_CHANEN = 0x2, | ||
| 63 | IDE_CFG_CABLE = 0x10000, | ||
| 64 | |||
| 65 | IDE_D0_SHIFT = 24, | ||
| 66 | IDE_D1_SHIFT = 16, | ||
| 67 | IDE_DRV_MASK = 0xff, | ||
| 68 | |||
| 69 | IDE_CAST_D0_SHIFT = 6, | ||
| 70 | IDE_CAST_D1_SHIFT = 4, | ||
| 71 | IDE_CAST_DRV_MASK = 0x3, | ||
| 72 | IDE_CAST_CMD_MASK = 0xff, | ||
| 73 | IDE_CAST_CMD_SHIFT = 24, | ||
| 74 | |||
| 75 | IDE_ETC_NODMA = 0x03, | ||
| 76 | }; | ||
| 77 | |||
| 78 | static int use_msr; | ||
| 79 | |||
| 80 | static const u32 msr_reg[4] = { | ||
| 81 | MSR_IDE_CFG, MSR_IDE_DTC, MSR_IDE_CAST, MSR_IDE_ETC, | ||
| 82 | }; | ||
| 83 | |||
| 84 | static const u8 pci_reg[4] = { | ||
| 85 | PCI_IDE_CFG, PCI_IDE_DTC, PCI_IDE_CAST, PCI_IDE_ETC, | ||
| 86 | }; | ||
| 87 | |||
| 88 | static inline int cs5536_read(struct pci_dev *pdev, int reg, int *val) | ||
| 89 | { | ||
| 90 | if (unlikely(use_msr)) { | ||
| 91 | u32 dummy; | ||
| 92 | |||
| 93 | rdmsr(msr_reg[reg], *val, dummy); | ||
| 94 | return 0; | ||
| 95 | } | ||
| 96 | |||
| 97 | return pci_read_config_dword(pdev, pci_reg[reg], val); | ||
| 98 | } | ||
| 99 | |||
| 100 | static inline int cs5536_write(struct pci_dev *pdev, int reg, int val) | ||
| 101 | { | ||
| 102 | if (unlikely(use_msr)) { | ||
| 103 | wrmsr(msr_reg[reg], val, 0); | ||
| 104 | return 0; | ||
| 105 | } | ||
| 106 | |||
| 107 | return pci_write_config_dword(pdev, pci_reg[reg], val); | ||
| 108 | } | ||
| 109 | |||
| 110 | /** | ||
| 111 | * cs5536_cable_detect - detect cable type | ||
| 112 | * @ap: Port to detect on | ||
| 113 | * @deadline: deadline jiffies for the operation | ||
| 114 | * | ||
| 115 | * Perform cable detection for ATA66 capable cable. Return a libata | ||
| 116 | * cable type. | ||
| 117 | */ | ||
| 118 | |||
| 119 | static int cs5536_cable_detect(struct ata_port *ap) | ||
| 120 | { | ||
| 121 | struct pci_dev *pdev = to_pci_dev(ap->host->dev); | ||
| 122 | u32 cfg; | ||
| 123 | |||
| 124 | cs5536_read(pdev, CFG, &cfg); | ||
| 125 | |||
| 126 | if (cfg & (IDE_CFG_CABLE << ap->port_no)) | ||
| 127 | return ATA_CBL_PATA80; | ||
| 128 | else | ||
| 129 | return ATA_CBL_PATA40; | ||
| 130 | } | ||
| 131 | |||
| 132 | /** | ||
| 133 | * cs5536_set_piomode - PIO setup | ||
| 134 | * @ap: ATA interface | ||
| 135 | * @adev: device on the interface | ||
| 136 | */ | ||
| 137 | |||
| 138 | static void cs5536_set_piomode(struct ata_port *ap, struct ata_device *adev) | ||
| 139 | { | ||
| 140 | static const u8 drv_timings[5] = { | ||
| 141 | 0x98, 0x55, 0x32, 0x21, 0x20, | ||
| 142 | }; | ||
| 143 | |||
| 144 | static const u8 addr_timings[5] = { | ||
| 145 | 0x2, 0x1, 0x0, 0x0, 0x0, | ||
| 146 | }; | ||
| 147 | |||
| 148 | static const u8 cmd_timings[5] = { | ||
| 149 | 0x99, 0x92, 0x90, 0x22, 0x20, | ||
| 150 | }; | ||
| 151 | |||
| 152 | struct pci_dev *pdev = to_pci_dev(ap->host->dev); | ||
| 153 | struct ata_device *pair = ata_dev_pair(adev); | ||
| 154 | int mode = adev->pio_mode - XFER_PIO_0; | ||
| 155 | int cmdmode = mode; | ||
| 156 | int dshift = ap->port_no ? IDE_D1_SHIFT : IDE_D0_SHIFT; | ||
| 157 | int cshift = ap->port_no ? IDE_CAST_D1_SHIFT : IDE_CAST_D0_SHIFT; | ||
| 158 | u32 dtc, cast, etc; | ||
| 159 | |||
| 160 | if (pair) | ||
| 161 | cmdmode = min(mode, pair->pio_mode - XFER_PIO_0); | ||
| 162 | |||
| 163 | cs5536_read(pdev, DTC, &dtc); | ||
| 164 | cs5536_read(pdev, CAST, &cast); | ||
| 165 | cs5536_read(pdev, ETC, &etc); | ||
| 166 | |||
| 167 | dtc &= ~(IDE_DRV_MASK << dshift); | ||
| 168 | dtc |= drv_timings[mode] << dshift; | ||
| 169 | |||
| 170 | cast &= ~(IDE_CAST_DRV_MASK << cshift); | ||
| 171 | cast |= addr_timings[mode] << cshift; | ||
| 172 | |||
| 173 | cast &= ~(IDE_CAST_CMD_MASK << IDE_CAST_CMD_SHIFT); | ||
| 174 | cast |= cmd_timings[cmdmode] << IDE_CAST_CMD_SHIFT; | ||
| 175 | |||
| 176 | etc &= ~(IDE_DRV_MASK << dshift); | ||
| 177 | etc |= IDE_ETC_NODMA << dshift; | ||
| 178 | |||
| 179 | cs5536_write(pdev, DTC, dtc); | ||
| 180 | cs5536_write(pdev, CAST, cast); | ||
| 181 | cs5536_write(pdev, ETC, etc); | ||
| 182 | } | ||
| 183 | |||
| 184 | /** | ||
| 185 | * cs5536_set_dmamode - DMA timing setup | ||
| 186 | * @ap: ATA interface | ||
| 187 | * @adev: Device being configured | ||
| 188 | * | ||
| 189 | */ | ||
| 190 | |||
| 191 | static void cs5536_set_dmamode(struct ata_port *ap, struct ata_device *adev) | ||
| 192 | { | ||
| 193 | static const u8 udma_timings[6] = { | ||
| 194 | 0xc2, 0xc1, 0xc0, 0xc4, 0xc5, 0xc6, | ||
| 195 | }; | ||
| 196 | |||
| 197 | static const u8 mwdma_timings[3] = { | ||
| 198 | 0x67, 0x21, 0x20, | ||
| 199 | }; | ||
| 200 | |||
| 201 | struct pci_dev *pdev = to_pci_dev(ap->host->dev); | ||
| 202 | u32 dtc, etc; | ||
| 203 | int mode = adev->dma_mode; | ||
| 204 | int dshift = ap->port_no ? IDE_D1_SHIFT : IDE_D0_SHIFT; | ||
| 205 | |||
| 206 | if (mode >= XFER_UDMA_0) { | ||
| 207 | cs5536_read(pdev, ETC, &etc); | ||
| 208 | |||
| 209 | etc &= ~(IDE_DRV_MASK << dshift); | ||
| 210 | etc |= udma_timings[mode - XFER_UDMA_0] << dshift; | ||
| 211 | |||
| 212 | cs5536_write(pdev, ETC, etc); | ||
| 213 | } else { /* MWDMA */ | ||
| 214 | cs5536_read(pdev, DTC, &dtc); | ||
| 215 | |||
| 216 | dtc &= ~(IDE_DRV_MASK << dshift); | ||
| 217 | dtc |= mwdma_timings[mode] << dshift; | ||
| 218 | |||
| 219 | cs5536_write(pdev, DTC, dtc); | ||
| 220 | } | ||
| 221 | } | ||
| 222 | |||
| 223 | static struct scsi_host_template cs5536_sht = { | ||
| 224 | .module = THIS_MODULE, | ||
| 225 | .name = DRV_NAME, | ||
| 226 | .ioctl = ata_scsi_ioctl, | ||
| 227 | .queuecommand = ata_scsi_queuecmd, | ||
| 228 | .can_queue = ATA_DEF_QUEUE, | ||
| 229 | .this_id = ATA_SHT_THIS_ID, | ||
| 230 | .sg_tablesize = LIBATA_MAX_PRD, | ||
| 231 | .cmd_per_lun = ATA_SHT_CMD_PER_LUN, | ||
| 232 | .emulated = ATA_SHT_EMULATED, | ||
| 233 | .use_clustering = ATA_SHT_USE_CLUSTERING, | ||
| 234 | .proc_name = DRV_NAME, | ||
| 235 | .dma_boundary = ATA_DMA_BOUNDARY, | ||
| 236 | .slave_configure = ata_scsi_slave_config, | ||
| 237 | .slave_destroy = ata_scsi_slave_destroy, | ||
| 238 | .bios_param = ata_std_bios_param, | ||
| 239 | }; | ||
| 240 | |||
| 241 | static struct ata_port_operations cs5536_port_ops = { | ||
| 242 | .port_disable = ata_port_disable, | ||
| 243 | .set_piomode = cs5536_set_piomode, | ||
| 244 | .set_dmamode = cs5536_set_dmamode, | ||
| 245 | .mode_filter = ata_pci_default_filter, | ||
| 246 | |||
| 247 | .tf_load = ata_tf_load, | ||
| 248 | .tf_read = ata_tf_read, | ||
| 249 | .check_status = ata_check_status, | ||
| 250 | .exec_command = ata_exec_command, | ||
| 251 | .dev_select = ata_std_dev_select, | ||
| 252 | |||
| 253 | .freeze = ata_bmdma_freeze, | ||
| 254 | .thaw = ata_bmdma_thaw, | ||
| 255 | .error_handler = ata_bmdma_error_handler, | ||
| 256 | .post_internal_cmd = ata_bmdma_post_internal_cmd, | ||
| 257 | .cable_detect = cs5536_cable_detect, | ||
| 258 | |||
| 259 | .bmdma_setup = ata_bmdma_setup, | ||
| 260 | .bmdma_start = ata_bmdma_start, | ||
| 261 | .bmdma_stop = ata_bmdma_stop, | ||
| 262 | .bmdma_status = ata_bmdma_status, | ||
| 263 | |||
| 264 | .qc_prep = ata_qc_prep, | ||
| 265 | .qc_issue = ata_qc_issue_prot, | ||
| 266 | |||
| 267 | .data_xfer = ata_data_xfer, | ||
| 268 | |||
| 269 | .irq_handler = ata_interrupt, | ||
| 270 | .irq_clear = ata_bmdma_irq_clear, | ||
| 271 | .irq_on = ata_irq_on, | ||
| 272 | .irq_ack = ata_irq_ack, | ||
| 273 | |||
| 274 | .port_start = ata_port_start, | ||
| 275 | }; | ||
| 276 | |||
| 277 | /** | ||
| 278 | * cs5536_init_one | ||
| 279 | * @dev: PCI device | ||
| 280 | * @id: Entry in match table | ||
| 281 | * | ||
| 282 | */ | ||
| 283 | |||
| 284 | static int cs5536_init_one(struct pci_dev *dev, const struct pci_device_id *id) | ||
| 285 | { | ||
| 286 | static const struct ata_port_info info = { | ||
| 287 | .sht = &cs5536_sht, | ||
| 288 | .flags = ATA_FLAG_SLAVE_POSS, | ||
| 289 | .pio_mask = 0x1f, | ||
| 290 | .mwdma_mask = 0x07, | ||
| 291 | .udma_mask = ATA_UDMA5, | ||
| 292 | .port_ops = &cs5536_port_ops, | ||
| 293 | }; | ||
| 294 | |||
| 295 | const struct ata_port_info *ppi[] = { &info, &ata_dummy_port_info }; | ||
| 296 | u32 cfg; | ||
| 297 | |||
| 298 | if (use_msr) | ||
| 299 | printk(KERN_ERR DRV_NAME ": Using MSR regs instead of PCI\n"); | ||
| 300 | |||
| 301 | cs5536_read(dev, CFG, &cfg); | ||
| 302 | |||
| 303 | if ((cfg & IDE_CFG_CHANEN) == 0) { | ||
| 304 | printk(KERN_ERR DRV_NAME ": disabled by BIOS\n"); | ||
| 305 | return -ENODEV; | ||
| 306 | } | ||
| 307 | |||
| 308 | return ata_pci_init_one(dev, ppi); | ||
| 309 | } | ||
| 310 | |||
| 311 | static const struct pci_device_id cs5536[] = { | ||
| 312 | { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CS5536_IDE), }, | ||
| 313 | { }, | ||
| 314 | }; | ||
| 315 | |||
| 316 | static struct pci_driver cs5536_pci_driver = { | ||
| 317 | .name = DRV_NAME, | ||
| 318 | .id_table = cs5536, | ||
| 319 | .probe = cs5536_init_one, | ||
| 320 | .remove = ata_pci_remove_one, | ||
| 321 | #ifdef CONFIG_PM | ||
| 322 | .suspend = ata_pci_device_suspend, | ||
| 323 | .resume = ata_pci_device_resume, | ||
| 324 | #endif | ||
| 325 | }; | ||
| 326 | |||
| 327 | static int __init cs5536_init(void) | ||
| 328 | { | ||
| 329 | return pci_register_driver(&cs5536_pci_driver); | ||
| 330 | } | ||
| 331 | |||
| 332 | static void __exit cs5536_exit(void) | ||
| 333 | { | ||
| 334 | pci_unregister_driver(&cs5536_pci_driver); | ||
| 335 | } | ||
| 336 | |||
| 337 | MODULE_AUTHOR("Martin K. Petersen"); | ||
| 338 | MODULE_DESCRIPTION("low-level driver for the CS5536 IDE controller"); | ||
| 339 | MODULE_LICENSE("GPL"); | ||
| 340 | MODULE_DEVICE_TABLE(pci, cs5536); | ||
| 341 | MODULE_VERSION(DRV_VERSION); | ||
| 342 | module_param_named(msr, use_msr, int, 0644); | ||
| 343 | MODULE_PARM_DESC(msr, "Force using MSR to configure IDE function (Default: 0)"); | ||
| 344 | |||
| 345 | module_init(cs5536_init); | ||
| 346 | module_exit(cs5536_exit); | ||
diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c index 782ff4ada9d1..5db2013230b3 100644 --- a/drivers/ata/pata_pcmcia.c +++ b/drivers/ata/pata_pcmcia.c | |||
| @@ -353,6 +353,7 @@ static void pcmcia_remove_one(struct pcmcia_device *pdev) | |||
| 353 | 353 | ||
| 354 | static struct pcmcia_device_id pcmcia_devices[] = { | 354 | static struct pcmcia_device_id pcmcia_devices[] = { |
| 355 | PCMCIA_DEVICE_FUNC_ID(4), | 355 | PCMCIA_DEVICE_FUNC_ID(4), |
| 356 | PCMCIA_DEVICE_MANF_CARD(0x0000, 0x0000), /* Corsair */ | ||
| 356 | PCMCIA_DEVICE_MANF_CARD(0x0007, 0x0000), /* Hitachi */ | 357 | PCMCIA_DEVICE_MANF_CARD(0x0007, 0x0000), /* Hitachi */ |
| 357 | PCMCIA_DEVICE_MANF_CARD(0x000a, 0x0000), /* I-O Data CFA */ | 358 | PCMCIA_DEVICE_MANF_CARD(0x000a, 0x0000), /* I-O Data CFA */ |
| 358 | PCMCIA_DEVICE_MANF_CARD(0x001c, 0x0001), /* Mitsubishi CFA */ | 359 | PCMCIA_DEVICE_MANF_CARD(0x001c, 0x0001), /* Mitsubishi CFA */ |
| @@ -378,6 +379,7 @@ static struct pcmcia_device_id pcmcia_devices[] = { | |||
| 378 | PCMCIA_DEVICE_PROD_ID12("EXP ", "CD-ROM", 0x0a5c52fd, 0x66536591), | 379 | PCMCIA_DEVICE_PROD_ID12("EXP ", "CD-ROM", 0x0a5c52fd, 0x66536591), |
| 379 | PCMCIA_DEVICE_PROD_ID12("EXP ", "PnPIDE", 0x0a5c52fd, 0x0c694728), | 380 | PCMCIA_DEVICE_PROD_ID12("EXP ", "PnPIDE", 0x0a5c52fd, 0x0c694728), |
| 380 | PCMCIA_DEVICE_PROD_ID12("FREECOM", "PCCARD-IDE", 0x5714cbf7, 0x48e0ab8e), | 381 | PCMCIA_DEVICE_PROD_ID12("FREECOM", "PCCARD-IDE", 0x5714cbf7, 0x48e0ab8e), |
| 382 | PCMCIA_DEVICE_PROD_ID12("Hyperstone", "Model1", 0x3d5b9ef5, 0xca6ab420), | ||
| 381 | PCMCIA_DEVICE_PROD_ID12("HITACHI", "FLASH", 0xf4f43949, 0x9eb86aae), | 383 | PCMCIA_DEVICE_PROD_ID12("HITACHI", "FLASH", 0xf4f43949, 0x9eb86aae), |
| 382 | PCMCIA_DEVICE_PROD_ID12("HITACHI", "microdrive", 0xf4f43949, 0xa6d76178), | 384 | PCMCIA_DEVICE_PROD_ID12("HITACHI", "microdrive", 0xf4f43949, 0xa6d76178), |
| 383 | PCMCIA_DEVICE_PROD_ID12("IBM", "microdrive", 0xb569a6e5, 0xa6d76178), | 385 | PCMCIA_DEVICE_PROD_ID12("IBM", "microdrive", 0xb569a6e5, 0xa6d76178), |
diff --git a/drivers/ata/pata_sil680.c b/drivers/ata/pata_sil680.c index 2eb75cd74a96..4dc2e73298fd 100644 --- a/drivers/ata/pata_sil680.c +++ b/drivers/ata/pata_sil680.c | |||
| @@ -279,7 +279,7 @@ static struct ata_port_operations sil680_port_ops = { | |||
| 279 | * Returns the final clock settings. | 279 | * Returns the final clock settings. |
| 280 | */ | 280 | */ |
| 281 | 281 | ||
| 282 | static u8 sil680_init_chip(struct pci_dev *pdev) | 282 | static u8 sil680_init_chip(struct pci_dev *pdev, int *try_mmio) |
| 283 | { | 283 | { |
| 284 | u32 class_rev = 0; | 284 | u32 class_rev = 0; |
| 285 | u8 tmpbyte = 0; | 285 | u8 tmpbyte = 0; |
| @@ -297,6 +297,8 @@ static u8 sil680_init_chip(struct pci_dev *pdev) | |||
| 297 | dev_dbg(&pdev->dev, "sil680: BA5_EN = %d clock = %02X\n", | 297 | dev_dbg(&pdev->dev, "sil680: BA5_EN = %d clock = %02X\n", |
| 298 | tmpbyte & 1, tmpbyte & 0x30); | 298 | tmpbyte & 1, tmpbyte & 0x30); |
| 299 | 299 | ||
| 300 | *try_mmio = (tmpbyte & 1) || pci_resource_start(pdev, 5); | ||
| 301 | |||
| 300 | switch(tmpbyte & 0x30) { | 302 | switch(tmpbyte & 0x30) { |
| 301 | case 0x00: | 303 | case 0x00: |
| 302 | /* 133 clock attempt to force it on */ | 304 | /* 133 clock attempt to force it on */ |
| @@ -361,25 +363,76 @@ static int __devinit sil680_init_one(struct pci_dev *pdev, | |||
| 361 | }; | 363 | }; |
| 362 | const struct ata_port_info *ppi[] = { &info, NULL }; | 364 | const struct ata_port_info *ppi[] = { &info, NULL }; |
| 363 | static int printed_version; | 365 | static int printed_version; |
| 366 | struct ata_host *host; | ||
| 367 | void __iomem *mmio_base; | ||
| 368 | int rc, try_mmio; | ||
| 364 | 369 | ||
| 365 | if (!printed_version++) | 370 | if (!printed_version++) |
| 366 | dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); | 371 | dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n"); |
| 367 | 372 | ||
| 368 | switch(sil680_init_chip(pdev)) | 373 | switch (sil680_init_chip(pdev, &try_mmio)) { |
| 369 | { | ||
| 370 | case 0: | 374 | case 0: |
| 371 | ppi[0] = &info_slow; | 375 | ppi[0] = &info_slow; |
| 372 | break; | 376 | break; |
| 373 | case 0x30: | 377 | case 0x30: |
| 374 | return -ENODEV; | 378 | return -ENODEV; |
| 375 | } | 379 | } |
| 380 | |||
| 381 | if (!try_mmio) | ||
| 382 | goto use_ioports; | ||
| 383 | |||
| 384 | /* Try to acquire MMIO resources and fallback to PIO if | ||
| 385 | * that fails | ||
| 386 | */ | ||
| 387 | rc = pcim_enable_device(pdev); | ||
| 388 | if (rc) | ||
| 389 | return rc; | ||
| 390 | rc = pcim_iomap_regions(pdev, 1 << SIL680_MMIO_BAR, DRV_NAME); | ||
| 391 | if (rc) | ||
| 392 | goto use_ioports; | ||
| 393 | |||
| 394 | /* Allocate host and set it up */ | ||
| 395 | host = ata_host_alloc_pinfo(&pdev->dev, ppi, 2); | ||
| 396 | if (!host) | ||
| 397 | return -ENOMEM; | ||
| 398 | host->iomap = pcim_iomap_table(pdev); | ||
| 399 | |||
| 400 | /* Setup DMA masks */ | ||
| 401 | rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); | ||
| 402 | if (rc) | ||
| 403 | return rc; | ||
| 404 | rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK); | ||
| 405 | if (rc) | ||
| 406 | return rc; | ||
| 407 | pci_set_master(pdev); | ||
| 408 | |||
| 409 | /* Get MMIO base and initialize port addresses */ | ||
| 410 | mmio_base = host->iomap[SIL680_MMIO_BAR]; | ||
| 411 | host->ports[0]->ioaddr.bmdma_addr = mmio_base + 0x00; | ||
| 412 | host->ports[0]->ioaddr.cmd_addr = mmio_base + 0x80; | ||
| 413 | host->ports[0]->ioaddr.ctl_addr = mmio_base + 0x8a; | ||
| 414 | host->ports[0]->ioaddr.altstatus_addr = mmio_base + 0x8a; | ||
| 415 | ata_std_ports(&host->ports[0]->ioaddr); | ||
| 416 | host->ports[1]->ioaddr.bmdma_addr = mmio_base + 0x08; | ||
| 417 | host->ports[1]->ioaddr.cmd_addr = mmio_base + 0xc0; | ||
| 418 | host->ports[1]->ioaddr.ctl_addr = mmio_base + 0xca; | ||
| 419 | host->ports[1]->ioaddr.altstatus_addr = mmio_base + 0xca; | ||
| 420 | ata_std_ports(&host->ports[1]->ioaddr); | ||
| 421 | |||
| 422 | /* Register & activate */ | ||
| 423 | return ata_host_activate(host, pdev->irq, ata_interrupt, IRQF_SHARED, | ||
| 424 | &sil680_sht); | ||
| 425 | |||
| 426 | use_ioports: | ||
| 376 | return ata_pci_init_one(pdev, ppi); | 427 | return ata_pci_init_one(pdev, ppi); |
| 377 | } | 428 | } |
| 378 | 429 | ||
| 379 | #ifdef CONFIG_PM | 430 | #ifdef CONFIG_PM |
| 380 | static int sil680_reinit_one(struct pci_dev *pdev) | 431 | static int sil680_reinit_one(struct pci_dev *pdev) |
| 381 | { | 432 | { |
| 382 | sil680_init_chip(pdev); | 433 | int try_mmio; |
| 434 | |||
| 435 | sil680_init_chip(pdev, &try_mmio); | ||
| 383 | return ata_pci_device_resume(pdev); | 436 | return ata_pci_device_resume(pdev); |
| 384 | } | 437 | } |
| 385 | #endif | 438 | #endif |
diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c index 40557fe2ffdf..240a8920d0bd 100644 --- a/drivers/ata/sata_nv.c +++ b/drivers/ata/sata_nv.c | |||
| @@ -169,6 +169,35 @@ enum { | |||
| 169 | NV_ADMA_PORT_REGISTER_MODE = (1 << 0), | 169 | NV_ADMA_PORT_REGISTER_MODE = (1 << 0), |
| 170 | NV_ADMA_ATAPI_SETUP_COMPLETE = (1 << 1), | 170 | NV_ADMA_ATAPI_SETUP_COMPLETE = (1 << 1), |
| 171 | 171 | ||
| 172 | /* MCP55 reg offset */ | ||
| 173 | NV_CTL_MCP55 = 0x400, | ||
| 174 | NV_INT_STATUS_MCP55 = 0x440, | ||
| 175 | NV_INT_ENABLE_MCP55 = 0x444, | ||
| 176 | NV_NCQ_REG_MCP55 = 0x448, | ||
| 177 | |||
| 178 | /* MCP55 */ | ||
| 179 | NV_INT_ALL_MCP55 = 0xffff, | ||
| 180 | NV_INT_PORT_SHIFT_MCP55 = 16, /* each port occupies 16 bits */ | ||
| 181 | NV_INT_MASK_MCP55 = NV_INT_ALL_MCP55 & 0xfffd, | ||
| 182 | |||
| 183 | /* SWNCQ ENABLE BITS*/ | ||
| 184 | NV_CTL_PRI_SWNCQ = 0x02, | ||
| 185 | NV_CTL_SEC_SWNCQ = 0x04, | ||
| 186 | |||
| 187 | /* SW NCQ status bits*/ | ||
| 188 | NV_SWNCQ_IRQ_DEV = (1 << 0), | ||
| 189 | NV_SWNCQ_IRQ_PM = (1 << 1), | ||
| 190 | NV_SWNCQ_IRQ_ADDED = (1 << 2), | ||
| 191 | NV_SWNCQ_IRQ_REMOVED = (1 << 3), | ||
| 192 | |||
| 193 | NV_SWNCQ_IRQ_BACKOUT = (1 << 4), | ||
| 194 | NV_SWNCQ_IRQ_SDBFIS = (1 << 5), | ||
| 195 | NV_SWNCQ_IRQ_DHREGFIS = (1 << 6), | ||
| 196 | NV_SWNCQ_IRQ_DMASETUP = (1 << 7), | ||
| 197 | |||
| 198 | NV_SWNCQ_IRQ_HOTPLUG = NV_SWNCQ_IRQ_ADDED | | ||
| 199 | NV_SWNCQ_IRQ_REMOVED, | ||
| 200 | |||
| 172 | }; | 201 | }; |
| 173 | 202 | ||
| 174 | /* ADMA Physical Region Descriptor - one SG segment */ | 203 | /* ADMA Physical Region Descriptor - one SG segment */ |
| @@ -226,6 +255,42 @@ struct nv_host_priv { | |||
| 226 | unsigned long type; | 255 | unsigned long type; |
| 227 | }; | 256 | }; |
| 228 | 257 | ||
| 258 | struct defer_queue { | ||
| 259 | u32 defer_bits; | ||
| 260 | unsigned int head; | ||
| 261 | unsigned int tail; | ||
| 262 | unsigned int tag[ATA_MAX_QUEUE]; | ||
| 263 | }; | ||
| 264 | |||
| 265 | enum ncq_saw_flag_list { | ||
| 266 | ncq_saw_d2h = (1U << 0), | ||
| 267 | ncq_saw_dmas = (1U << 1), | ||
| 268 | ncq_saw_sdb = (1U << 2), | ||
| 269 | ncq_saw_backout = (1U << 3), | ||
| 270 | }; | ||
| 271 | |||
| 272 | struct nv_swncq_port_priv { | ||
| 273 | struct ata_prd *prd; /* our SG list */ | ||
| 274 | dma_addr_t prd_dma; /* and its DMA mapping */ | ||
| 275 | void __iomem *sactive_block; | ||
| 276 | void __iomem *irq_block; | ||
| 277 | void __iomem *tag_block; | ||
| 278 | u32 qc_active; | ||
| 279 | |||
| 280 | unsigned int last_issue_tag; | ||
| 281 | |||
| 282 | /* fifo circular queue to store deferral command */ | ||
| 283 | struct defer_queue defer_queue; | ||
| 284 | |||
| 285 | /* for NCQ interrupt analysis */ | ||
| 286 | u32 dhfis_bits; | ||
| 287 | u32 dmafis_bits; | ||
| 288 | u32 sdbfis_bits; | ||
| 289 | |||
| 290 | unsigned int ncq_flags; | ||
| 291 | }; | ||
| 292 | |||
| 293 | |||
| 229 | #define NV_ADMA_CHECK_INTR(GCTL, PORT) ((GCTL) & ( 1 << (19 + (12 * (PORT))))) | 294 | #define NV_ADMA_CHECK_INTR(GCTL, PORT) ((GCTL) & ( 1 << (19 + (12 * (PORT))))) |
| 230 | 295 | ||
| 231 | static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); | 296 | static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); |
| @@ -263,13 +328,29 @@ static void nv_adma_host_stop(struct ata_host *host); | |||
| 263 | static void nv_adma_post_internal_cmd(struct ata_queued_cmd *qc); | 328 | static void nv_adma_post_internal_cmd(struct ata_queued_cmd *qc); |
| 264 | static void nv_adma_tf_read(struct ata_port *ap, struct ata_taskfile *tf); | 329 | static void nv_adma_tf_read(struct ata_port *ap, struct ata_taskfile *tf); |
| 265 | 330 | ||
| 331 | static void nv_mcp55_thaw(struct ata_port *ap); | ||
| 332 | static void nv_mcp55_freeze(struct ata_port *ap); | ||
| 333 | static void nv_swncq_error_handler(struct ata_port *ap); | ||
| 334 | static int nv_swncq_slave_config(struct scsi_device *sdev); | ||
| 335 | static int nv_swncq_port_start(struct ata_port *ap); | ||
| 336 | static void nv_swncq_qc_prep(struct ata_queued_cmd *qc); | ||
| 337 | static void nv_swncq_fill_sg(struct ata_queued_cmd *qc); | ||
| 338 | static unsigned int nv_swncq_qc_issue(struct ata_queued_cmd *qc); | ||
| 339 | static void nv_swncq_irq_clear(struct ata_port *ap, u16 fis); | ||
| 340 | static irqreturn_t nv_swncq_interrupt(int irq, void *dev_instance); | ||
| 341 | #ifdef CONFIG_PM | ||
| 342 | static int nv_swncq_port_suspend(struct ata_port *ap, pm_message_t mesg); | ||
| 343 | static int nv_swncq_port_resume(struct ata_port *ap); | ||
| 344 | #endif | ||
| 345 | |||
| 266 | enum nv_host_type | 346 | enum nv_host_type |
| 267 | { | 347 | { |
| 268 | GENERIC, | 348 | GENERIC, |
| 269 | NFORCE2, | 349 | NFORCE2, |
| 270 | NFORCE3 = NFORCE2, /* NF2 == NF3 as far as sata_nv is concerned */ | 350 | NFORCE3 = NFORCE2, /* NF2 == NF3 as far as sata_nv is concerned */ |
| 271 | CK804, | 351 | CK804, |
| 272 | ADMA | 352 | ADMA, |
| 353 | SWNCQ, | ||
| 273 | }; | 354 | }; |
| 274 | 355 | ||
| 275 | static const struct pci_device_id nv_pci_tbl[] = { | 356 | static const struct pci_device_id nv_pci_tbl[] = { |
| @@ -280,13 +361,13 @@ static const struct pci_device_id nv_pci_tbl[] = { | |||
| 280 | { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA2), CK804 }, | 361 | { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA2), CK804 }, |
| 281 | { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA), CK804 }, | 362 | { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA), CK804 }, |
| 282 | { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2), CK804 }, | 363 | { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2), CK804 }, |
| 283 | { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA), GENERIC }, | 364 | { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA), SWNCQ }, |
| 284 | { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA2), GENERIC }, | 365 | { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA2), SWNCQ }, |
| 285 | { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA), GENERIC }, | 366 | { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA), SWNCQ }, |
| 286 | { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2), GENERIC }, | 367 | { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2), SWNCQ }, |
| 287 | { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA), GENERIC }, | 368 | { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA), SWNCQ }, |
| 288 | { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA2), GENERIC }, | 369 | { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA2), SWNCQ }, |
| 289 | { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA3), GENERIC }, | 370 | { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA3), SWNCQ }, |
| 290 | 371 | ||
| 291 | { } /* terminate list */ | 372 | { } /* terminate list */ |
| 292 | }; | 373 | }; |
| @@ -339,6 +420,25 @@ static struct scsi_host_template nv_adma_sht = { | |||
| 339 | .bios_param = ata_std_bios_param, | 420 | .bios_param = ata_std_bios_param, |
| 340 | }; | 421 | }; |
| 341 | 422 | ||
| 423 | static struct scsi_host_template nv_swncq_sht = { | ||
| 424 | .module = THIS_MODULE, | ||
| 425 | .name = DRV_NAME, | ||
| 426 | .ioctl = ata_scsi_ioctl, | ||
| 427 | .queuecommand = ata_scsi_queuecmd, | ||
| 428 | .change_queue_depth = ata_scsi_change_queue_depth, | ||
| 429 | .can_queue = ATA_MAX_QUEUE, | ||
| 430 | .this_id = ATA_SHT_THIS_ID, | ||
| 431 | .sg_tablesize = LIBATA_MAX_PRD, | ||
| 432 | .cmd_per_lun = ATA_SHT_CMD_PER_LUN, | ||
| 433 | .emulated = ATA_SHT_EMULATED, | ||
| 434 | .use_clustering = ATA_SHT_USE_CLUSTERING, | ||
| 435 | .proc_name = DRV_NAME, | ||
| 436 | .dma_boundary = ATA_DMA_BOUNDARY, | ||
| 437 | .slave_configure = nv_swncq_slave_config, | ||
| 438 | .slave_destroy = ata_scsi_slave_destroy, | ||
| 439 | .bios_param = ata_std_bios_param, | ||
| 440 | }; | ||
| 441 | |||
| 342 | static const struct ata_port_operations nv_generic_ops = { | 442 | static const struct ata_port_operations nv_generic_ops = { |
| 343 | .tf_load = ata_tf_load, | 443 | .tf_load = ata_tf_load, |
| 344 | .tf_read = ata_tf_read, | 444 | .tf_read = ata_tf_read, |
| @@ -444,6 +544,35 @@ static const struct ata_port_operations nv_adma_ops = { | |||
| 444 | .host_stop = nv_adma_host_stop, | 544 | .host_stop = nv_adma_host_stop, |
| 445 | }; | 545 | }; |
| 446 | 546 | ||
| 547 | static const struct ata_port_operations nv_swncq_ops = { | ||
| 548 | .tf_load = ata_tf_load, | ||
| 549 | .tf_read = ata_tf_read, | ||
| 550 | .exec_command = ata_exec_command, | ||
| 551 | .check_status = ata_check_status, | ||
| 552 | .dev_select = ata_std_dev_select, | ||
| 553 | .bmdma_setup = ata_bmdma_setup, | ||
| 554 | .bmdma_start = ata_bmdma_start, | ||
| 555 | .bmdma_stop = ata_bmdma_stop, | ||
| 556 | .bmdma_status = ata_bmdma_status, | ||
| 557 | .qc_defer = ata_std_qc_defer, | ||
| 558 | .qc_prep = nv_swncq_qc_prep, | ||
| 559 | .qc_issue = nv_swncq_qc_issue, | ||
| 560 | .freeze = nv_mcp55_freeze, | ||
| 561 | .thaw = nv_mcp55_thaw, | ||
| 562 | .error_handler = nv_swncq_error_handler, | ||
| 563 | .post_internal_cmd = ata_bmdma_post_internal_cmd, | ||
| 564 | .data_xfer = ata_data_xfer, | ||
| 565 | .irq_clear = ata_bmdma_irq_clear, | ||
| 566 | .irq_on = ata_irq_on, | ||
| 567 | .scr_read = nv_scr_read, | ||
| 568 | .scr_write = nv_scr_write, | ||
| 569 | #ifdef CONFIG_PM | ||
| 570 | .port_suspend = nv_swncq_port_suspend, | ||
| 571 | .port_resume = nv_swncq_port_resume, | ||
| 572 | #endif | ||
| 573 | .port_start = nv_swncq_port_start, | ||
| 574 | }; | ||
| 575 | |||
| 447 | static const struct ata_port_info nv_port_info[] = { | 576 | static const struct ata_port_info nv_port_info[] = { |
| 448 | /* generic */ | 577 | /* generic */ |
| 449 | { | 578 | { |
| @@ -490,6 +619,18 @@ static const struct ata_port_info nv_port_info[] = { | |||
| 490 | .port_ops = &nv_adma_ops, | 619 | .port_ops = &nv_adma_ops, |
| 491 | .irq_handler = nv_adma_interrupt, | 620 | .irq_handler = nv_adma_interrupt, |
| 492 | }, | 621 | }, |
| 622 | /* SWNCQ */ | ||
| 623 | { | ||
| 624 | .sht = &nv_swncq_sht, | ||
| 625 | .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | | ||
| 626 | ATA_FLAG_NCQ, | ||
| 627 | .link_flags = ATA_LFLAG_HRST_TO_RESUME, | ||
| 628 | .pio_mask = NV_PIO_MASK, | ||
| 629 | .mwdma_mask = NV_MWDMA_MASK, | ||
| 630 | .udma_mask = NV_UDMA_MASK, | ||
| 631 | .port_ops = &nv_swncq_ops, | ||
| 632 | .irq_handler = nv_swncq_interrupt, | ||
| 633 | }, | ||
| 493 | }; | 634 | }; |
| 494 | 635 | ||
| 495 | MODULE_AUTHOR("NVIDIA"); | 636 | MODULE_AUTHOR("NVIDIA"); |
| @@ -499,6 +640,7 @@ MODULE_DEVICE_TABLE(pci, nv_pci_tbl); | |||
| 499 | MODULE_VERSION(DRV_VERSION); | 640 | MODULE_VERSION(DRV_VERSION); |
| 500 | 641 | ||
| 501 | static int adma_enabled = 1; | 642 | static int adma_enabled = 1; |
| 643 | static int swncq_enabled; | ||
| 502 | 644 | ||
| 503 | static void nv_adma_register_mode(struct ata_port *ap) | 645 | static void nv_adma_register_mode(struct ata_port *ap) |
| 504 | { | 646 | { |
| @@ -1452,6 +1594,34 @@ static void nv_ck804_thaw(struct ata_port *ap) | |||
| 1452 | writeb(mask, mmio_base + NV_INT_ENABLE_CK804); | 1594 | writeb(mask, mmio_base + NV_INT_ENABLE_CK804); |
| 1453 | } | 1595 | } |
| 1454 | 1596 | ||
| 1597 | static void nv_mcp55_freeze(struct ata_port *ap) | ||
| 1598 | { | ||
| 1599 | void __iomem *mmio_base = ap->host->iomap[NV_MMIO_BAR]; | ||
| 1600 | int shift = ap->port_no * NV_INT_PORT_SHIFT_MCP55; | ||
| 1601 | u32 mask; | ||
| 1602 | |||
| 1603 | writel(NV_INT_ALL_MCP55 << shift, mmio_base + NV_INT_STATUS_MCP55); | ||
| 1604 | |||
| 1605 | mask = readl(mmio_base + NV_INT_ENABLE_MCP55); | ||
| 1606 | mask &= ~(NV_INT_ALL_MCP55 << shift); | ||
| 1607 | writel(mask, mmio_base + NV_INT_ENABLE_MCP55); | ||
| 1608 | ata_bmdma_freeze(ap); | ||
| 1609 | } | ||
| 1610 | |||
| 1611 | static void nv_mcp55_thaw(struct ata_port *ap) | ||
| 1612 | { | ||
| 1613 | void __iomem *mmio_base = ap->host->iomap[NV_MMIO_BAR]; | ||
| 1614 | int shift = ap->port_no * NV_INT_PORT_SHIFT_MCP55; | ||
| 1615 | u32 mask; | ||
| 1616 | |||
| 1617 | writel(NV_INT_ALL_MCP55 << shift, mmio_base + NV_INT_STATUS_MCP55); | ||
| 1618 | |||
| 1619 | mask = readl(mmio_base + NV_INT_ENABLE_MCP55); | ||
| 1620 | mask |= (NV_INT_MASK_MCP55 << shift); | ||
| 1621 | writel(mask, mmio_base + NV_INT_ENABLE_MCP55); | ||
| 1622 | ata_bmdma_thaw(ap); | ||
| 1623 | } | ||
| 1624 | |||
| 1455 | static int nv_hardreset(struct ata_link *link, unsigned int *class, | 1625 | static int nv_hardreset(struct ata_link *link, unsigned int *class, |
| 1456 | unsigned long deadline) | 1626 | unsigned long deadline) |
| 1457 | { | 1627 | { |
| @@ -1525,6 +1695,663 @@ static void nv_adma_error_handler(struct ata_port *ap) | |||
| 1525 | nv_hardreset, ata_std_postreset); | 1695 | nv_hardreset, ata_std_postreset); |
| 1526 | } | 1696 | } |
| 1527 | 1697 | ||
| 1698 | static void nv_swncq_qc_to_dq(struct ata_port *ap, struct ata_queued_cmd *qc) | ||
| 1699 | { | ||
| 1700 | struct nv_swncq_port_priv *pp = ap->private_data; | ||
| 1701 | struct defer_queue *dq = &pp->defer_queue; | ||
| 1702 | |||
| 1703 | /* queue is full */ | ||
| 1704 | WARN_ON(dq->tail - dq->head == ATA_MAX_QUEUE); | ||
| 1705 | dq->defer_bits |= (1 << qc->tag); | ||
| 1706 | dq->tag[dq->tail++ & (ATA_MAX_QUEUE - 1)] = qc->tag; | ||
| 1707 | } | ||
| 1708 | |||
| 1709 | static struct ata_queued_cmd *nv_swncq_qc_from_dq(struct ata_port *ap) | ||
| 1710 | { | ||
| 1711 | struct nv_swncq_port_priv *pp = ap->private_data; | ||
| 1712 | struct defer_queue *dq = &pp->defer_queue; | ||
| 1713 | unsigned int tag; | ||
| 1714 | |||
| 1715 | if (dq->head == dq->tail) /* null queue */ | ||
| 1716 | return NULL; | ||
| 1717 | |||
| 1718 | tag = dq->tag[dq->head & (ATA_MAX_QUEUE - 1)]; | ||
| 1719 | dq->tag[dq->head++ & (ATA_MAX_QUEUE - 1)] = ATA_TAG_POISON; | ||
| 1720 | WARN_ON(!(dq->defer_bits & (1 << tag))); | ||
| 1721 | dq->defer_bits &= ~(1 << tag); | ||
| 1722 | |||
| 1723 | return ata_qc_from_tag(ap, tag); | ||
| 1724 | } | ||
| 1725 | |||
| 1726 | static void nv_swncq_fis_reinit(struct ata_port *ap) | ||
| 1727 | { | ||
| 1728 | struct nv_swncq_port_priv *pp = ap->private_data; | ||
| 1729 | |||
| 1730 | pp->dhfis_bits = 0; | ||
| 1731 | pp->dmafis_bits = 0; | ||
| 1732 | pp->sdbfis_bits = 0; | ||
| 1733 | pp->ncq_flags = 0; | ||
| 1734 | } | ||
| 1735 | |||
| 1736 | static void nv_swncq_pp_reinit(struct ata_port *ap) | ||
| 1737 | { | ||
| 1738 | struct nv_swncq_port_priv *pp = ap->private_data; | ||
| 1739 | struct defer_queue *dq = &pp->defer_queue; | ||
| 1740 | |||
| 1741 | dq->head = 0; | ||
| 1742 | dq->tail = 0; | ||
| 1743 | dq->defer_bits = 0; | ||
| 1744 | pp->qc_active = 0; | ||
| 1745 | pp->last_issue_tag = ATA_TAG_POISON; | ||
| 1746 | nv_swncq_fis_reinit(ap); | ||
| 1747 | } | ||
| 1748 | |||
| 1749 | static void nv_swncq_irq_clear(struct ata_port *ap, u16 fis) | ||
| 1750 | { | ||
| 1751 | struct nv_swncq_port_priv *pp = ap->private_data; | ||
| 1752 | |||
| 1753 | writew(fis, pp->irq_block); | ||
| 1754 | } | ||
| 1755 | |||
| 1756 | static void __ata_bmdma_stop(struct ata_port *ap) | ||
| 1757 | { | ||
| 1758 | struct ata_queued_cmd qc; | ||
| 1759 | |||
| 1760 | qc.ap = ap; | ||
| 1761 | ata_bmdma_stop(&qc); | ||
| 1762 | } | ||
| 1763 | |||
| 1764 | static void nv_swncq_ncq_stop(struct ata_port *ap) | ||
| 1765 | { | ||
| 1766 | struct nv_swncq_port_priv *pp = ap->private_data; | ||
| 1767 | unsigned int i; | ||
| 1768 | u32 sactive; | ||
| 1769 | u32 done_mask; | ||
| 1770 | |||
| 1771 | ata_port_printk(ap, KERN_ERR, | ||
| 1772 | "EH in SWNCQ mode,QC:qc_active 0x%X sactive 0x%X\n", | ||
| 1773 | ap->qc_active, ap->link.sactive); | ||
| 1774 | ata_port_printk(ap, KERN_ERR, | ||
| 1775 | "SWNCQ:qc_active 0x%X defer_bits 0x%X last_issue_tag 0x%x\n " | ||
| 1776 | "dhfis 0x%X dmafis 0x%X sdbfis 0x%X\n", | ||
| 1777 | pp->qc_active, pp->defer_queue.defer_bits, pp->last_issue_tag, | ||
| 1778 | pp->dhfis_bits, pp->dmafis_bits, pp->sdbfis_bits); | ||
| 1779 | |||
| 1780 | ata_port_printk(ap, KERN_ERR, "ATA_REG 0x%X ERR_REG 0x%X\n", | ||
| 1781 | ap->ops->check_status(ap), | ||
| 1782 | ioread8(ap->ioaddr.error_addr)); | ||
| 1783 | |||
| 1784 | sactive = readl(pp->sactive_block); | ||
| 1785 | done_mask = pp->qc_active ^ sactive; | ||
| 1786 | |||
| 1787 | ata_port_printk(ap, KERN_ERR, "tag : dhfis dmafis sdbfis sacitve\n"); | ||
| 1788 | for (i = 0; i < ATA_MAX_QUEUE; i++) { | ||
| 1789 | u8 err = 0; | ||
| 1790 | if (pp->qc_active & (1 << i)) | ||
| 1791 | err = 0; | ||
| 1792 | else if (done_mask & (1 << i)) | ||
| 1793 | err = 1; | ||
| 1794 | else | ||
| 1795 | continue; | ||
| 1796 | |||
| 1797 | ata_port_printk(ap, KERN_ERR, | ||
| 1798 | "tag 0x%x: %01x %01x %01x %01x %s\n", i, | ||
| 1799 | (pp->dhfis_bits >> i) & 0x1, | ||
| 1800 | (pp->dmafis_bits >> i) & 0x1, | ||
| 1801 | (pp->sdbfis_bits >> i) & 0x1, | ||
| 1802 | (sactive >> i) & 0x1, | ||
| 1803 | (err ? "error! tag doesn't exit" : " ")); | ||
| 1804 | } | ||
| 1805 | |||
| 1806 | nv_swncq_pp_reinit(ap); | ||
| 1807 | ap->ops->irq_clear(ap); | ||
| 1808 | __ata_bmdma_stop(ap); | ||
| 1809 | nv_swncq_irq_clear(ap, 0xffff); | ||
| 1810 | } | ||
| 1811 | |||
| 1812 | static void nv_swncq_error_handler(struct ata_port *ap) | ||
| 1813 | { | ||
| 1814 | struct ata_eh_context *ehc = &ap->link.eh_context; | ||
| 1815 | |||
| 1816 | if (ap->link.sactive) { | ||
| 1817 | nv_swncq_ncq_stop(ap); | ||
| 1818 | ehc->i.action |= ATA_EH_HARDRESET; | ||
| 1819 | } | ||
| 1820 | |||
| 1821 | ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset, | ||
| 1822 | nv_hardreset, ata_std_postreset); | ||
| 1823 | } | ||
| 1824 | |||
| 1825 | #ifdef CONFIG_PM | ||
| 1826 | static int nv_swncq_port_suspend(struct ata_port *ap, pm_message_t mesg) | ||
| 1827 | { | ||
| 1828 | void __iomem *mmio = ap->host->iomap[NV_MMIO_BAR]; | ||
| 1829 | u32 tmp; | ||
| 1830 | |||
| 1831 | /* clear irq */ | ||
| 1832 | writel(~0, mmio + NV_INT_STATUS_MCP55); | ||
| 1833 | |||
| 1834 | /* disable irq */ | ||
| 1835 | writel(0, mmio + NV_INT_ENABLE_MCP55); | ||
| 1836 | |||
| 1837 | /* disable swncq */ | ||
| 1838 | tmp = readl(mmio + NV_CTL_MCP55); | ||
| 1839 | tmp &= ~(NV_CTL_PRI_SWNCQ | NV_CTL_SEC_SWNCQ); | ||
| 1840 | writel(tmp, mmio + NV_CTL_MCP55); | ||
| 1841 | |||
| 1842 | return 0; | ||
| 1843 | } | ||
| 1844 | |||
| 1845 | static int nv_swncq_port_resume(struct ata_port *ap) | ||
| 1846 | { | ||
| 1847 | void __iomem *mmio = ap->host->iomap[NV_MMIO_BAR]; | ||
| 1848 | u32 tmp; | ||
| 1849 | |||
| 1850 | /* clear irq */ | ||
| 1851 | writel(~0, mmio + NV_INT_STATUS_MCP55); | ||
| 1852 | |||
| 1853 | /* enable irq */ | ||
| 1854 | writel(0x00fd00fd, mmio + NV_INT_ENABLE_MCP55); | ||
| 1855 | |||
| 1856 | /* enable swncq */ | ||
| 1857 | tmp = readl(mmio + NV_CTL_MCP55); | ||
| 1858 | writel(tmp | NV_CTL_PRI_SWNCQ | NV_CTL_SEC_SWNCQ, mmio + NV_CTL_MCP55); | ||
| 1859 | |||
| 1860 | return 0; | ||
| 1861 | } | ||
| 1862 | #endif | ||
| 1863 | |||
| 1864 | static void nv_swncq_host_init(struct ata_host *host) | ||
| 1865 | { | ||
| 1866 | u32 tmp; | ||
| 1867 | void __iomem *mmio = host->iomap[NV_MMIO_BAR]; | ||
| 1868 | struct pci_dev *pdev = to_pci_dev(host->dev); | ||
| 1869 | u8 regval; | ||
| 1870 | |||
| 1871 | /* disable ECO 398 */ | ||
| 1872 | pci_read_config_byte(pdev, 0x7f, ®val); | ||
| 1873 | regval &= ~(1 << 7); | ||
| 1874 | pci_write_config_byte(pdev, 0x7f, regval); | ||
| 1875 | |||
| 1876 | /* enable swncq */ | ||
| 1877 | tmp = readl(mmio + NV_CTL_MCP55); | ||
| 1878 | VPRINTK("HOST_CTL:0x%X\n", tmp); | ||
| 1879 | writel(tmp | NV_CTL_PRI_SWNCQ | NV_CTL_SEC_SWNCQ, mmio + NV_CTL_MCP55); | ||
| 1880 | |||
| 1881 | /* enable irq intr */ | ||
| 1882 | tmp = readl(mmio + NV_INT_ENABLE_MCP55); | ||
| 1883 | VPRINTK("HOST_ENABLE:0x%X\n", tmp); | ||
| 1884 | writel(tmp | 0x00fd00fd, mmio + NV_INT_ENABLE_MCP55); | ||
| 1885 | |||
| 1886 | /* clear port irq */ | ||
| 1887 | writel(~0x0, mmio + NV_INT_STATUS_MCP55); | ||
| 1888 | } | ||
| 1889 | |||
| 1890 | static int nv_swncq_slave_config(struct scsi_device *sdev) | ||
| 1891 | { | ||
| 1892 | struct ata_port *ap = ata_shost_to_port(sdev->host); | ||
| 1893 | struct pci_dev *pdev = to_pci_dev(ap->host->dev); | ||
| 1894 | struct ata_device *dev; | ||
| 1895 | int rc; | ||
| 1896 | u8 rev; | ||
| 1897 | u8 check_maxtor = 0; | ||
| 1898 | unsigned char model_num[ATA_ID_PROD_LEN + 1]; | ||
| 1899 | |||
| 1900 | rc = ata_scsi_slave_config(sdev); | ||
| 1901 | if (sdev->id >= ATA_MAX_DEVICES || sdev->channel || sdev->lun) | ||
| 1902 | /* Not a proper libata device, ignore */ | ||
| 1903 | return rc; | ||
| 1904 | |||
| 1905 | dev = &ap->link.device[sdev->id]; | ||
| 1906 | if (!(ap->flags & ATA_FLAG_NCQ) || dev->class == ATA_DEV_ATAPI) | ||
| 1907 | return rc; | ||
| 1908 | |||
| 1909 | /* if MCP51 and Maxtor, then disable ncq */ | ||
| 1910 | if (pdev->device == PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA || | ||
| 1911 | pdev->device == PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA2) | ||
| 1912 | check_maxtor = 1; | ||
| 1913 | |||
| 1914 | /* if MCP55 and rev <= a2 and Maxtor, then disable ncq */ | ||
| 1915 | if (pdev->device == PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA || | ||
| 1916 | pdev->device == PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2) { | ||
| 1917 | pci_read_config_byte(pdev, 0x8, &rev); | ||
| 1918 | if (rev <= 0xa2) | ||
| 1919 | check_maxtor = 1; | ||
| 1920 | } | ||
| 1921 | |||
| 1922 | if (!check_maxtor) | ||
| 1923 | return rc; | ||
| 1924 | |||
| 1925 | ata_id_c_string(dev->id, model_num, ATA_ID_PROD, sizeof(model_num)); | ||
| 1926 | |||
| 1927 | if (strncmp(model_num, "Maxtor", 6) == 0) { | ||
| 1928 | ata_scsi_change_queue_depth(sdev, 1); | ||
| 1929 | ata_dev_printk(dev, KERN_NOTICE, | ||
| 1930 | "Disabling SWNCQ mode (depth %x)\n", sdev->queue_depth); | ||
| 1931 | } | ||
| 1932 | |||
| 1933 | return rc; | ||
| 1934 | } | ||
| 1935 | |||
| 1936 | static int nv_swncq_port_start(struct ata_port *ap) | ||
| 1937 | { | ||
| 1938 | struct device *dev = ap->host->dev; | ||
| 1939 | void __iomem *mmio = ap->host->iomap[NV_MMIO_BAR]; | ||
| 1940 | struct nv_swncq_port_priv *pp; | ||
| 1941 | int rc; | ||
| 1942 | |||
| 1943 | rc = ata_port_start(ap); | ||
| 1944 | if (rc) | ||
| 1945 | return rc; | ||
| 1946 | |||
| 1947 | pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL); | ||
| 1948 | if (!pp) | ||
| 1949 | return -ENOMEM; | ||
| 1950 | |||
| 1951 | pp->prd = dmam_alloc_coherent(dev, ATA_PRD_TBL_SZ * ATA_MAX_QUEUE, | ||
| 1952 | &pp->prd_dma, GFP_KERNEL); | ||
| 1953 | if (!pp->prd) | ||
| 1954 | return -ENOMEM; | ||
| 1955 | memset(pp->prd, 0, ATA_PRD_TBL_SZ * ATA_MAX_QUEUE); | ||
| 1956 | |||
| 1957 | ap->private_data = pp; | ||
| 1958 | pp->sactive_block = ap->ioaddr.scr_addr + 4 * SCR_ACTIVE; | ||
| 1959 | pp->irq_block = mmio + NV_INT_STATUS_MCP55 + ap->port_no * 2; | ||
| 1960 | pp->tag_block = mmio + NV_NCQ_REG_MCP55 + ap->port_no * 2; | ||
| 1961 | |||
| 1962 | return 0; | ||
| 1963 | } | ||
| 1964 | |||
| 1965 | static void nv_swncq_qc_prep(struct ata_queued_cmd *qc) | ||
| 1966 | { | ||
| 1967 | if (qc->tf.protocol != ATA_PROT_NCQ) { | ||
| 1968 | ata_qc_prep(qc); | ||
| 1969 | return; | ||
| 1970 | } | ||
| 1971 | |||
| 1972 | if (!(qc->flags & ATA_QCFLAG_DMAMAP)) | ||
| 1973 | return; | ||
| 1974 | |||
| 1975 | nv_swncq_fill_sg(qc); | ||
| 1976 | } | ||
| 1977 | |||
| 1978 | static void nv_swncq_fill_sg(struct ata_queued_cmd *qc) | ||
| 1979 | { | ||
| 1980 | struct ata_port *ap = qc->ap; | ||
| 1981 | struct scatterlist *sg; | ||
| 1982 | unsigned int idx; | ||
| 1983 | struct nv_swncq_port_priv *pp = ap->private_data; | ||
| 1984 | struct ata_prd *prd; | ||
| 1985 | |||
| 1986 | WARN_ON(qc->__sg == NULL); | ||
| 1987 | WARN_ON(qc->n_elem == 0 && qc->pad_len == 0); | ||
| 1988 | |||
| 1989 | prd = pp->prd + ATA_MAX_PRD * qc->tag; | ||
| 1990 | |||
| 1991 | idx = 0; | ||
| 1992 | ata_for_each_sg(sg, qc) { | ||
| 1993 | u32 addr, offset; | ||
| 1994 | u32 sg_len, len; | ||
| 1995 | |||
| 1996 | addr = (u32)sg_dma_address(sg); | ||
| 1997 | sg_len = sg_dma_len(sg); | ||
| 1998 | |||
| 1999 | while (sg_len) { | ||
| 2000 | offset = addr & 0xffff; | ||
| 2001 | len = sg_len; | ||
| 2002 | if ((offset + sg_len) > 0x10000) | ||
| 2003 | len = 0x10000 - offset; | ||
| 2004 | |||
| 2005 | prd[idx].addr = cpu_to_le32(addr); | ||
| 2006 | prd[idx].flags_len = cpu_to_le32(len & 0xffff); | ||
| 2007 | |||
| 2008 | idx++; | ||
| 2009 | sg_len -= len; | ||
| 2010 | addr += len; | ||
| 2011 | } | ||
| 2012 | } | ||
| 2013 | |||
| 2014 | if (idx) | ||
| 2015 | prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT); | ||
| 2016 | } | ||
| 2017 | |||
| 2018 | static unsigned int nv_swncq_issue_atacmd(struct ata_port *ap, | ||
| 2019 | struct ata_queued_cmd *qc) | ||
| 2020 | { | ||
| 2021 | struct nv_swncq_port_priv *pp = ap->private_data; | ||
| 2022 | |||
| 2023 | if (qc == NULL) | ||
| 2024 | return 0; | ||
| 2025 | |||
| 2026 | DPRINTK("Enter\n"); | ||
| 2027 | |||
| 2028 | writel((1 << qc->tag), pp->sactive_block); | ||
| 2029 | pp->last_issue_tag = qc->tag; | ||
| 2030 | pp->dhfis_bits &= ~(1 << qc->tag); | ||
| 2031 | pp->dmafis_bits &= ~(1 << qc->tag); | ||
| 2032 | pp->qc_active |= (0x1 << qc->tag); | ||
| 2033 | |||
| 2034 | ap->ops->tf_load(ap, &qc->tf); /* load tf registers */ | ||
| 2035 | ap->ops->exec_command(ap, &qc->tf); | ||
| 2036 | |||
| 2037 | DPRINTK("Issued tag %u\n", qc->tag); | ||
| 2038 | |||
| 2039 | return 0; | ||
| 2040 | } | ||
| 2041 | |||
| 2042 | static unsigned int nv_swncq_qc_issue(struct ata_queued_cmd *qc) | ||
| 2043 | { | ||
| 2044 | struct ata_port *ap = qc->ap; | ||
| 2045 | struct nv_swncq_port_priv *pp = ap->private_data; | ||
| 2046 | |||
| 2047 | if (qc->tf.protocol != ATA_PROT_NCQ) | ||
| 2048 | return ata_qc_issue_prot(qc); | ||
| 2049 | |||
| 2050 | DPRINTK("Enter\n"); | ||
| 2051 | |||
| 2052 | if (!pp->qc_active) | ||
| 2053 | nv_swncq_issue_atacmd(ap, qc); | ||
| 2054 | else | ||
| 2055 | nv_swncq_qc_to_dq(ap, qc); /* add qc to defer queue */ | ||
| 2056 | |||
| 2057 | return 0; | ||
| 2058 | } | ||
| 2059 | |||
| 2060 | static void nv_swncq_hotplug(struct ata_port *ap, u32 fis) | ||
| 2061 | { | ||
| 2062 | u32 serror; | ||
| 2063 | struct ata_eh_info *ehi = &ap->link.eh_info; | ||
| 2064 | |||
| 2065 | ata_ehi_clear_desc(ehi); | ||
| 2066 | |||
| 2067 | /* AHCI needs SError cleared; otherwise, it might lock up */ | ||
| 2068 | sata_scr_read(&ap->link, SCR_ERROR, &serror); | ||
| 2069 | sata_scr_write(&ap->link, SCR_ERROR, serror); | ||
| 2070 | |||
| 2071 | /* analyze @irq_stat */ | ||
| 2072 | if (fis & NV_SWNCQ_IRQ_ADDED) | ||
| 2073 | ata_ehi_push_desc(ehi, "hot plug"); | ||
| 2074 | else if (fis & NV_SWNCQ_IRQ_REMOVED) | ||
| 2075 | ata_ehi_push_desc(ehi, "hot unplug"); | ||
| 2076 | |||
| 2077 | ata_ehi_hotplugged(ehi); | ||
| 2078 | |||
| 2079 | /* okay, let's hand over to EH */ | ||
| 2080 | ehi->serror |= serror; | ||
| 2081 | |||
| 2082 | ata_port_freeze(ap); | ||
| 2083 | } | ||
| 2084 | |||
| 2085 | static int nv_swncq_sdbfis(struct ata_port *ap) | ||
| 2086 | { | ||
| 2087 | struct ata_queued_cmd *qc; | ||
| 2088 | struct nv_swncq_port_priv *pp = ap->private_data; | ||
| 2089 | struct ata_eh_info *ehi = &ap->link.eh_info; | ||
| 2090 | u32 sactive; | ||
| 2091 | int nr_done = 0; | ||
| 2092 | u32 done_mask; | ||
| 2093 | int i; | ||
| 2094 | u8 host_stat; | ||
| 2095 | u8 lack_dhfis = 0; | ||
| 2096 | |||
| 2097 | host_stat = ap->ops->bmdma_status(ap); | ||
| 2098 | if (unlikely(host_stat & ATA_DMA_ERR)) { | ||
| 2099 | /* error when transfering data to/from memory */ | ||
| 2100 | ata_ehi_clear_desc(ehi); | ||
| 2101 | ata_ehi_push_desc(ehi, "BMDMA stat 0x%x", host_stat); | ||
| 2102 | ehi->err_mask |= AC_ERR_HOST_BUS; | ||
| 2103 | ehi->action |= ATA_EH_SOFTRESET; | ||
| 2104 | return -EINVAL; | ||
| 2105 | } | ||
| 2106 | |||
| 2107 | ap->ops->irq_clear(ap); | ||
| 2108 | __ata_bmdma_stop(ap); | ||
| 2109 | |||
| 2110 | sactive = readl(pp->sactive_block); | ||
| 2111 | done_mask = pp->qc_active ^ sactive; | ||
| 2112 | |||
| 2113 | if (unlikely(done_mask & sactive)) { | ||
| 2114 | ata_ehi_clear_desc(ehi); | ||
| 2115 | ata_ehi_push_desc(ehi, "illegal SWNCQ:qc_active transition" | ||
| 2116 | "(%08x->%08x)", pp->qc_active, sactive); | ||
| 2117 | ehi->err_mask |= AC_ERR_HSM; | ||
| 2118 | ehi->action |= ATA_EH_HARDRESET; | ||
| 2119 | return -EINVAL; | ||
| 2120 | } | ||
| 2121 | for (i = 0; i < ATA_MAX_QUEUE; i++) { | ||
| 2122 | if (!(done_mask & (1 << i))) | ||
| 2123 | continue; | ||
| 2124 | |||
| 2125 | qc = ata_qc_from_tag(ap, i); | ||
| 2126 | if (qc) { | ||
| 2127 | ata_qc_complete(qc); | ||
| 2128 | pp->qc_active &= ~(1 << i); | ||
| 2129 | pp->dhfis_bits &= ~(1 << i); | ||
| 2130 | pp->dmafis_bits &= ~(1 << i); | ||
| 2131 | pp->sdbfis_bits |= (1 << i); | ||
| 2132 | nr_done++; | ||
| 2133 | } | ||
| 2134 | } | ||
| 2135 | |||
| 2136 | if (!ap->qc_active) { | ||
| 2137 | DPRINTK("over\n"); | ||
| 2138 | nv_swncq_pp_reinit(ap); | ||
| 2139 | return nr_done; | ||
| 2140 | } | ||
| 2141 | |||
| 2142 | if (pp->qc_active & pp->dhfis_bits) | ||
| 2143 | return nr_done; | ||
| 2144 | |||
| 2145 | if ((pp->ncq_flags & ncq_saw_backout) || | ||
| 2146 | (pp->qc_active ^ pp->dhfis_bits)) | ||
| 2147 | /* if the controller cann't get a device to host register FIS, | ||
| 2148 | * The driver needs to reissue the new command. | ||
| 2149 | */ | ||
| 2150 | lack_dhfis = 1; | ||
| 2151 | |||
| 2152 | DPRINTK("id 0x%x QC: qc_active 0x%x," | ||
| 2153 | "SWNCQ:qc_active 0x%X defer_bits %X " | ||
| 2154 | "dhfis 0x%X dmafis 0x%X last_issue_tag %x\n", | ||
| 2155 | ap->print_id, ap->qc_active, pp->qc_active, | ||
| 2156 | pp->defer_queue.defer_bits, pp->dhfis_bits, | ||
| 2157 | pp->dmafis_bits, pp->last_issue_tag); | ||
| 2158 | |||
| 2159 | nv_swncq_fis_reinit(ap); | ||
| 2160 | |||
| 2161 | if (lack_dhfis) { | ||
| 2162 | qc = ata_qc_from_tag(ap, pp->last_issue_tag); | ||
| 2163 | nv_swncq_issue_atacmd(ap, qc); | ||
| 2164 | return nr_done; | ||
| 2165 | } | ||
| 2166 | |||
| 2167 | if (pp->defer_queue.defer_bits) { | ||
| 2168 | /* send deferral queue command */ | ||
| 2169 | qc = nv_swncq_qc_from_dq(ap); | ||
| 2170 | WARN_ON(qc == NULL); | ||
| 2171 | nv_swncq_issue_atacmd(ap, qc); | ||
| 2172 | } | ||
| 2173 | |||
| 2174 | return nr_done; | ||
| 2175 | } | ||
| 2176 | |||
| 2177 | static inline u32 nv_swncq_tag(struct ata_port *ap) | ||
| 2178 | { | ||
| 2179 | struct nv_swncq_port_priv *pp = ap->private_data; | ||
| 2180 | u32 tag; | ||
| 2181 | |||
| 2182 | tag = readb(pp->tag_block) >> 2; | ||
| 2183 | return (tag & 0x1f); | ||
| 2184 | } | ||
| 2185 | |||
| 2186 | static int nv_swncq_dmafis(struct ata_port *ap) | ||
| 2187 | { | ||
| 2188 | struct ata_queued_cmd *qc; | ||
| 2189 | unsigned int rw; | ||
| 2190 | u8 dmactl; | ||
| 2191 | u32 tag; | ||
| 2192 | struct nv_swncq_port_priv *pp = ap->private_data; | ||
| 2193 | |||
| 2194 | __ata_bmdma_stop(ap); | ||
| 2195 | tag = nv_swncq_tag(ap); | ||
| 2196 | |||
| 2197 | DPRINTK("dma setup tag 0x%x\n", tag); | ||
| 2198 | qc = ata_qc_from_tag(ap, tag); | ||
| 2199 | |||
| 2200 | if (unlikely(!qc)) | ||
| 2201 | return 0; | ||
| 2202 | |||
| 2203 | rw = qc->tf.flags & ATA_TFLAG_WRITE; | ||
| 2204 | |||
| 2205 | /* load PRD table addr. */ | ||
| 2206 | iowrite32(pp->prd_dma + ATA_PRD_TBL_SZ * qc->tag, | ||
| 2207 | ap->ioaddr.bmdma_addr + ATA_DMA_TABLE_OFS); | ||
| 2208 | |||
| 2209 | /* specify data direction, triple-check start bit is clear */ | ||
| 2210 | dmactl = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_CMD); | ||
| 2211 | dmactl &= ~ATA_DMA_WR; | ||
| 2212 | if (!rw) | ||
| 2213 | dmactl |= ATA_DMA_WR; | ||
| 2214 | |||
| 2215 | iowrite8(dmactl | ATA_DMA_START, ap->ioaddr.bmdma_addr + ATA_DMA_CMD); | ||
| 2216 | |||
| 2217 | return 1; | ||
| 2218 | } | ||
| 2219 | |||
| 2220 | static void nv_swncq_host_interrupt(struct ata_port *ap, u16 fis) | ||
| 2221 | { | ||
| 2222 | struct nv_swncq_port_priv *pp = ap->private_data; | ||
| 2223 | struct ata_queued_cmd *qc; | ||
| 2224 | struct ata_eh_info *ehi = &ap->link.eh_info; | ||
| 2225 | u32 serror; | ||
| 2226 | u8 ata_stat; | ||
| 2227 | int rc = 0; | ||
| 2228 | |||
| 2229 | ata_stat = ap->ops->check_status(ap); | ||
| 2230 | nv_swncq_irq_clear(ap, fis); | ||
| 2231 | if (!fis) | ||
| 2232 | return; | ||
| 2233 | |||
| 2234 | if (ap->pflags & ATA_PFLAG_FROZEN) | ||
| 2235 | return; | ||
| 2236 | |||
| 2237 | if (fis & NV_SWNCQ_IRQ_HOTPLUG) { | ||
| 2238 | nv_swncq_hotplug(ap, fis); | ||
| 2239 | return; | ||
| 2240 | } | ||
| 2241 | |||
| 2242 | if (!pp->qc_active) | ||
| 2243 | return; | ||
| 2244 | |||
| 2245 | if (ap->ops->scr_read(ap, SCR_ERROR, &serror)) | ||
| 2246 | return; | ||
| 2247 | ap->ops->scr_write(ap, SCR_ERROR, serror); | ||
| 2248 | |||
| 2249 | if (ata_stat & ATA_ERR) { | ||
| 2250 | ata_ehi_clear_desc(ehi); | ||
| 2251 | ata_ehi_push_desc(ehi, "Ata error. fis:0x%X", fis); | ||
| 2252 | ehi->err_mask |= AC_ERR_DEV; | ||
| 2253 | ehi->serror |= serror; | ||
| 2254 | ehi->action |= ATA_EH_SOFTRESET; | ||
| 2255 | ata_port_freeze(ap); | ||
| 2256 | return; | ||
| 2257 | } | ||
| 2258 | |||
| 2259 | if (fis & NV_SWNCQ_IRQ_BACKOUT) { | ||
| 2260 | /* If the IRQ is backout, driver must issue | ||
| 2261 | * the new command again some time later. | ||
| 2262 | */ | ||
| 2263 | pp->ncq_flags |= ncq_saw_backout; | ||
| 2264 | } | ||
| 2265 | |||
| 2266 | if (fis & NV_SWNCQ_IRQ_SDBFIS) { | ||
| 2267 | pp->ncq_flags |= ncq_saw_sdb; | ||
| 2268 | DPRINTK("id 0x%x SWNCQ: qc_active 0x%X " | ||
| 2269 | "dhfis 0x%X dmafis 0x%X sactive 0x%X\n", | ||
| 2270 | ap->print_id, pp->qc_active, pp->dhfis_bits, | ||
| 2271 | pp->dmafis_bits, readl(pp->sactive_block)); | ||
| 2272 | rc = nv_swncq_sdbfis(ap); | ||
| 2273 | if (rc < 0) | ||
| 2274 | goto irq_error; | ||
| 2275 | } | ||
| 2276 | |||
| 2277 | if (fis & NV_SWNCQ_IRQ_DHREGFIS) { | ||
| 2278 | /* The interrupt indicates the new command | ||
| 2279 | * was transmitted correctly to the drive. | ||
| 2280 | */ | ||
| 2281 | pp->dhfis_bits |= (0x1 << pp->last_issue_tag); | ||
| 2282 | pp->ncq_flags |= ncq_saw_d2h; | ||
| 2283 | if (pp->ncq_flags & (ncq_saw_sdb | ncq_saw_backout)) { | ||
| 2284 | ata_ehi_push_desc(ehi, "illegal fis transaction"); | ||
| 2285 | ehi->err_mask |= AC_ERR_HSM; | ||
| 2286 | ehi->action |= ATA_EH_HARDRESET; | ||
| 2287 | goto irq_error; | ||
| 2288 | } | ||
| 2289 | |||
| 2290 | if (!(fis & NV_SWNCQ_IRQ_DMASETUP) && | ||
| 2291 | !(pp->ncq_flags & ncq_saw_dmas)) { | ||
| 2292 | ata_stat = ap->ops->check_status(ap); | ||
| 2293 | if (ata_stat & ATA_BUSY) | ||
| 2294 | goto irq_exit; | ||
| 2295 | |||
| 2296 | if (pp->defer_queue.defer_bits) { | ||
| 2297 | DPRINTK("send next command\n"); | ||
| 2298 | qc = nv_swncq_qc_from_dq(ap); | ||
| 2299 | nv_swncq_issue_atacmd(ap, qc); | ||
| 2300 | } | ||
| 2301 | } | ||
| 2302 | } | ||
| 2303 | |||
| 2304 | if (fis & NV_SWNCQ_IRQ_DMASETUP) { | ||
| 2305 | /* program the dma controller with appropriate PRD buffers | ||
| 2306 | * and start the DMA transfer for requested command. | ||
| 2307 | */ | ||
| 2308 | pp->dmafis_bits |= (0x1 << nv_swncq_tag(ap)); | ||
| 2309 | pp->ncq_flags |= ncq_saw_dmas; | ||
| 2310 | rc = nv_swncq_dmafis(ap); | ||
| 2311 | } | ||
| 2312 | |||
| 2313 | irq_exit: | ||
| 2314 | return; | ||
| 2315 | irq_error: | ||
| 2316 | ata_ehi_push_desc(ehi, "fis:0x%x", fis); | ||
| 2317 | ata_port_freeze(ap); | ||
| 2318 | return; | ||
| 2319 | } | ||
| 2320 | |||
| 2321 | static irqreturn_t nv_swncq_interrupt(int irq, void *dev_instance) | ||
| 2322 | { | ||
| 2323 | struct ata_host *host = dev_instance; | ||
| 2324 | unsigned int i; | ||
| 2325 | unsigned int handled = 0; | ||
| 2326 | unsigned long flags; | ||
| 2327 | u32 irq_stat; | ||
| 2328 | |||
| 2329 | spin_lock_irqsave(&host->lock, flags); | ||
| 2330 | |||
| 2331 | irq_stat = readl(host->iomap[NV_MMIO_BAR] + NV_INT_STATUS_MCP55); | ||
| 2332 | |||
| 2333 | for (i = 0; i < host->n_ports; i++) { | ||
| 2334 | struct ata_port *ap = host->ports[i]; | ||
| 2335 | |||
| 2336 | if (ap && !(ap->flags & ATA_FLAG_DISABLED)) { | ||
| 2337 | if (ap->link.sactive) { | ||
| 2338 | nv_swncq_host_interrupt(ap, (u16)irq_stat); | ||
| 2339 | handled = 1; | ||
| 2340 | } else { | ||
| 2341 | if (irq_stat) /* reserve Hotplug */ | ||
| 2342 | nv_swncq_irq_clear(ap, 0xfff0); | ||
| 2343 | |||
| 2344 | handled += nv_host_intr(ap, (u8)irq_stat); | ||
| 2345 | } | ||
| 2346 | } | ||
| 2347 | irq_stat >>= NV_INT_PORT_SHIFT_MCP55; | ||
| 2348 | } | ||
| 2349 | |||
| 2350 | spin_unlock_irqrestore(&host->lock, flags); | ||
| 2351 | |||
| 2352 | return IRQ_RETVAL(handled); | ||
| 2353 | } | ||
| 2354 | |||
| 1528 | static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) | 2355 | static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) |
| 1529 | { | 2356 | { |
| 1530 | static int printed_version = 0; | 2357 | static int printed_version = 0; |
| @@ -1551,7 +2378,7 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) | |||
| 1551 | return rc; | 2378 | return rc; |
| 1552 | 2379 | ||
| 1553 | /* determine type and allocate host */ | 2380 | /* determine type and allocate host */ |
| 1554 | if (type >= CK804 && adma_enabled) { | 2381 | if (type == CK804 && adma_enabled) { |
| 1555 | dev_printk(KERN_NOTICE, &pdev->dev, "Using ADMA mode\n"); | 2382 | dev_printk(KERN_NOTICE, &pdev->dev, "Using ADMA mode\n"); |
| 1556 | type = ADMA; | 2383 | type = ADMA; |
| 1557 | } | 2384 | } |
| @@ -1597,6 +2424,9 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) | |||
| 1597 | rc = nv_adma_host_init(host); | 2424 | rc = nv_adma_host_init(host); |
| 1598 | if (rc) | 2425 | if (rc) |
| 1599 | return rc; | 2426 | return rc; |
| 2427 | } else if (type == SWNCQ && swncq_enabled) { | ||
| 2428 | dev_printk(KERN_NOTICE, &pdev->dev, "Using SWNCQ mode\n"); | ||
| 2429 | nv_swncq_host_init(host); | ||
| 1600 | } | 2430 | } |
| 1601 | 2431 | ||
| 1602 | pci_set_master(pdev); | 2432 | pci_set_master(pdev); |
| @@ -1696,3 +2526,6 @@ module_init(nv_init); | |||
| 1696 | module_exit(nv_exit); | 2526 | module_exit(nv_exit); |
| 1697 | module_param_named(adma, adma_enabled, bool, 0444); | 2527 | module_param_named(adma, adma_enabled, bool, 0444); |
| 1698 | MODULE_PARM_DESC(adma, "Enable use of ADMA (Default: true)"); | 2528 | MODULE_PARM_DESC(adma, "Enable use of ADMA (Default: true)"); |
| 2529 | module_param_named(swncq, swncq_enabled, bool, 0444); | ||
| 2530 | MODULE_PARM_DESC(swncq, "Enable use of SWNCQ (Default: false)"); | ||
| 2531 | |||
diff --git a/drivers/char/ec3104_keyb.c b/drivers/char/ec3104_keyb.c deleted file mode 100644 index 020011495d91..000000000000 --- a/drivers/char/ec3104_keyb.c +++ /dev/null | |||
| @@ -1,457 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * linux/drivers/char/ec3104_keyb.c | ||
| 3 | * | ||
| 4 | * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org> | ||
| 5 | * | ||
| 6 | * based on linux/drivers/char/pc_keyb.c, which had the following comments: | ||
| 7 | * | ||
| 8 | * Separation of the PC low-level part by Geert Uytterhoeven, May 1997 | ||
| 9 | * See keyboard.c for the whole history. | ||
| 10 | * | ||
| 11 | * Major cleanup by Martin Mares, May 1997 | ||
| 12 | * | ||
| 13 | * Combined the keyboard and PS/2 mouse handling into one file, | ||
| 14 | * because they share the same hardware. | ||
| 15 | * Johan Myreen <jem@iki.fi> 1998-10-08. | ||
| 16 | * | ||
| 17 | * Code fixes to handle mouse ACKs properly. | ||
| 18 | * C. Scott Ananian <cananian@alumni.princeton.edu> 1999-01-29. | ||
| 19 | */ | ||
| 20 | /* EC3104 note: | ||
| 21 | * This code was written without any documentation about the EC3104 chip. While | ||
| 22 | * I hope I got most of the basic functionality right, the register names I use | ||
| 23 | * are most likely completely different from those in the chip documentation. | ||
| 24 | * | ||
| 25 | * If you have any further information about the EC3104, please tell me | ||
| 26 | * (prumpf@tux.org). | ||
| 27 | */ | ||
| 28 | |||
| 29 | |||
| 30 | #include <linux/spinlock.h> | ||
| 31 | #include <linux/sched.h> | ||
| 32 | #include <linux/interrupt.h> | ||
| 33 | #include <linux/tty.h> | ||
| 34 | #include <linux/mm.h> | ||
| 35 | #include <linux/signal.h> | ||
| 36 | #include <linux/init.h> | ||
| 37 | #include <linux/kbd_ll.h> | ||
| 38 | #include <linux/delay.h> | ||
| 39 | #include <linux/random.h> | ||
| 40 | #include <linux/poll.h> | ||
| 41 | #include <linux/miscdevice.h> | ||
| 42 | #include <linux/slab.h> | ||
| 43 | #include <linux/kbd_kern.h> | ||
| 44 | #include <linux/bitops.h> | ||
| 45 | |||
| 46 | #include <asm/keyboard.h> | ||
| 47 | #include <asm/uaccess.h> | ||
| 48 | #include <asm/irq.h> | ||
| 49 | #include <asm/system.h> | ||
| 50 | #include <asm/ec3104.h> | ||
| 51 | |||
| 52 | #include <asm/io.h> | ||
| 53 | |||
| 54 | /* Some configuration switches are present in the include file... */ | ||
| 55 | |||
| 56 | #include <linux/pc_keyb.h> | ||
| 57 | |||
| 58 | #define MSR_CTS 0x10 | ||
| 59 | #define MCR_RTS 0x02 | ||
| 60 | #define LSR_DR 0x01 | ||
| 61 | #define LSR_BOTH_EMPTY 0x60 | ||
| 62 | |||
| 63 | static struct e5_struct { | ||
| 64 | u8 packet[8]; | ||
| 65 | int pos; | ||
| 66 | int length; | ||
| 67 | |||
| 68 | u8 cached_mcr; | ||
| 69 | u8 last_msr; | ||
| 70 | } ec3104_keyb; | ||
| 71 | |||
| 72 | /* Simple translation table for the SysRq keys */ | ||
| 73 | |||
| 74 | |||
| 75 | #ifdef CONFIG_MAGIC_SYSRQ | ||
| 76 | unsigned char ec3104_kbd_sysrq_xlate[128] = | ||
| 77 | "\000\0331234567890-=\177\t" /* 0x00 - 0x0f */ | ||
| 78 | "qwertyuiop[]\r\000as" /* 0x10 - 0x1f */ | ||
| 79 | "dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */ | ||
| 80 | "bnm,./\000*\000 \000\201\202\203\204\205" /* 0x30 - 0x3f */ | ||
| 81 | "\206\207\210\211\212\000\000789-456+1" /* 0x40 - 0x4f */ | ||
| 82 | "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */ | ||
| 83 | "\r\000/"; /* 0x60 - 0x6f */ | ||
| 84 | #endif | ||
| 85 | |||
| 86 | static void kbd_write_command_w(int data); | ||
| 87 | static void kbd_write_output_w(int data); | ||
| 88 | #ifdef CONFIG_PSMOUSE | ||
| 89 | static void aux_write_ack(int val); | ||
| 90 | static void __aux_write_ack(int val); | ||
| 91 | #endif | ||
| 92 | |||
| 93 | static DEFINE_SPINLOCK(kbd_controller_lock); | ||
| 94 | static unsigned char handle_kbd_event(void); | ||
| 95 | |||
| 96 | /* used only by send_data - set by keyboard_interrupt */ | ||
| 97 | static volatile unsigned char reply_expected; | ||
| 98 | static volatile unsigned char acknowledge; | ||
| 99 | static volatile unsigned char resend; | ||
| 100 | |||
| 101 | |||
| 102 | int ec3104_kbd_setkeycode(unsigned int scancode, unsigned int keycode) | ||
| 103 | { | ||
| 104 | return 0; | ||
| 105 | } | ||
| 106 | |||
| 107 | int ec3104_kbd_getkeycode(unsigned int scancode) | ||
| 108 | { | ||
| 109 | return 0; | ||
| 110 | } | ||
| 111 | |||
| 112 | |||
| 113 | /* yes, it probably would be faster to use an array. I don't care. */ | ||
| 114 | |||
| 115 | static inline unsigned char ec3104_scan2key(unsigned char scancode) | ||
| 116 | { | ||
| 117 | switch (scancode) { | ||
| 118 | case 1: /* '`' */ | ||
| 119 | return 41; | ||
| 120 | |||
| 121 | case 2 ... 27: | ||
| 122 | return scancode; | ||
| 123 | |||
| 124 | case 28: /* '\\' */ | ||
| 125 | return 43; | ||
| 126 | |||
| 127 | case 29 ... 39: | ||
| 128 | return scancode + 1; | ||
| 129 | |||
| 130 | case 40: /* '\r' */ | ||
| 131 | return 28; | ||
| 132 | |||
| 133 | case 41 ... 50: | ||
| 134 | return scancode + 3; | ||
| 135 | |||
| 136 | case 51: /* ' ' */ | ||
| 137 | return 57; | ||
| 138 | |||
| 139 | case 52: /* escape */ | ||
| 140 | return 1; | ||
| 141 | |||
| 142 | case 54: /* insert/delete (labelled delete) */ | ||
| 143 | /* this should arguably be 110, but I'd like to have ctrl-alt-del | ||
| 144 | * working with a standard keymap */ | ||
| 145 | return 111; | ||
| 146 | |||
| 147 | case 55: /* left */ | ||
| 148 | return 105; | ||
| 149 | case 56: /* home */ | ||
| 150 | return 102; | ||
| 151 | case 57: /* end */ | ||
| 152 | return 107; | ||
| 153 | case 58: /* up */ | ||
| 154 | return 103; | ||
| 155 | case 59: /* down */ | ||
| 156 | return 108; | ||
| 157 | case 60: /* pgup */ | ||
| 158 | return 104; | ||
| 159 | case 61: /* pgdown */ | ||
| 160 | return 109; | ||
| 161 | case 62: /* right */ | ||
| 162 | return 106; | ||
| 163 | |||
| 164 | case 79 ... 88: /* f1 - f10 */ | ||
| 165 | return scancode - 20; | ||
| 166 | |||
| 167 | case 89 ... 90: /* f11 - f12 */ | ||
| 168 | return scancode - 2; | ||
| 169 | |||
| 170 | case 91: /* left shift */ | ||
| 171 | return 42; | ||
| 172 | |||
| 173 | case 92: /* right shift */ | ||
| 174 | return 54; | ||
| 175 | |||
| 176 | case 93: /* left alt */ | ||
| 177 | return 56; | ||
| 178 | case 94: /* right alt */ | ||
| 179 | return 100; | ||
| 180 | case 95: /* left ctrl */ | ||
| 181 | return 29; | ||
| 182 | case 96: /* right ctrl */ | ||
| 183 | return 97; | ||
| 184 | |||
| 185 | case 97: /* caps lock */ | ||
| 186 | return 58; | ||
| 187 | case 102: /* left windows */ | ||
| 188 | return 125; | ||
| 189 | case 103: /* right windows */ | ||
| 190 | return 126; | ||
| 191 | |||
| 192 | case 106: /* Fn */ | ||
| 193 | /* this is wrong. */ | ||
| 194 | return 84; | ||
| 195 | |||
| 196 | default: | ||
| 197 | return 0; | ||
| 198 | } | ||
| 199 | } | ||
| 200 | |||
| 201 | int ec3104_kbd_translate(unsigned char scancode, unsigned char *keycode, | ||
| 202 | char raw_mode) | ||
| 203 | { | ||
| 204 | scancode &= 0x7f; | ||
| 205 | |||
| 206 | *keycode = ec3104_scan2key(scancode); | ||
| 207 | |||
| 208 | return 1; | ||
| 209 | } | ||
| 210 | |||
| 211 | char ec3104_kbd_unexpected_up(unsigned char keycode) | ||
| 212 | { | ||
| 213 | return 0200; | ||
| 214 | } | ||
| 215 | |||
| 216 | static inline void handle_keyboard_event(unsigned char scancode) | ||
| 217 | { | ||
| 218 | #ifdef CONFIG_VT | ||
| 219 | handle_scancode(scancode, !(scancode & 0x80)); | ||
| 220 | #endif | ||
| 221 | tasklet_schedule(&keyboard_tasklet); | ||
| 222 | } | ||
| 223 | |||
| 224 | void ec3104_kbd_leds(unsigned char leds) | ||
| 225 | { | ||
| 226 | } | ||
| 227 | |||
| 228 | static u8 e5_checksum(u8 *packet, int count) | ||
| 229 | { | ||
| 230 | int i; | ||
| 231 | u8 sum = 0; | ||
| 232 | |||
| 233 | for (i=0; i<count; i++) | ||
| 234 | sum ^= packet[i]; | ||
| 235 | |||
| 236 | if (sum & 0x80) | ||
| 237 | sum ^= 0xc0; | ||
| 238 | |||
| 239 | return sum; | ||
| 240 | } | ||
| 241 | |||
| 242 | static void e5_wait_for_cts(struct e5_struct *k) | ||
| 243 | { | ||
| 244 | u8 msr; | ||
| 245 | |||
| 246 | do { | ||
| 247 | msr = ctrl_inb(EC3104_SER4_MSR); | ||
| 248 | } while (!(msr & MSR_CTS)); | ||
| 249 | } | ||
| 250 | |||
| 251 | |||
| 252 | static void e5_send_byte(u8 byte, struct e5_struct *k) | ||
| 253 | { | ||
| 254 | u8 status; | ||
| 255 | |||
| 256 | do { | ||
| 257 | status = ctrl_inb(EC3104_SER4_LSR); | ||
| 258 | } while ((status & LSR_BOTH_EMPTY) != LSR_BOTH_EMPTY); | ||
| 259 | |||
| 260 | printk("<%02x>", byte); | ||
| 261 | |||
| 262 | ctrl_outb(byte, EC3104_SER4_DATA); | ||
| 263 | |||
| 264 | do { | ||
| 265 | status = ctrl_inb(EC3104_SER4_LSR); | ||
| 266 | } while ((status & LSR_BOTH_EMPTY) != LSR_BOTH_EMPTY); | ||
| 267 | |||
| 268 | } | ||
| 269 | |||
| 270 | static int e5_send_packet(u8 *packet, int count, struct e5_struct *k) | ||
| 271 | { | ||
| 272 | int i; | ||
| 273 | |||
| 274 | disable_irq(EC3104_IRQ_SER4); | ||
| 275 | |||
| 276 | if (k->cached_mcr & MCR_RTS) { | ||
| 277 | printk("e5_send_packet: too slow\n"); | ||
| 278 | enable_irq(EC3104_IRQ_SER4); | ||
| 279 | return -EAGAIN; | ||
| 280 | } | ||
| 281 | |||
| 282 | k->cached_mcr |= MCR_RTS; | ||
| 283 | ctrl_outb(k->cached_mcr, EC3104_SER4_MCR); | ||
| 284 | |||
| 285 | e5_wait_for_cts(k); | ||
| 286 | |||
| 287 | printk("p: "); | ||
| 288 | |||
| 289 | for(i=0; i<count; i++) | ||
| 290 | e5_send_byte(packet[i], k); | ||
| 291 | |||
| 292 | e5_send_byte(e5_checksum(packet, count), k); | ||
| 293 | |||
| 294 | printk("\n"); | ||
| 295 | |||
| 296 | udelay(1500); | ||
| 297 | |||
| 298 | k->cached_mcr &= ~MCR_RTS; | ||
| 299 | ctrl_outb(k->cached_mcr, EC3104_SER4_MCR); | ||
| 300 | |||
| 301 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
| 302 | |||
| 303 | |||
| 304 | |||
| 305 | enable_irq(EC3104_IRQ_SER4); | ||
| 306 | |||
| 307 | |||
| 308 | |||
| 309 | return 0; | ||
| 310 | } | ||
| 311 | |||
| 312 | /* | ||
| 313 | * E5 packets we know about: | ||
| 314 | * E5->host 0x80 0x05 <checksum> - resend packet | ||
| 315 | * host->E5 0x83 0x43 <contrast> - set LCD contrast | ||
| 316 | * host->E5 0x85 0x41 0x02 <brightness> 0x02 - set LCD backlight | ||
| 317 | * E5->host 0x87 <ps2 packet> 0x00 <checksum> - external PS2 | ||
| 318 | * E5->host 0x88 <scancode> <checksum> - key press | ||
| 319 | */ | ||
| 320 | |||
| 321 | static void e5_receive(struct e5_struct *k) | ||
| 322 | { | ||
| 323 | k->packet[k->pos++] = ctrl_inb(EC3104_SER4_DATA); | ||
| 324 | |||
| 325 | if (k->pos == 1) { | ||
| 326 | switch(k->packet[0]) { | ||
| 327 | case 0x80: | ||
| 328 | k->length = 3; | ||
| 329 | break; | ||
| 330 | |||
| 331 | case 0x87: /* PS2 ext */ | ||
| 332 | k->length = 6; | ||
| 333 | break; | ||
| 334 | |||
| 335 | case 0x88: /* keyboard */ | ||
| 336 | k->length = 3; | ||
| 337 | break; | ||
| 338 | |||
| 339 | default: | ||
| 340 | k->length = 1; | ||
| 341 | printk(KERN_WARNING "unknown E5 packet %02x\n", | ||
| 342 | k->packet[0]); | ||
| 343 | } | ||
| 344 | } | ||
| 345 | |||
| 346 | if (k->pos == k->length) { | ||
| 347 | int i; | ||
| 348 | |||
| 349 | if (e5_checksum(k->packet, k->length) != 0) | ||
| 350 | printk(KERN_WARNING "E5: wrong checksum\n"); | ||
| 351 | |||
| 352 | #if 0 | ||
| 353 | printk("E5 packet ["); | ||
| 354 | for(i=0; i<k->length; i++) { | ||
| 355 | printk("%02x ", k->packet[i]); | ||
| 356 | } | ||
| 357 | |||
| 358 | printk("(%02x)]\n", e5_checksum(k->packet, k->length-1)); | ||
| 359 | #endif | ||
| 360 | |||
| 361 | switch(k->packet[0]) { | ||
| 362 | case 0x80: | ||
| 363 | case 0x88: | ||
| 364 | handle_keyboard_event(k->packet[1]); | ||
| 365 | break; | ||
| 366 | } | ||
| 367 | |||
| 368 | k->pos = k->length = 0; | ||
| 369 | } | ||
| 370 | } | ||
| 371 | |||
| 372 | static void ec3104_keyb_interrupt(int irq, void *data) | ||
| 373 | { | ||
| 374 | struct e5_struct *k = &ec3104_keyb; | ||
| 375 | u8 msr, lsr; | ||
| 376 | |||
| 377 | msr = ctrl_inb(EC3104_SER4_MSR); | ||
| 378 | |||
| 379 | if ((msr & MSR_CTS) && !(k->last_msr & MSR_CTS)) { | ||
| 380 | if (k->cached_mcr & MCR_RTS) | ||
| 381 | printk("confused: RTS already high\n"); | ||
| 382 | /* CTS went high. Send RTS. */ | ||
| 383 | k->cached_mcr |= MCR_RTS; | ||
| 384 | |||
| 385 | ctrl_outb(k->cached_mcr, EC3104_SER4_MCR); | ||
| 386 | } else if ((!(msr & MSR_CTS)) && (k->last_msr & MSR_CTS)) { | ||
| 387 | /* CTS went low. */ | ||
| 388 | if (!(k->cached_mcr & MCR_RTS)) | ||
| 389 | printk("confused: RTS already low\n"); | ||
| 390 | |||
| 391 | k->cached_mcr &= ~MCR_RTS; | ||
| 392 | |||
| 393 | ctrl_outb(k->cached_mcr, EC3104_SER4_MCR); | ||
| 394 | } | ||
| 395 | |||
| 396 | k->last_msr = msr; | ||
| 397 | |||
| 398 | lsr = ctrl_inb(EC3104_SER4_LSR); | ||
| 399 | |||
| 400 | if (lsr & LSR_DR) | ||
| 401 | e5_receive(k); | ||
| 402 | } | ||
| 403 | |||
| 404 | static void ec3104_keyb_clear_state(void) | ||
| 405 | { | ||
| 406 | struct e5_struct *k = &ec3104_keyb; | ||
| 407 | u8 msr, lsr; | ||
| 408 | |||
| 409 | /* we want CTS to be low */ | ||
| 410 | k->last_msr = 0; | ||
| 411 | |||
| 412 | for (;;) { | ||
| 413 | msleep(100); | ||
| 414 | |||
| 415 | msr = ctrl_inb(EC3104_SER4_MSR); | ||
| 416 | |||
| 417 | lsr = ctrl_inb(EC3104_SER4_LSR); | ||
| 418 | |||
| 419 | if (lsr & LSR_DR) { | ||
| 420 | e5_receive(k); | ||
| 421 | continue; | ||
| 422 | } | ||
| 423 | |||
| 424 | if ((msr & MSR_CTS) && !(k->last_msr & MSR_CTS)) { | ||
| 425 | if (k->cached_mcr & MCR_RTS) | ||
| 426 | printk("confused: RTS already high\n"); | ||
| 427 | /* CTS went high. Send RTS. */ | ||
| 428 | k->cached_mcr |= MCR_RTS; | ||
| 429 | |||
| 430 | ctrl_outb(k->cached_mcr, EC3104_SER4_MCR); | ||
| 431 | } else if ((!(msr & MSR_CTS)) && (k->last_msr & MSR_CTS)) { | ||
| 432 | /* CTS went low. */ | ||
| 433 | if (!(k->cached_mcr & MCR_RTS)) | ||
| 434 | printk("confused: RTS already low\n"); | ||
| 435 | |||
| 436 | k->cached_mcr &= ~MCR_RTS; | ||
| 437 | |||
| 438 | ctrl_outb(k->cached_mcr, EC3104_SER4_MCR); | ||
| 439 | } else | ||
| 440 | break; | ||
| 441 | |||
| 442 | k->last_msr = msr; | ||
| 443 | |||
| 444 | continue; | ||
| 445 | } | ||
| 446 | } | ||
| 447 | |||
| 448 | void __init ec3104_kbd_init_hw(void) | ||
| 449 | { | ||
| 450 | ec3104_keyb.last_msr = ctrl_inb(EC3104_SER4_MSR); | ||
| 451 | ec3104_keyb.cached_mcr = ctrl_inb(EC3104_SER4_MCR); | ||
| 452 | |||
| 453 | ec3104_keyb_clear_state(); | ||
| 454 | |||
| 455 | /* Ok, finally allocate the IRQ, and off we go.. */ | ||
| 456 | request_irq(EC3104_IRQ_SER4, ec3104_keyb_interrupt, 0, "keyboard", NULL); | ||
| 457 | } | ||
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index e47f88170806..700a1657554f 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig | |||
| @@ -158,6 +158,7 @@ config SENSORS_K8TEMP | |||
| 158 | config SENSORS_AMS | 158 | config SENSORS_AMS |
| 159 | tristate "Apple Motion Sensor driver" | 159 | tristate "Apple Motion Sensor driver" |
| 160 | depends on PPC_PMAC && !PPC64 && INPUT && ((ADB_PMU && I2C = y) || (ADB_PMU && !I2C) || I2C) && EXPERIMENTAL | 160 | depends on PPC_PMAC && !PPC64 && INPUT && ((ADB_PMU && I2C = y) || (ADB_PMU && !I2C) || I2C) && EXPERIMENTAL |
| 161 | select INPUT_POLLDEV | ||
| 161 | help | 162 | help |
| 162 | Support for the motion sensor included in PowerBooks. Includes | 163 | Support for the motion sensor included in PowerBooks. Includes |
| 163 | implementations for PMU and I2C. | 164 | implementations for PMU and I2C. |
| @@ -701,6 +702,7 @@ config SENSORS_W83627EHF | |||
| 701 | config SENSORS_HDAPS | 702 | config SENSORS_HDAPS |
| 702 | tristate "IBM Hard Drive Active Protection System (hdaps)" | 703 | tristate "IBM Hard Drive Active Protection System (hdaps)" |
| 703 | depends on INPUT && X86 | 704 | depends on INPUT && X86 |
| 705 | select INPUT_POLLDEV | ||
| 704 | default n | 706 | default n |
| 705 | help | 707 | help |
| 706 | This driver provides support for the IBM Hard Drive Active Protection | 708 | This driver provides support for the IBM Hard Drive Active Protection |
| @@ -722,6 +724,7 @@ config SENSORS_APPLESMC | |||
| 722 | depends on INPUT && X86 | 724 | depends on INPUT && X86 |
| 723 | select NEW_LEDS | 725 | select NEW_LEDS |
| 724 | select LEDS_CLASS | 726 | select LEDS_CLASS |
| 727 | select INPUT_POLLDEV | ||
| 725 | default n | 728 | default n |
| 726 | help | 729 | help |
| 727 | This driver provides support for the Apple System Management | 730 | This driver provides support for the Apple System Management |
diff --git a/drivers/hwmon/ams/ams-input.c b/drivers/hwmon/ams/ams-input.c index ca7095d96ad0..7b81e0c2c2d9 100644 --- a/drivers/hwmon/ams/ams-input.c +++ b/drivers/hwmon/ams/ams-input.c | |||
| @@ -27,47 +27,32 @@ static unsigned int invert; | |||
| 27 | module_param(invert, bool, 0644); | 27 | module_param(invert, bool, 0644); |
| 28 | MODULE_PARM_DESC(invert, "Invert input data on X and Y axis"); | 28 | MODULE_PARM_DESC(invert, "Invert input data on X and Y axis"); |
| 29 | 29 | ||
| 30 | static int ams_input_kthread(void *data) | 30 | static void ams_idev_poll(struct input_polled_dev *dev) |
| 31 | { | 31 | { |
| 32 | struct input_dev *idev = dev->input; | ||
| 32 | s8 x, y, z; | 33 | s8 x, y, z; |
| 33 | 34 | ||
| 34 | while (!kthread_should_stop()) { | 35 | mutex_lock(&ams_info.lock); |
| 35 | mutex_lock(&ams_info.lock); | ||
| 36 | |||
| 37 | ams_sensors(&x, &y, &z); | ||
| 38 | |||
| 39 | x -= ams_info.xcalib; | ||
| 40 | y -= ams_info.ycalib; | ||
| 41 | z -= ams_info.zcalib; | ||
| 42 | |||
| 43 | input_report_abs(ams_info.idev, ABS_X, invert ? -x : x); | ||
| 44 | input_report_abs(ams_info.idev, ABS_Y, invert ? -y : y); | ||
| 45 | input_report_abs(ams_info.idev, ABS_Z, z); | ||
| 46 | 36 | ||
| 47 | input_sync(ams_info.idev); | 37 | ams_sensors(&x, &y, &z); |
| 48 | 38 | ||
| 49 | mutex_unlock(&ams_info.lock); | 39 | x -= ams_info.xcalib; |
| 40 | y -= ams_info.ycalib; | ||
| 41 | z -= ams_info.zcalib; | ||
| 50 | 42 | ||
| 51 | msleep(25); | 43 | input_report_abs(idev, ABS_X, invert ? -x : x); |
| 52 | } | 44 | input_report_abs(idev, ABS_Y, invert ? -y : y); |
| 45 | input_report_abs(idev, ABS_Z, z); | ||
| 53 | 46 | ||
| 54 | return 0; | 47 | input_sync(idev); |
| 55 | } | ||
| 56 | 48 | ||
| 57 | static int ams_input_open(struct input_dev *dev) | 49 | mutex_unlock(&ams_info.lock); |
| 58 | { | ||
| 59 | ams_info.kthread = kthread_run(ams_input_kthread, NULL, "kams"); | ||
| 60 | return IS_ERR(ams_info.kthread) ? PTR_ERR(ams_info.kthread) : 0; | ||
| 61 | } | ||
| 62 | |||
| 63 | static void ams_input_close(struct input_dev *dev) | ||
| 64 | { | ||
| 65 | kthread_stop(ams_info.kthread); | ||
| 66 | } | 50 | } |
| 67 | 51 | ||
| 68 | /* Call with ams_info.lock held! */ | 52 | /* Call with ams_info.lock held! */ |
| 69 | static void ams_input_enable(void) | 53 | static void ams_input_enable(void) |
| 70 | { | 54 | { |
| 55 | struct input_dev *input; | ||
| 71 | s8 x, y, z; | 56 | s8 x, y, z; |
| 72 | 57 | ||
| 73 | if (ams_info.idev) | 58 | if (ams_info.idev) |
| @@ -78,27 +63,29 @@ static void ams_input_enable(void) | |||
| 78 | ams_info.ycalib = y; | 63 | ams_info.ycalib = y; |
| 79 | ams_info.zcalib = z; | 64 | ams_info.zcalib = z; |
| 80 | 65 | ||
| 81 | ams_info.idev = input_allocate_device(); | 66 | ams_info.idev = input_allocate_polled_device(); |
| 82 | if (!ams_info.idev) | 67 | if (!ams_info.idev) |
| 83 | return; | 68 | return; |
| 84 | 69 | ||
| 85 | ams_info.idev->name = "Apple Motion Sensor"; | 70 | ams_info.idev->poll = ams_idev_poll; |
| 86 | ams_info.idev->id.bustype = ams_info.bustype; | 71 | ams_info.idev->poll_interval = 25; |
| 87 | ams_info.idev->id.vendor = 0; | 72 | |
| 88 | ams_info.idev->open = ams_input_open; | 73 | input = ams_info.idev->input; |
| 89 | ams_info.idev->close = ams_input_close; | 74 | input->name = "Apple Motion Sensor"; |
| 90 | ams_info.idev->dev.parent = &ams_info.of_dev->dev; | 75 | input->id.bustype = ams_info.bustype; |
| 76 | input->id.vendor = 0; | ||
| 77 | input->dev.parent = &ams_info.of_dev->dev; | ||
| 91 | 78 | ||
| 92 | input_set_abs_params(ams_info.idev, ABS_X, -50, 50, 3, 0); | 79 | input_set_abs_params(input, ABS_X, -50, 50, 3, 0); |
| 93 | input_set_abs_params(ams_info.idev, ABS_Y, -50, 50, 3, 0); | 80 | input_set_abs_params(input, ABS_Y, -50, 50, 3, 0); |
| 94 | input_set_abs_params(ams_info.idev, ABS_Z, -50, 50, 3, 0); | 81 | input_set_abs_params(input, ABS_Z, -50, 50, 3, 0); |
| 95 | 82 | ||
| 96 | set_bit(EV_ABS, ams_info.idev->evbit); | 83 | set_bit(EV_ABS, input->evbit); |
| 97 | set_bit(EV_KEY, ams_info.idev->evbit); | 84 | set_bit(EV_KEY, input->evbit); |
| 98 | set_bit(BTN_TOUCH, ams_info.idev->keybit); | 85 | set_bit(BTN_TOUCH, input->keybit); |
| 99 | 86 | ||
| 100 | if (input_register_device(ams_info.idev)) { | 87 | if (input_register_polled_device(ams_info.idev)) { |
| 101 | input_free_device(ams_info.idev); | 88 | input_free_polled_device(ams_info.idev); |
| 102 | ams_info.idev = NULL; | 89 | ams_info.idev = NULL; |
| 103 | return; | 90 | return; |
| 104 | } | 91 | } |
| @@ -108,7 +95,8 @@ static void ams_input_enable(void) | |||
| 108 | static void ams_input_disable(void) | 95 | static void ams_input_disable(void) |
| 109 | { | 96 | { |
| 110 | if (ams_info.idev) { | 97 | if (ams_info.idev) { |
| 111 | input_unregister_device(ams_info.idev); | 98 | input_unregister_polled_device(ams_info.idev); |
| 99 | input_free_polled_device(ams_info.idev); | ||
| 112 | ams_info.idev = NULL; | 100 | ams_info.idev = NULL; |
| 113 | } | 101 | } |
| 114 | } | 102 | } |
diff --git a/drivers/hwmon/ams/ams.h b/drivers/hwmon/ams/ams.h index 240730e6bcde..a6221e5dd984 100644 --- a/drivers/hwmon/ams/ams.h +++ b/drivers/hwmon/ams/ams.h | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | #include <linux/i2c.h> | 1 | #include <linux/i2c.h> |
| 2 | #include <linux/input.h> | 2 | #include <linux/input-polldev.h> |
| 3 | #include <linux/kthread.h> | 3 | #include <linux/kthread.h> |
| 4 | #include <linux/mutex.h> | 4 | #include <linux/mutex.h> |
| 5 | #include <linux/spinlock.h> | 5 | #include <linux/spinlock.h> |
| @@ -52,8 +52,7 @@ struct ams { | |||
| 52 | #endif | 52 | #endif |
| 53 | 53 | ||
| 54 | /* Joystick emulation */ | 54 | /* Joystick emulation */ |
| 55 | struct task_struct *kthread; | 55 | struct input_polled_dev *idev; |
| 56 | struct input_dev *idev; | ||
| 57 | __u16 bustype; | 56 | __u16 bustype; |
| 58 | 57 | ||
| 59 | /* calibrated null values */ | 58 | /* calibrated null values */ |
diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c index f37fd7ebf65a..4879125b4cdc 100644 --- a/drivers/hwmon/applesmc.c +++ b/drivers/hwmon/applesmc.c | |||
| @@ -28,7 +28,7 @@ | |||
| 28 | 28 | ||
| 29 | #include <linux/delay.h> | 29 | #include <linux/delay.h> |
| 30 | #include <linux/platform_device.h> | 30 | #include <linux/platform_device.h> |
| 31 | #include <linux/input.h> | 31 | #include <linux/input-polldev.h> |
| 32 | #include <linux/kernel.h> | 32 | #include <linux/kernel.h> |
| 33 | #include <linux/module.h> | 33 | #include <linux/module.h> |
| 34 | #include <linux/timer.h> | 34 | #include <linux/timer.h> |
| @@ -59,9 +59,9 @@ | |||
| 59 | 59 | ||
| 60 | #define LIGHT_SENSOR_LEFT_KEY "ALV0" /* r-o {alv (6 bytes) */ | 60 | #define LIGHT_SENSOR_LEFT_KEY "ALV0" /* r-o {alv (6 bytes) */ |
| 61 | #define LIGHT_SENSOR_RIGHT_KEY "ALV1" /* r-o {alv (6 bytes) */ | 61 | #define LIGHT_SENSOR_RIGHT_KEY "ALV1" /* r-o {alv (6 bytes) */ |
| 62 | #define BACKLIGHT_KEY "LKSB" /* w-o {lkb (2 bytes) */ | 62 | #define BACKLIGHT_KEY "LKSB" /* w-o {lkb (2 bytes) */ |
| 63 | 63 | ||
| 64 | #define CLAMSHELL_KEY "MSLD" /* r-o ui8 (unused) */ | 64 | #define CLAMSHELL_KEY "MSLD" /* r-o ui8 (unused) */ |
| 65 | 65 | ||
| 66 | #define MOTION_SENSOR_X_KEY "MO_X" /* r-o sp78 (2 bytes) */ | 66 | #define MOTION_SENSOR_X_KEY "MO_X" /* r-o sp78 (2 bytes) */ |
| 67 | #define MOTION_SENSOR_Y_KEY "MO_Y" /* r-o sp78 (2 bytes) */ | 67 | #define MOTION_SENSOR_Y_KEY "MO_Y" /* r-o sp78 (2 bytes) */ |
| @@ -103,7 +103,7 @@ static const char* fan_speed_keys[] = { | |||
| 103 | #define INIT_TIMEOUT_MSECS 5000 /* wait up to 5s for device init ... */ | 103 | #define INIT_TIMEOUT_MSECS 5000 /* wait up to 5s for device init ... */ |
| 104 | #define INIT_WAIT_MSECS 50 /* ... in 50ms increments */ | 104 | #define INIT_WAIT_MSECS 50 /* ... in 50ms increments */ |
| 105 | 105 | ||
| 106 | #define APPLESMC_POLL_PERIOD (HZ/20) /* poll for input every 1/20s */ | 106 | #define APPLESMC_POLL_INTERVAL 50 /* msecs */ |
| 107 | #define APPLESMC_INPUT_FUZZ 4 /* input event threshold */ | 107 | #define APPLESMC_INPUT_FUZZ 4 /* input event threshold */ |
| 108 | #define APPLESMC_INPUT_FLAT 4 | 108 | #define APPLESMC_INPUT_FLAT 4 |
| 109 | 109 | ||
| @@ -125,9 +125,8 @@ static const int debug; | |||
| 125 | static struct platform_device *pdev; | 125 | static struct platform_device *pdev; |
| 126 | static s16 rest_x; | 126 | static s16 rest_x; |
| 127 | static s16 rest_y; | 127 | static s16 rest_y; |
| 128 | static struct timer_list applesmc_timer; | ||
| 129 | static struct input_dev *applesmc_idev; | ||
| 130 | static struct device *hwmon_dev; | 128 | static struct device *hwmon_dev; |
| 129 | static struct input_polled_dev *applesmc_idev; | ||
| 131 | 130 | ||
| 132 | /* Indicates whether this computer has an accelerometer. */ | 131 | /* Indicates whether this computer has an accelerometer. */ |
| 133 | static unsigned int applesmc_accelerometer; | 132 | static unsigned int applesmc_accelerometer; |
| @@ -138,7 +137,7 @@ static unsigned int applesmc_light; | |||
| 138 | /* Indicates which temperature sensors set to use. */ | 137 | /* Indicates which temperature sensors set to use. */ |
| 139 | static unsigned int applesmc_temperature_set; | 138 | static unsigned int applesmc_temperature_set; |
| 140 | 139 | ||
| 141 | static struct mutex applesmc_lock; | 140 | static DEFINE_MUTEX(applesmc_lock); |
| 142 | 141 | ||
| 143 | /* | 142 | /* |
| 144 | * Last index written to key_at_index sysfs file, and value to use for all other | 143 | * Last index written to key_at_index sysfs file, and value to use for all other |
| @@ -455,27 +454,12 @@ static void applesmc_calibrate(void) | |||
| 455 | rest_x = -rest_x; | 454 | rest_x = -rest_x; |
| 456 | } | 455 | } |
| 457 | 456 | ||
| 458 | static int applesmc_idev_open(struct input_dev *dev) | 457 | static void applesmc_idev_poll(struct input_polled_dev *dev) |
| 459 | { | ||
| 460 | add_timer(&applesmc_timer); | ||
| 461 | |||
| 462 | return 0; | ||
| 463 | } | ||
| 464 | |||
| 465 | static void applesmc_idev_close(struct input_dev *dev) | ||
| 466 | { | ||
| 467 | del_timer_sync(&applesmc_timer); | ||
| 468 | } | ||
| 469 | |||
| 470 | static void applesmc_idev_poll(unsigned long unused) | ||
| 471 | { | 458 | { |
| 459 | struct input_dev *idev = dev->input; | ||
| 472 | s16 x, y; | 460 | s16 x, y; |
| 473 | 461 | ||
| 474 | /* Cannot sleep. Try nonblockingly. If we fail, try again later. */ | 462 | mutex_lock(&applesmc_lock); |
| 475 | if (!mutex_trylock(&applesmc_lock)) { | ||
| 476 | mod_timer(&applesmc_timer, jiffies + APPLESMC_POLL_PERIOD); | ||
| 477 | return; | ||
| 478 | } | ||
| 479 | 463 | ||
| 480 | if (applesmc_read_motion_sensor(SENSOR_X, &x)) | 464 | if (applesmc_read_motion_sensor(SENSOR_X, &x)) |
| 481 | goto out; | 465 | goto out; |
| @@ -483,13 +467,11 @@ static void applesmc_idev_poll(unsigned long unused) | |||
| 483 | goto out; | 467 | goto out; |
| 484 | 468 | ||
| 485 | x = -x; | 469 | x = -x; |
| 486 | input_report_abs(applesmc_idev, ABS_X, x - rest_x); | 470 | input_report_abs(idev, ABS_X, x - rest_x); |
| 487 | input_report_abs(applesmc_idev, ABS_Y, y - rest_y); | 471 | input_report_abs(idev, ABS_Y, y - rest_y); |
| 488 | input_sync(applesmc_idev); | 472 | input_sync(idev); |
| 489 | 473 | ||
| 490 | out: | 474 | out: |
| 491 | mod_timer(&applesmc_timer, jiffies + APPLESMC_POLL_PERIOD); | ||
| 492 | |||
| 493 | mutex_unlock(&applesmc_lock); | 475 | mutex_unlock(&applesmc_lock); |
| 494 | } | 476 | } |
| 495 | 477 | ||
| @@ -821,8 +803,7 @@ static ssize_t applesmc_key_at_index_read_show(struct device *dev, | |||
| 821 | 803 | ||
| 822 | if (!ret) { | 804 | if (!ret) { |
| 823 | return info[0]; | 805 | return info[0]; |
| 824 | } | 806 | } else { |
| 825 | else { | ||
| 826 | return ret; | 807 | return ret; |
| 827 | } | 808 | } |
| 828 | } | 809 | } |
| @@ -1093,6 +1074,7 @@ static int applesmc_dmi_match(const struct dmi_system_id *id) | |||
| 1093 | /* Create accelerometer ressources */ | 1074 | /* Create accelerometer ressources */ |
| 1094 | static int applesmc_create_accelerometer(void) | 1075 | static int applesmc_create_accelerometer(void) |
| 1095 | { | 1076 | { |
| 1077 | struct input_dev *idev; | ||
| 1096 | int ret; | 1078 | int ret; |
| 1097 | 1079 | ||
| 1098 | ret = sysfs_create_group(&pdev->dev.kobj, | 1080 | ret = sysfs_create_group(&pdev->dev.kobj, |
| @@ -1100,40 +1082,37 @@ static int applesmc_create_accelerometer(void) | |||
| 1100 | if (ret) | 1082 | if (ret) |
| 1101 | goto out; | 1083 | goto out; |
| 1102 | 1084 | ||
| 1103 | applesmc_idev = input_allocate_device(); | 1085 | applesmc_idev = input_allocate_polled_device(); |
| 1104 | if (!applesmc_idev) { | 1086 | if (!applesmc_idev) { |
| 1105 | ret = -ENOMEM; | 1087 | ret = -ENOMEM; |
| 1106 | goto out_sysfs; | 1088 | goto out_sysfs; |
| 1107 | } | 1089 | } |
| 1108 | 1090 | ||
| 1091 | applesmc_idev->poll = applesmc_idev_poll; | ||
| 1092 | applesmc_idev->poll_interval = APPLESMC_POLL_INTERVAL; | ||
| 1093 | |||
| 1109 | /* initial calibrate for the input device */ | 1094 | /* initial calibrate for the input device */ |
| 1110 | applesmc_calibrate(); | 1095 | applesmc_calibrate(); |
| 1111 | 1096 | ||
| 1112 | /* initialize the input class */ | 1097 | /* initialize the input device */ |
| 1113 | applesmc_idev->name = "applesmc"; | 1098 | idev = applesmc_idev->input; |
| 1114 | applesmc_idev->id.bustype = BUS_HOST; | 1099 | idev->name = "applesmc"; |
| 1115 | applesmc_idev->dev.parent = &pdev->dev; | 1100 | idev->id.bustype = BUS_HOST; |
| 1116 | applesmc_idev->evbit[0] = BIT(EV_ABS); | 1101 | idev->dev.parent = &pdev->dev; |
| 1117 | applesmc_idev->open = applesmc_idev_open; | 1102 | idev->evbit[0] = BIT(EV_ABS); |
| 1118 | applesmc_idev->close = applesmc_idev_close; | 1103 | input_set_abs_params(idev, ABS_X, |
| 1119 | input_set_abs_params(applesmc_idev, ABS_X, | ||
| 1120 | -256, 256, APPLESMC_INPUT_FUZZ, APPLESMC_INPUT_FLAT); | 1104 | -256, 256, APPLESMC_INPUT_FUZZ, APPLESMC_INPUT_FLAT); |
| 1121 | input_set_abs_params(applesmc_idev, ABS_Y, | 1105 | input_set_abs_params(idev, ABS_Y, |
| 1122 | -256, 256, APPLESMC_INPUT_FUZZ, APPLESMC_INPUT_FLAT); | 1106 | -256, 256, APPLESMC_INPUT_FUZZ, APPLESMC_INPUT_FLAT); |
| 1123 | 1107 | ||
| 1124 | ret = input_register_device(applesmc_idev); | 1108 | ret = input_register_polled_device(applesmc_idev); |
| 1125 | if (ret) | 1109 | if (ret) |
| 1126 | goto out_idev; | 1110 | goto out_idev; |
| 1127 | 1111 | ||
| 1128 | /* start up our timer for the input device */ | ||
| 1129 | init_timer(&applesmc_timer); | ||
| 1130 | applesmc_timer.function = applesmc_idev_poll; | ||
| 1131 | applesmc_timer.expires = jiffies + APPLESMC_POLL_PERIOD; | ||
| 1132 | |||
| 1133 | return 0; | 1112 | return 0; |
| 1134 | 1113 | ||
| 1135 | out_idev: | 1114 | out_idev: |
| 1136 | input_free_device(applesmc_idev); | 1115 | input_free_polled_device(applesmc_idev); |
| 1137 | 1116 | ||
| 1138 | out_sysfs: | 1117 | out_sysfs: |
| 1139 | sysfs_remove_group(&pdev->dev.kobj, &accelerometer_attributes_group); | 1118 | sysfs_remove_group(&pdev->dev.kobj, &accelerometer_attributes_group); |
| @@ -1146,8 +1125,8 @@ out: | |||
| 1146 | /* Release all ressources used by the accelerometer */ | 1125 | /* Release all ressources used by the accelerometer */ |
| 1147 | static void applesmc_release_accelerometer(void) | 1126 | static void applesmc_release_accelerometer(void) |
| 1148 | { | 1127 | { |
| 1149 | del_timer_sync(&applesmc_timer); | 1128 | input_unregister_polled_device(applesmc_idev); |
| 1150 | input_unregister_device(applesmc_idev); | 1129 | input_free_polled_device(applesmc_idev); |
| 1151 | sysfs_remove_group(&pdev->dev.kobj, &accelerometer_attributes_group); | 1130 | sysfs_remove_group(&pdev->dev.kobj, &accelerometer_attributes_group); |
| 1152 | } | 1131 | } |
| 1153 | 1132 | ||
| @@ -1184,8 +1163,6 @@ static int __init applesmc_init(void) | |||
| 1184 | int count; | 1163 | int count; |
| 1185 | int i; | 1164 | int i; |
| 1186 | 1165 | ||
| 1187 | mutex_init(&applesmc_lock); | ||
| 1188 | |||
| 1189 | if (!dmi_check_system(applesmc_whitelist)) { | 1166 | if (!dmi_check_system(applesmc_whitelist)) { |
| 1190 | printk(KERN_WARNING "applesmc: supported laptop not found!\n"); | 1167 | printk(KERN_WARNING "applesmc: supported laptop not found!\n"); |
| 1191 | ret = -ENODEV; | 1168 | ret = -ENODEV; |
diff --git a/drivers/hwmon/hdaps.c b/drivers/hwmon/hdaps.c index a7c6d407572b..8a7ae03aeee4 100644 --- a/drivers/hwmon/hdaps.c +++ b/drivers/hwmon/hdaps.c | |||
| @@ -28,7 +28,7 @@ | |||
| 28 | 28 | ||
| 29 | #include <linux/delay.h> | 29 | #include <linux/delay.h> |
| 30 | #include <linux/platform_device.h> | 30 | #include <linux/platform_device.h> |
| 31 | #include <linux/input.h> | 31 | #include <linux/input-polldev.h> |
| 32 | #include <linux/kernel.h> | 32 | #include <linux/kernel.h> |
| 33 | #include <linux/mutex.h> | 33 | #include <linux/mutex.h> |
| 34 | #include <linux/module.h> | 34 | #include <linux/module.h> |
| @@ -61,13 +61,12 @@ | |||
| 61 | #define INIT_TIMEOUT_MSECS 4000 /* wait up to 4s for device init ... */ | 61 | #define INIT_TIMEOUT_MSECS 4000 /* wait up to 4s for device init ... */ |
| 62 | #define INIT_WAIT_MSECS 200 /* ... in 200ms increments */ | 62 | #define INIT_WAIT_MSECS 200 /* ... in 200ms increments */ |
| 63 | 63 | ||
| 64 | #define HDAPS_POLL_PERIOD (HZ/20) /* poll for input every 1/20s */ | 64 | #define HDAPS_POLL_INTERVAL 50 /* poll for input every 1/20s (50 ms)*/ |
| 65 | #define HDAPS_INPUT_FUZZ 4 /* input event threshold */ | 65 | #define HDAPS_INPUT_FUZZ 4 /* input event threshold */ |
| 66 | #define HDAPS_INPUT_FLAT 4 | 66 | #define HDAPS_INPUT_FLAT 4 |
| 67 | 67 | ||
| 68 | static struct timer_list hdaps_timer; | ||
| 69 | static struct platform_device *pdev; | 68 | static struct platform_device *pdev; |
| 70 | static struct input_dev *hdaps_idev; | 69 | static struct input_polled_dev *hdaps_idev; |
| 71 | static unsigned int hdaps_invert; | 70 | static unsigned int hdaps_invert; |
| 72 | static u8 km_activity; | 71 | static u8 km_activity; |
| 73 | static int rest_x; | 72 | static int rest_x; |
| @@ -323,24 +322,19 @@ static void hdaps_calibrate(void) | |||
| 323 | __hdaps_read_pair(HDAPS_PORT_XPOS, HDAPS_PORT_YPOS, &rest_x, &rest_y); | 322 | __hdaps_read_pair(HDAPS_PORT_XPOS, HDAPS_PORT_YPOS, &rest_x, &rest_y); |
| 324 | } | 323 | } |
| 325 | 324 | ||
| 326 | static void hdaps_mousedev_poll(unsigned long unused) | 325 | static void hdaps_mousedev_poll(struct input_polled_dev *dev) |
| 327 | { | 326 | { |
| 327 | struct input_dev *input_dev = dev->input; | ||
| 328 | int x, y; | 328 | int x, y; |
| 329 | 329 | ||
| 330 | /* Cannot sleep. Try nonblockingly. If we fail, try again later. */ | 330 | mutex_lock(&hdaps_mtx); |
| 331 | if (mutex_trylock(&hdaps_mtx)) { | ||
| 332 | mod_timer(&hdaps_timer,jiffies + HDAPS_POLL_PERIOD); | ||
| 333 | return; | ||
| 334 | } | ||
| 335 | 331 | ||
| 336 | if (__hdaps_read_pair(HDAPS_PORT_XPOS, HDAPS_PORT_YPOS, &x, &y)) | 332 | if (__hdaps_read_pair(HDAPS_PORT_XPOS, HDAPS_PORT_YPOS, &x, &y)) |
| 337 | goto out; | 333 | goto out; |
| 338 | 334 | ||
| 339 | input_report_abs(hdaps_idev, ABS_X, x - rest_x); | 335 | input_report_abs(input_dev, ABS_X, x - rest_x); |
| 340 | input_report_abs(hdaps_idev, ABS_Y, y - rest_y); | 336 | input_report_abs(input_dev, ABS_Y, y - rest_y); |
| 341 | input_sync(hdaps_idev); | 337 | input_sync(input_dev); |
| 342 | |||
| 343 | mod_timer(&hdaps_timer, jiffies + HDAPS_POLL_PERIOD); | ||
| 344 | 338 | ||
| 345 | out: | 339 | out: |
| 346 | mutex_unlock(&hdaps_mtx); | 340 | mutex_unlock(&hdaps_mtx); |
| @@ -536,6 +530,7 @@ static struct dmi_system_id __initdata hdaps_whitelist[] = { | |||
| 536 | 530 | ||
| 537 | static int __init hdaps_init(void) | 531 | static int __init hdaps_init(void) |
| 538 | { | 532 | { |
| 533 | struct input_dev *idev; | ||
| 539 | int ret; | 534 | int ret; |
| 540 | 535 | ||
| 541 | if (!dmi_check_system(hdaps_whitelist)) { | 536 | if (!dmi_check_system(hdaps_whitelist)) { |
| @@ -563,39 +558,37 @@ static int __init hdaps_init(void) | |||
| 563 | if (ret) | 558 | if (ret) |
| 564 | goto out_device; | 559 | goto out_device; |
| 565 | 560 | ||
| 566 | hdaps_idev = input_allocate_device(); | 561 | hdaps_idev = input_allocate_polled_device(); |
| 567 | if (!hdaps_idev) { | 562 | if (!hdaps_idev) { |
| 568 | ret = -ENOMEM; | 563 | ret = -ENOMEM; |
| 569 | goto out_group; | 564 | goto out_group; |
| 570 | } | 565 | } |
| 571 | 566 | ||
| 567 | hdaps_idev->poll = hdaps_mousedev_poll; | ||
| 568 | hdaps_idev->poll_interval = HDAPS_POLL_INTERVAL; | ||
| 569 | |||
| 572 | /* initial calibrate for the input device */ | 570 | /* initial calibrate for the input device */ |
| 573 | hdaps_calibrate(); | 571 | hdaps_calibrate(); |
| 574 | 572 | ||
| 575 | /* initialize the input class */ | 573 | /* initialize the input class */ |
| 576 | hdaps_idev->name = "hdaps"; | 574 | idev = hdaps_idev->input; |
| 577 | hdaps_idev->dev.parent = &pdev->dev; | 575 | idev->name = "hdaps"; |
| 578 | hdaps_idev->evbit[0] = BIT(EV_ABS); | 576 | idev->dev.parent = &pdev->dev; |
| 579 | input_set_abs_params(hdaps_idev, ABS_X, | 577 | idev->evbit[0] = BIT(EV_ABS); |
| 578 | input_set_abs_params(idev, ABS_X, | ||
| 580 | -256, 256, HDAPS_INPUT_FUZZ, HDAPS_INPUT_FLAT); | 579 | -256, 256, HDAPS_INPUT_FUZZ, HDAPS_INPUT_FLAT); |
| 581 | input_set_abs_params(hdaps_idev, ABS_Y, | 580 | input_set_abs_params(idev, ABS_Y, |
| 582 | -256, 256, HDAPS_INPUT_FUZZ, HDAPS_INPUT_FLAT); | 581 | -256, 256, HDAPS_INPUT_FUZZ, HDAPS_INPUT_FLAT); |
| 583 | 582 | ||
| 584 | ret = input_register_device(hdaps_idev); | 583 | ret = input_register_polled_device(hdaps_idev); |
| 585 | if (ret) | 584 | if (ret) |
| 586 | goto out_idev; | 585 | goto out_idev; |
| 587 | 586 | ||
| 588 | /* start up our timer for the input device */ | ||
| 589 | init_timer(&hdaps_timer); | ||
| 590 | hdaps_timer.function = hdaps_mousedev_poll; | ||
| 591 | hdaps_timer.expires = jiffies + HDAPS_POLL_PERIOD; | ||
| 592 | add_timer(&hdaps_timer); | ||
| 593 | |||
| 594 | printk(KERN_INFO "hdaps: driver successfully loaded.\n"); | 587 | printk(KERN_INFO "hdaps: driver successfully loaded.\n"); |
| 595 | return 0; | 588 | return 0; |
| 596 | 589 | ||
| 597 | out_idev: | 590 | out_idev: |
| 598 | input_free_device(hdaps_idev); | 591 | input_free_polled_device(hdaps_idev); |
| 599 | out_group: | 592 | out_group: |
| 600 | sysfs_remove_group(&pdev->dev.kobj, &hdaps_attribute_group); | 593 | sysfs_remove_group(&pdev->dev.kobj, &hdaps_attribute_group); |
| 601 | out_device: | 594 | out_device: |
| @@ -611,8 +604,8 @@ out: | |||
| 611 | 604 | ||
| 612 | static void __exit hdaps_exit(void) | 605 | static void __exit hdaps_exit(void) |
| 613 | { | 606 | { |
| 614 | del_timer_sync(&hdaps_timer); | 607 | input_unregister_polled_device(hdaps_idev); |
| 615 | input_unregister_device(hdaps_idev); | 608 | input_free_polled_device(hdaps_idev); |
| 616 | sysfs_remove_group(&pdev->dev.kobj, &hdaps_attribute_group); | 609 | sysfs_remove_group(&pdev->dev.kobj, &hdaps_attribute_group); |
| 617 | platform_device_unregister(pdev); | 610 | platform_device_unregister(pdev); |
| 618 | platform_driver_unregister(&hdaps_driver); | 611 | platform_driver_unregister(&hdaps_driver); |
diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h index 6545fa798b12..1b3327ad6bc4 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib.h +++ b/drivers/infiniband/ulp/ipoib/ipoib.h | |||
| @@ -349,6 +349,7 @@ struct ipoib_neigh { | |||
| 349 | struct sk_buff_head queue; | 349 | struct sk_buff_head queue; |
| 350 | 350 | ||
| 351 | struct neighbour *neighbour; | 351 | struct neighbour *neighbour; |
| 352 | struct net_device *dev; | ||
| 352 | 353 | ||
| 353 | struct list_head list; | 354 | struct list_head list; |
| 354 | }; | 355 | }; |
| @@ -365,7 +366,8 @@ static inline struct ipoib_neigh **to_ipoib_neigh(struct neighbour *neigh) | |||
| 365 | INFINIBAND_ALEN, sizeof(void *)); | 366 | INFINIBAND_ALEN, sizeof(void *)); |
| 366 | } | 367 | } |
| 367 | 368 | ||
| 368 | struct ipoib_neigh *ipoib_neigh_alloc(struct neighbour *neigh); | 369 | struct ipoib_neigh *ipoib_neigh_alloc(struct neighbour *neigh, |
| 370 | struct net_device *dev); | ||
| 369 | void ipoib_neigh_free(struct net_device *dev, struct ipoib_neigh *neigh); | 371 | void ipoib_neigh_free(struct net_device *dev, struct ipoib_neigh *neigh); |
| 370 | 372 | ||
| 371 | extern struct workqueue_struct *ipoib_workqueue; | 373 | extern struct workqueue_struct *ipoib_workqueue; |
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index e072f3c32ce6..362610d870e4 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c | |||
| @@ -517,7 +517,7 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev) | |||
| 517 | struct ipoib_path *path; | 517 | struct ipoib_path *path; |
| 518 | struct ipoib_neigh *neigh; | 518 | struct ipoib_neigh *neigh; |
| 519 | 519 | ||
| 520 | neigh = ipoib_neigh_alloc(skb->dst->neighbour); | 520 | neigh = ipoib_neigh_alloc(skb->dst->neighbour, skb->dev); |
| 521 | if (!neigh) { | 521 | if (!neigh) { |
| 522 | ++dev->stats.tx_dropped; | 522 | ++dev->stats.tx_dropped; |
| 523 | dev_kfree_skb_any(skb); | 523 | dev_kfree_skb_any(skb); |
| @@ -692,9 +692,10 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
| 692 | goto out; | 692 | goto out; |
| 693 | } | 693 | } |
| 694 | } else if (neigh->ah) { | 694 | } else if (neigh->ah) { |
| 695 | if (unlikely(memcmp(&neigh->dgid.raw, | 695 | if (unlikely((memcmp(&neigh->dgid.raw, |
| 696 | skb->dst->neighbour->ha + 4, | 696 | skb->dst->neighbour->ha + 4, |
| 697 | sizeof(union ib_gid)))) { | 697 | sizeof(union ib_gid))) || |
| 698 | (neigh->dev != dev))) { | ||
| 698 | spin_lock(&priv->lock); | 699 | spin_lock(&priv->lock); |
| 699 | /* | 700 | /* |
| 700 | * It's safe to call ipoib_put_ah() inside | 701 | * It's safe to call ipoib_put_ah() inside |
| @@ -817,6 +818,13 @@ static void ipoib_neigh_cleanup(struct neighbour *n) | |||
| 817 | unsigned long flags; | 818 | unsigned long flags; |
| 818 | struct ipoib_ah *ah = NULL; | 819 | struct ipoib_ah *ah = NULL; |
| 819 | 820 | ||
| 821 | neigh = *to_ipoib_neigh(n); | ||
| 822 | if (neigh) { | ||
| 823 | priv = netdev_priv(neigh->dev); | ||
| 824 | ipoib_dbg(priv, "neigh_destructor for bonding device: %s\n", | ||
| 825 | n->dev->name); | ||
| 826 | } else | ||
| 827 | return; | ||
| 820 | ipoib_dbg(priv, | 828 | ipoib_dbg(priv, |
| 821 | "neigh_cleanup for %06x " IPOIB_GID_FMT "\n", | 829 | "neigh_cleanup for %06x " IPOIB_GID_FMT "\n", |
| 822 | IPOIB_QPN(n->ha), | 830 | IPOIB_QPN(n->ha), |
| @@ -824,13 +832,10 @@ static void ipoib_neigh_cleanup(struct neighbour *n) | |||
| 824 | 832 | ||
| 825 | spin_lock_irqsave(&priv->lock, flags); | 833 | spin_lock_irqsave(&priv->lock, flags); |
| 826 | 834 | ||
| 827 | neigh = *to_ipoib_neigh(n); | 835 | if (neigh->ah) |
| 828 | if (neigh) { | 836 | ah = neigh->ah; |
| 829 | if (neigh->ah) | 837 | list_del(&neigh->list); |
| 830 | ah = neigh->ah; | 838 | ipoib_neigh_free(n->dev, neigh); |
| 831 | list_del(&neigh->list); | ||
| 832 | ipoib_neigh_free(n->dev, neigh); | ||
| 833 | } | ||
| 834 | 839 | ||
| 835 | spin_unlock_irqrestore(&priv->lock, flags); | 840 | spin_unlock_irqrestore(&priv->lock, flags); |
| 836 | 841 | ||
| @@ -838,7 +843,8 @@ static void ipoib_neigh_cleanup(struct neighbour *n) | |||
| 838 | ipoib_put_ah(ah); | 843 | ipoib_put_ah(ah); |
| 839 | } | 844 | } |
| 840 | 845 | ||
| 841 | struct ipoib_neigh *ipoib_neigh_alloc(struct neighbour *neighbour) | 846 | struct ipoib_neigh *ipoib_neigh_alloc(struct neighbour *neighbour, |
| 847 | struct net_device *dev) | ||
| 842 | { | 848 | { |
| 843 | struct ipoib_neigh *neigh; | 849 | struct ipoib_neigh *neigh; |
| 844 | 850 | ||
| @@ -847,6 +853,7 @@ struct ipoib_neigh *ipoib_neigh_alloc(struct neighbour *neighbour) | |||
| 847 | return NULL; | 853 | return NULL; |
| 848 | 854 | ||
| 849 | neigh->neighbour = neighbour; | 855 | neigh->neighbour = neighbour; |
| 856 | neigh->dev = dev; | ||
| 850 | *to_ipoib_neigh(neighbour) = neigh; | 857 | *to_ipoib_neigh(neighbour) = neigh; |
| 851 | skb_queue_head_init(&neigh->queue); | 858 | skb_queue_head_init(&neigh->queue); |
| 852 | ipoib_cm_set(neigh, NULL); | 859 | ipoib_cm_set(neigh, NULL); |
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c index 827820ec66d1..9bcfc7ad6aa6 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c | |||
| @@ -705,7 +705,8 @@ out: | |||
| 705 | if (skb->dst && | 705 | if (skb->dst && |
| 706 | skb->dst->neighbour && | 706 | skb->dst->neighbour && |
| 707 | !*to_ipoib_neigh(skb->dst->neighbour)) { | 707 | !*to_ipoib_neigh(skb->dst->neighbour)) { |
| 708 | struct ipoib_neigh *neigh = ipoib_neigh_alloc(skb->dst->neighbour); | 708 | struct ipoib_neigh *neigh = ipoib_neigh_alloc(skb->dst->neighbour, |
| 709 | skb->dev); | ||
| 709 | 710 | ||
| 710 | if (neigh) { | 711 | if (neigh) { |
| 711 | kref_get(&mcast->ah->ref); | 712 | kref_get(&mcast->ah->ref); |
diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index 2d87357e2b2b..63512d906f02 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig | |||
| @@ -114,28 +114,6 @@ config INPUT_JOYDEV | |||
| 114 | To compile this driver as a module, choose M here: the | 114 | To compile this driver as a module, choose M here: the |
| 115 | module will be called joydev. | 115 | module will be called joydev. |
| 116 | 116 | ||
| 117 | config INPUT_TSDEV | ||
| 118 | tristate "Touchscreen interface" | ||
| 119 | ---help--- | ||
| 120 | Say Y here if you have an application that only can understand the | ||
| 121 | Compaq touchscreen protocol for absolute pointer data. This is | ||
| 122 | useful namely for embedded configurations. | ||
| 123 | |||
| 124 | If unsure, say N. | ||
| 125 | |||
| 126 | To compile this driver as a module, choose M here: the | ||
| 127 | module will be called tsdev. | ||
| 128 | |||
| 129 | config INPUT_TSDEV_SCREEN_X | ||
| 130 | int "Horizontal screen resolution" | ||
| 131 | depends on INPUT_TSDEV | ||
| 132 | default "240" | ||
| 133 | |||
| 134 | config INPUT_TSDEV_SCREEN_Y | ||
| 135 | int "Vertical screen resolution" | ||
| 136 | depends on INPUT_TSDEV | ||
| 137 | default "320" | ||
| 138 | |||
| 139 | config INPUT_EVDEV | 117 | config INPUT_EVDEV |
| 140 | tristate "Event interface" | 118 | tristate "Event interface" |
| 141 | help | 119 | help |
diff --git a/drivers/input/Makefile b/drivers/input/Makefile index 15eb752697b3..99af903bd3ce 100644 --- a/drivers/input/Makefile +++ b/drivers/input/Makefile | |||
| @@ -13,7 +13,6 @@ obj-$(CONFIG_INPUT_POLLDEV) += input-polldev.o | |||
| 13 | obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o | 13 | obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o |
| 14 | obj-$(CONFIG_INPUT_JOYDEV) += joydev.o | 14 | obj-$(CONFIG_INPUT_JOYDEV) += joydev.o |
| 15 | obj-$(CONFIG_INPUT_EVDEV) += evdev.o | 15 | obj-$(CONFIG_INPUT_EVDEV) += evdev.o |
| 16 | obj-$(CONFIG_INPUT_TSDEV) += tsdev.o | ||
| 17 | obj-$(CONFIG_INPUT_EVBUG) += evbug.o | 16 | obj-$(CONFIG_INPUT_EVBUG) += evbug.o |
| 18 | 17 | ||
| 19 | obj-$(CONFIG_INPUT_KEYBOARD) += keyboard/ | 18 | obj-$(CONFIG_INPUT_KEYBOARD) += keyboard/ |
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index f1c3d6cebd58..1d62c8b88e12 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c | |||
| @@ -30,6 +30,8 @@ struct evdev { | |||
| 30 | wait_queue_head_t wait; | 30 | wait_queue_head_t wait; |
| 31 | struct evdev_client *grab; | 31 | struct evdev_client *grab; |
| 32 | struct list_head client_list; | 32 | struct list_head client_list; |
| 33 | spinlock_t client_lock; /* protects client_list */ | ||
| 34 | struct mutex mutex; | ||
| 33 | struct device dev; | 35 | struct device dev; |
| 34 | }; | 36 | }; |
| 35 | 37 | ||
| @@ -37,39 +39,54 @@ struct evdev_client { | |||
| 37 | struct input_event buffer[EVDEV_BUFFER_SIZE]; | 39 | struct input_event buffer[EVDEV_BUFFER_SIZE]; |
| 38 | int head; | 40 | int head; |
| 39 | int tail; | 41 | int tail; |
| 42 | spinlock_t buffer_lock; /* protects access to buffer, head and tail */ | ||
| 40 | struct fasync_struct *fasync; | 43 | struct fasync_struct *fasync; |
| 41 | struct evdev *evdev; | 44 | struct evdev *evdev; |
| 42 | struct list_head node; | 45 | struct list_head node; |
| 43 | }; | 46 | }; |
| 44 | 47 | ||
| 45 | static struct evdev *evdev_table[EVDEV_MINORS]; | 48 | static struct evdev *evdev_table[EVDEV_MINORS]; |
| 49 | static DEFINE_MUTEX(evdev_table_mutex); | ||
| 46 | 50 | ||
| 47 | static void evdev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) | 51 | static void evdev_pass_event(struct evdev_client *client, |
| 52 | struct input_event *event) | ||
| 53 | { | ||
| 54 | /* | ||
| 55 | * Interrupts are disabled, just acquire the lock | ||
| 56 | */ | ||
| 57 | spin_lock(&client->buffer_lock); | ||
| 58 | client->buffer[client->head++] = *event; | ||
| 59 | client->head &= EVDEV_BUFFER_SIZE - 1; | ||
| 60 | spin_unlock(&client->buffer_lock); | ||
| 61 | |||
| 62 | kill_fasync(&client->fasync, SIGIO, POLL_IN); | ||
| 63 | } | ||
| 64 | |||
| 65 | /* | ||
| 66 | * Pass incoming event to all connected clients. | ||
| 67 | */ | ||
| 68 | static void evdev_event(struct input_handle *handle, | ||
| 69 | unsigned int type, unsigned int code, int value) | ||
| 48 | { | 70 | { |
| 49 | struct evdev *evdev = handle->private; | 71 | struct evdev *evdev = handle->private; |
| 50 | struct evdev_client *client; | 72 | struct evdev_client *client; |
| 73 | struct input_event event; | ||
| 51 | 74 | ||
| 52 | if (evdev->grab) { | 75 | do_gettimeofday(&event.time); |
| 53 | client = evdev->grab; | 76 | event.type = type; |
| 77 | event.code = code; | ||
| 78 | event.value = value; | ||
| 54 | 79 | ||
| 55 | do_gettimeofday(&client->buffer[client->head].time); | 80 | rcu_read_lock(); |
| 56 | client->buffer[client->head].type = type; | ||
| 57 | client->buffer[client->head].code = code; | ||
| 58 | client->buffer[client->head].value = value; | ||
| 59 | client->head = (client->head + 1) & (EVDEV_BUFFER_SIZE - 1); | ||
| 60 | 81 | ||
| 61 | kill_fasync(&client->fasync, SIGIO, POLL_IN); | 82 | client = rcu_dereference(evdev->grab); |
| 62 | } else | 83 | if (client) |
| 63 | list_for_each_entry(client, &evdev->client_list, node) { | 84 | evdev_pass_event(client, &event); |
| 85 | else | ||
| 86 | list_for_each_entry_rcu(client, &evdev->client_list, node) | ||
| 87 | evdev_pass_event(client, &event); | ||
| 64 | 88 | ||
| 65 | do_gettimeofday(&client->buffer[client->head].time); | 89 | rcu_read_unlock(); |
| 66 | client->buffer[client->head].type = type; | ||
| 67 | client->buffer[client->head].code = code; | ||
| 68 | client->buffer[client->head].value = value; | ||
| 69 | client->head = (client->head + 1) & (EVDEV_BUFFER_SIZE - 1); | ||
| 70 | |||
| 71 | kill_fasync(&client->fasync, SIGIO, POLL_IN); | ||
| 72 | } | ||
| 73 | 90 | ||
| 74 | wake_up_interruptible(&evdev->wait); | 91 | wake_up_interruptible(&evdev->wait); |
| 75 | } | 92 | } |
| @@ -88,38 +105,140 @@ static int evdev_flush(struct file *file, fl_owner_t id) | |||
| 88 | { | 105 | { |
| 89 | struct evdev_client *client = file->private_data; | 106 | struct evdev_client *client = file->private_data; |
| 90 | struct evdev *evdev = client->evdev; | 107 | struct evdev *evdev = client->evdev; |
| 108 | int retval; | ||
| 109 | |||
| 110 | retval = mutex_lock_interruptible(&evdev->mutex); | ||
| 111 | if (retval) | ||
| 112 | return retval; | ||
| 91 | 113 | ||
| 92 | if (!evdev->exist) | 114 | if (!evdev->exist) |
| 93 | return -ENODEV; | 115 | retval = -ENODEV; |
| 116 | else | ||
| 117 | retval = input_flush_device(&evdev->handle, file); | ||
| 94 | 118 | ||
| 95 | return input_flush_device(&evdev->handle, file); | 119 | mutex_unlock(&evdev->mutex); |
| 120 | return retval; | ||
| 96 | } | 121 | } |
| 97 | 122 | ||
| 98 | static void evdev_free(struct device *dev) | 123 | static void evdev_free(struct device *dev) |
| 99 | { | 124 | { |
| 100 | struct evdev *evdev = container_of(dev, struct evdev, dev); | 125 | struct evdev *evdev = container_of(dev, struct evdev, dev); |
| 101 | 126 | ||
| 102 | evdev_table[evdev->minor] = NULL; | ||
| 103 | kfree(evdev); | 127 | kfree(evdev); |
| 104 | } | 128 | } |
| 105 | 129 | ||
| 130 | /* | ||
| 131 | * Grabs an event device (along with underlying input device). | ||
| 132 | * This function is called with evdev->mutex taken. | ||
| 133 | */ | ||
| 134 | static int evdev_grab(struct evdev *evdev, struct evdev_client *client) | ||
| 135 | { | ||
| 136 | int error; | ||
| 137 | |||
| 138 | if (evdev->grab) | ||
| 139 | return -EBUSY; | ||
| 140 | |||
| 141 | error = input_grab_device(&evdev->handle); | ||
| 142 | if (error) | ||
| 143 | return error; | ||
| 144 | |||
| 145 | rcu_assign_pointer(evdev->grab, client); | ||
| 146 | synchronize_rcu(); | ||
| 147 | |||
| 148 | return 0; | ||
| 149 | } | ||
| 150 | |||
| 151 | static int evdev_ungrab(struct evdev *evdev, struct evdev_client *client) | ||
| 152 | { | ||
| 153 | if (evdev->grab != client) | ||
| 154 | return -EINVAL; | ||
| 155 | |||
| 156 | rcu_assign_pointer(evdev->grab, NULL); | ||
| 157 | synchronize_rcu(); | ||
| 158 | input_release_device(&evdev->handle); | ||
| 159 | |||
| 160 | return 0; | ||
| 161 | } | ||
| 162 | |||
| 163 | static void evdev_attach_client(struct evdev *evdev, | ||
| 164 | struct evdev_client *client) | ||
| 165 | { | ||
| 166 | spin_lock(&evdev->client_lock); | ||
| 167 | list_add_tail_rcu(&client->node, &evdev->client_list); | ||
| 168 | spin_unlock(&evdev->client_lock); | ||
| 169 | synchronize_rcu(); | ||
| 170 | } | ||
| 171 | |||
| 172 | static void evdev_detach_client(struct evdev *evdev, | ||
| 173 | struct evdev_client *client) | ||
| 174 | { | ||
| 175 | spin_lock(&evdev->client_lock); | ||
| 176 | list_del_rcu(&client->node); | ||
| 177 | spin_unlock(&evdev->client_lock); | ||
| 178 | synchronize_rcu(); | ||
| 179 | } | ||
| 180 | |||
| 181 | static int evdev_open_device(struct evdev *evdev) | ||
| 182 | { | ||
| 183 | int retval; | ||
| 184 | |||
| 185 | retval = mutex_lock_interruptible(&evdev->mutex); | ||
| 186 | if (retval) | ||
| 187 | return retval; | ||
| 188 | |||
| 189 | if (!evdev->exist) | ||
| 190 | retval = -ENODEV; | ||
| 191 | else if (!evdev->open++) { | ||
| 192 | retval = input_open_device(&evdev->handle); | ||
| 193 | if (retval) | ||
| 194 | evdev->open--; | ||
| 195 | } | ||
| 196 | |||
| 197 | mutex_unlock(&evdev->mutex); | ||
| 198 | return retval; | ||
| 199 | } | ||
| 200 | |||
| 201 | static void evdev_close_device(struct evdev *evdev) | ||
| 202 | { | ||
| 203 | mutex_lock(&evdev->mutex); | ||
| 204 | |||
| 205 | if (evdev->exist && !--evdev->open) | ||
| 206 | input_close_device(&evdev->handle); | ||
| 207 | |||
| 208 | mutex_unlock(&evdev->mutex); | ||
| 209 | } | ||
| 210 | |||
| 211 | /* | ||
| 212 | * Wake up users waiting for IO so they can disconnect from | ||
| 213 | * dead device. | ||
| 214 | */ | ||
| 215 | static void evdev_hangup(struct evdev *evdev) | ||
| 216 | { | ||
| 217 | struct evdev_client *client; | ||
| 218 | |||
| 219 | spin_lock(&evdev->client_lock); | ||
| 220 | list_for_each_entry(client, &evdev->client_list, node) | ||
| 221 | kill_fasync(&client->fasync, SIGIO, POLL_HUP); | ||
| 222 | spin_unlock(&evdev->client_lock); | ||
| 223 | |||
| 224 | wake_up_interruptible(&evdev->wait); | ||
| 225 | } | ||
| 226 | |||
| 106 | static int evdev_release(struct inode *inode, struct file *file) | 227 | static int evdev_release(struct inode *inode, struct file *file) |
| 107 | { | 228 | { |
| 108 | struct evdev_client *client = file->private_data; | 229 | struct evdev_client *client = file->private_data; |
| 109 | struct evdev *evdev = client->evdev; | 230 | struct evdev *evdev = client->evdev; |
| 110 | 231 | ||
| 111 | if (evdev->grab == client) { | 232 | mutex_lock(&evdev->mutex); |
| 112 | input_release_device(&evdev->handle); | 233 | if (evdev->grab == client) |
| 113 | evdev->grab = NULL; | 234 | evdev_ungrab(evdev, client); |
| 114 | } | 235 | mutex_unlock(&evdev->mutex); |
| 115 | 236 | ||
| 116 | evdev_fasync(-1, file, 0); | 237 | evdev_fasync(-1, file, 0); |
| 117 | list_del(&client->node); | 238 | evdev_detach_client(evdev, client); |
| 118 | kfree(client); | 239 | kfree(client); |
| 119 | 240 | ||
| 120 | if (!--evdev->open && evdev->exist) | 241 | evdev_close_device(evdev); |
| 121 | input_close_device(&evdev->handle); | ||
| 122 | |||
| 123 | put_device(&evdev->dev); | 242 | put_device(&evdev->dev); |
| 124 | 243 | ||
| 125 | return 0; | 244 | return 0; |
| @@ -127,41 +246,44 @@ static int evdev_release(struct inode *inode, struct file *file) | |||
| 127 | 246 | ||
| 128 | static int evdev_open(struct inode *inode, struct file *file) | 247 | static int evdev_open(struct inode *inode, struct file *file) |
| 129 | { | 248 | { |
| 130 | struct evdev_client *client; | ||
| 131 | struct evdev *evdev; | 249 | struct evdev *evdev; |
| 250 | struct evdev_client *client; | ||
| 132 | int i = iminor(inode) - EVDEV_MINOR_BASE; | 251 | int i = iminor(inode) - EVDEV_MINOR_BASE; |
| 133 | int error; | 252 | int error; |
| 134 | 253 | ||
| 135 | if (i >= EVDEV_MINORS) | 254 | if (i >= EVDEV_MINORS) |
| 136 | return -ENODEV; | 255 | return -ENODEV; |
| 137 | 256 | ||
| 257 | error = mutex_lock_interruptible(&evdev_table_mutex); | ||
| 258 | if (error) | ||
| 259 | return error; | ||
| 138 | evdev = evdev_table[i]; | 260 | evdev = evdev_table[i]; |
| 261 | if (evdev) | ||
| 262 | get_device(&evdev->dev); | ||
| 263 | mutex_unlock(&evdev_table_mutex); | ||
| 139 | 264 | ||
| 140 | if (!evdev || !evdev->exist) | 265 | if (!evdev) |
| 141 | return -ENODEV; | 266 | return -ENODEV; |
| 142 | 267 | ||
| 143 | get_device(&evdev->dev); | ||
| 144 | |||
| 145 | client = kzalloc(sizeof(struct evdev_client), GFP_KERNEL); | 268 | client = kzalloc(sizeof(struct evdev_client), GFP_KERNEL); |
| 146 | if (!client) { | 269 | if (!client) { |
| 147 | error = -ENOMEM; | 270 | error = -ENOMEM; |
| 148 | goto err_put_evdev; | 271 | goto err_put_evdev; |
| 149 | } | 272 | } |
| 150 | 273 | ||
| 274 | spin_lock_init(&client->buffer_lock); | ||
| 151 | client->evdev = evdev; | 275 | client->evdev = evdev; |
| 152 | list_add_tail(&client->node, &evdev->client_list); | 276 | evdev_attach_client(evdev, client); |
| 153 | 277 | ||
| 154 | if (!evdev->open++ && evdev->exist) { | 278 | error = evdev_open_device(evdev); |
| 155 | error = input_open_device(&evdev->handle); | 279 | if (error) |
| 156 | if (error) | 280 | goto err_free_client; |
| 157 | goto err_free_client; | ||
| 158 | } | ||
| 159 | 281 | ||
| 160 | file->private_data = client; | 282 | file->private_data = client; |
| 161 | return 0; | 283 | return 0; |
| 162 | 284 | ||
| 163 | err_free_client: | 285 | err_free_client: |
| 164 | list_del(&client->node); | 286 | evdev_detach_client(evdev, client); |
| 165 | kfree(client); | 287 | kfree(client); |
| 166 | err_put_evdev: | 288 | err_put_evdev: |
| 167 | put_device(&evdev->dev); | 289 | put_device(&evdev->dev); |
| @@ -197,12 +319,14 @@ static inline size_t evdev_event_size(void) | |||
| 197 | sizeof(struct input_event_compat) : sizeof(struct input_event); | 319 | sizeof(struct input_event_compat) : sizeof(struct input_event); |
| 198 | } | 320 | } |
| 199 | 321 | ||
| 200 | static int evdev_event_from_user(const char __user *buffer, struct input_event *event) | 322 | static int evdev_event_from_user(const char __user *buffer, |
| 323 | struct input_event *event) | ||
| 201 | { | 324 | { |
| 202 | if (COMPAT_TEST) { | 325 | if (COMPAT_TEST) { |
| 203 | struct input_event_compat compat_event; | 326 | struct input_event_compat compat_event; |
| 204 | 327 | ||
| 205 | if (copy_from_user(&compat_event, buffer, sizeof(struct input_event_compat))) | 328 | if (copy_from_user(&compat_event, buffer, |
| 329 | sizeof(struct input_event_compat))) | ||
| 206 | return -EFAULT; | 330 | return -EFAULT; |
| 207 | 331 | ||
| 208 | event->time.tv_sec = compat_event.time.tv_sec; | 332 | event->time.tv_sec = compat_event.time.tv_sec; |
| @@ -219,7 +343,8 @@ static int evdev_event_from_user(const char __user *buffer, struct input_event * | |||
| 219 | return 0; | 343 | return 0; |
| 220 | } | 344 | } |
| 221 | 345 | ||
| 222 | static int evdev_event_to_user(char __user *buffer, const struct input_event *event) | 346 | static int evdev_event_to_user(char __user *buffer, |
| 347 | const struct input_event *event) | ||
| 223 | { | 348 | { |
| 224 | if (COMPAT_TEST) { | 349 | if (COMPAT_TEST) { |
| 225 | struct input_event_compat compat_event; | 350 | struct input_event_compat compat_event; |
| @@ -230,7 +355,8 @@ static int evdev_event_to_user(char __user *buffer, const struct input_event *ev | |||
| 230 | compat_event.code = event->code; | 355 | compat_event.code = event->code; |
| 231 | compat_event.value = event->value; | 356 | compat_event.value = event->value; |
| 232 | 357 | ||
| 233 | if (copy_to_user(buffer, &compat_event, sizeof(struct input_event_compat))) | 358 | if (copy_to_user(buffer, &compat_event, |
| 359 | sizeof(struct input_event_compat))) | ||
| 234 | return -EFAULT; | 360 | return -EFAULT; |
| 235 | 361 | ||
| 236 | } else { | 362 | } else { |
| @@ -248,7 +374,8 @@ static inline size_t evdev_event_size(void) | |||
| 248 | return sizeof(struct input_event); | 374 | return sizeof(struct input_event); |
| 249 | } | 375 | } |
| 250 | 376 | ||
| 251 | static int evdev_event_from_user(const char __user *buffer, struct input_event *event) | 377 | static int evdev_event_from_user(const char __user *buffer, |
| 378 | struct input_event *event) | ||
| 252 | { | 379 | { |
| 253 | if (copy_from_user(event, buffer, sizeof(struct input_event))) | 380 | if (copy_from_user(event, buffer, sizeof(struct input_event))) |
| 254 | return -EFAULT; | 381 | return -EFAULT; |
| @@ -256,7 +383,8 @@ static int evdev_event_from_user(const char __user *buffer, struct input_event * | |||
| 256 | return 0; | 383 | return 0; |
| 257 | } | 384 | } |
| 258 | 385 | ||
| 259 | static int evdev_event_to_user(char __user *buffer, const struct input_event *event) | 386 | static int evdev_event_to_user(char __user *buffer, |
| 387 | const struct input_event *event) | ||
| 260 | { | 388 | { |
| 261 | if (copy_to_user(buffer, event, sizeof(struct input_event))) | 389 | if (copy_to_user(buffer, event, sizeof(struct input_event))) |
| 262 | return -EFAULT; | 390 | return -EFAULT; |
| @@ -266,37 +394,71 @@ static int evdev_event_to_user(char __user *buffer, const struct input_event *ev | |||
| 266 | 394 | ||
| 267 | #endif /* CONFIG_COMPAT */ | 395 | #endif /* CONFIG_COMPAT */ |
| 268 | 396 | ||
| 269 | static ssize_t evdev_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) | 397 | static ssize_t evdev_write(struct file *file, const char __user *buffer, |
| 398 | size_t count, loff_t *ppos) | ||
| 270 | { | 399 | { |
| 271 | struct evdev_client *client = file->private_data; | 400 | struct evdev_client *client = file->private_data; |
| 272 | struct evdev *evdev = client->evdev; | 401 | struct evdev *evdev = client->evdev; |
| 273 | struct input_event event; | 402 | struct input_event event; |
| 274 | int retval = 0; | 403 | int retval; |
| 275 | 404 | ||
| 276 | if (!evdev->exist) | 405 | retval = mutex_lock_interruptible(&evdev->mutex); |
| 277 | return -ENODEV; | 406 | if (retval) |
| 407 | return retval; | ||
| 408 | |||
| 409 | if (!evdev->exist) { | ||
| 410 | retval = -ENODEV; | ||
| 411 | goto out; | ||
| 412 | } | ||
| 278 | 413 | ||
| 279 | while (retval < count) { | 414 | while (retval < count) { |
| 280 | 415 | ||
| 281 | if (evdev_event_from_user(buffer + retval, &event)) | 416 | if (evdev_event_from_user(buffer + retval, &event)) { |
| 282 | return -EFAULT; | 417 | retval = -EFAULT; |
| 283 | input_inject_event(&evdev->handle, event.type, event.code, event.value); | 418 | goto out; |
| 419 | } | ||
| 420 | |||
| 421 | input_inject_event(&evdev->handle, | ||
| 422 | event.type, event.code, event.value); | ||
| 284 | retval += evdev_event_size(); | 423 | retval += evdev_event_size(); |
| 285 | } | 424 | } |
| 286 | 425 | ||
| 426 | out: | ||
| 427 | mutex_unlock(&evdev->mutex); | ||
| 287 | return retval; | 428 | return retval; |
| 288 | } | 429 | } |
| 289 | 430 | ||
| 290 | static ssize_t evdev_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) | 431 | static int evdev_fetch_next_event(struct evdev_client *client, |
| 432 | struct input_event *event) | ||
| 433 | { | ||
| 434 | int have_event; | ||
| 435 | |||
| 436 | spin_lock_irq(&client->buffer_lock); | ||
| 437 | |||
| 438 | have_event = client->head != client->tail; | ||
| 439 | if (have_event) { | ||
| 440 | *event = client->buffer[client->tail++]; | ||
| 441 | client->tail &= EVDEV_BUFFER_SIZE - 1; | ||
| 442 | } | ||
| 443 | |||
| 444 | spin_unlock_irq(&client->buffer_lock); | ||
| 445 | |||
| 446 | return have_event; | ||
| 447 | } | ||
| 448 | |||
| 449 | static ssize_t evdev_read(struct file *file, char __user *buffer, | ||
| 450 | size_t count, loff_t *ppos) | ||
| 291 | { | 451 | { |
| 292 | struct evdev_client *client = file->private_data; | 452 | struct evdev_client *client = file->private_data; |
| 293 | struct evdev *evdev = client->evdev; | 453 | struct evdev *evdev = client->evdev; |
| 454 | struct input_event event; | ||
| 294 | int retval; | 455 | int retval; |
| 295 | 456 | ||
| 296 | if (count < evdev_event_size()) | 457 | if (count < evdev_event_size()) |
| 297 | return -EINVAL; | 458 | return -EINVAL; |
| 298 | 459 | ||
| 299 | if (client->head == client->tail && evdev->exist && (file->f_flags & O_NONBLOCK)) | 460 | if (client->head == client->tail && evdev->exist && |
| 461 | (file->f_flags & O_NONBLOCK)) | ||
| 300 | return -EAGAIN; | 462 | return -EAGAIN; |
| 301 | 463 | ||
| 302 | retval = wait_event_interruptible(evdev->wait, | 464 | retval = wait_event_interruptible(evdev->wait, |
| @@ -307,14 +469,12 @@ static ssize_t evdev_read(struct file *file, char __user *buffer, size_t count, | |||
| 307 | if (!evdev->exist) | 469 | if (!evdev->exist) |
| 308 | return -ENODEV; | 470 | return -ENODEV; |
| 309 | 471 | ||
| 310 | while (client->head != client->tail && retval + evdev_event_size() <= count) { | 472 | while (retval + evdev_event_size() <= count && |
| 311 | 473 | evdev_fetch_next_event(client, &event)) { | |
| 312 | struct input_event *event = (struct input_event *) client->buffer + client->tail; | ||
| 313 | 474 | ||
| 314 | if (evdev_event_to_user(buffer + retval, event)) | 475 | if (evdev_event_to_user(buffer + retval, &event)) |
| 315 | return -EFAULT; | 476 | return -EFAULT; |
| 316 | 477 | ||
| 317 | client->tail = (client->tail + 1) & (EVDEV_BUFFER_SIZE - 1); | ||
| 318 | retval += evdev_event_size(); | 478 | retval += evdev_event_size(); |
| 319 | } | 479 | } |
| 320 | 480 | ||
| @@ -409,8 +569,8 @@ static int str_to_user(const char *str, unsigned int maxlen, void __user *p) | |||
| 409 | return copy_to_user(p, str, len) ? -EFAULT : len; | 569 | return copy_to_user(p, str, len) ? -EFAULT : len; |
| 410 | } | 570 | } |
| 411 | 571 | ||
| 412 | static long evdev_ioctl_handler(struct file *file, unsigned int cmd, | 572 | static long evdev_do_ioctl(struct file *file, unsigned int cmd, |
| 413 | void __user *p, int compat_mode) | 573 | void __user *p, int compat_mode) |
| 414 | { | 574 | { |
| 415 | struct evdev_client *client = file->private_data; | 575 | struct evdev_client *client = file->private_data; |
| 416 | struct evdev *evdev = client->evdev; | 576 | struct evdev *evdev = client->evdev; |
| @@ -421,215 +581,289 @@ static long evdev_ioctl_handler(struct file *file, unsigned int cmd, | |||
| 421 | int i, t, u, v; | 581 | int i, t, u, v; |
| 422 | int error; | 582 | int error; |
| 423 | 583 | ||
| 424 | if (!evdev->exist) | ||
| 425 | return -ENODEV; | ||
| 426 | |||
| 427 | switch (cmd) { | 584 | switch (cmd) { |
| 428 | 585 | ||
| 429 | case EVIOCGVERSION: | 586 | case EVIOCGVERSION: |
| 430 | return put_user(EV_VERSION, ip); | 587 | return put_user(EV_VERSION, ip); |
| 431 | 588 | ||
| 432 | case EVIOCGID: | 589 | case EVIOCGID: |
| 433 | if (copy_to_user(p, &dev->id, sizeof(struct input_id))) | 590 | if (copy_to_user(p, &dev->id, sizeof(struct input_id))) |
| 434 | return -EFAULT; | 591 | return -EFAULT; |
| 435 | return 0; | 592 | return 0; |
| 436 | 593 | ||
| 437 | case EVIOCGREP: | 594 | case EVIOCGREP: |
| 438 | if (!test_bit(EV_REP, dev->evbit)) | 595 | if (!test_bit(EV_REP, dev->evbit)) |
| 439 | return -ENOSYS; | 596 | return -ENOSYS; |
| 440 | if (put_user(dev->rep[REP_DELAY], ip)) | 597 | if (put_user(dev->rep[REP_DELAY], ip)) |
| 441 | return -EFAULT; | 598 | return -EFAULT; |
| 442 | if (put_user(dev->rep[REP_PERIOD], ip + 1)) | 599 | if (put_user(dev->rep[REP_PERIOD], ip + 1)) |
| 443 | return -EFAULT; | 600 | return -EFAULT; |
| 444 | return 0; | 601 | return 0; |
| 445 | 602 | ||
| 446 | case EVIOCSREP: | 603 | case EVIOCSREP: |
| 447 | if (!test_bit(EV_REP, dev->evbit)) | 604 | if (!test_bit(EV_REP, dev->evbit)) |
| 448 | return -ENOSYS; | 605 | return -ENOSYS; |
| 449 | if (get_user(u, ip)) | 606 | if (get_user(u, ip)) |
| 450 | return -EFAULT; | 607 | return -EFAULT; |
| 451 | if (get_user(v, ip + 1)) | 608 | if (get_user(v, ip + 1)) |
| 452 | return -EFAULT; | 609 | return -EFAULT; |
| 453 | 610 | ||
| 454 | input_inject_event(&evdev->handle, EV_REP, REP_DELAY, u); | 611 | input_inject_event(&evdev->handle, EV_REP, REP_DELAY, u); |
| 455 | input_inject_event(&evdev->handle, EV_REP, REP_PERIOD, v); | 612 | input_inject_event(&evdev->handle, EV_REP, REP_PERIOD, v); |
| 456 | 613 | ||
| 457 | return 0; | 614 | return 0; |
| 458 | 615 | ||
| 459 | case EVIOCGKEYCODE: | 616 | case EVIOCGKEYCODE: |
| 460 | if (get_user(t, ip)) | 617 | if (get_user(t, ip)) |
| 461 | return -EFAULT; | 618 | return -EFAULT; |
| 462 | 619 | ||
| 463 | error = dev->getkeycode(dev, t, &v); | 620 | error = dev->getkeycode(dev, t, &v); |
| 464 | if (error) | 621 | if (error) |
| 465 | return error; | 622 | return error; |
| 466 | 623 | ||
| 467 | if (put_user(v, ip + 1)) | 624 | if (put_user(v, ip + 1)) |
| 468 | return -EFAULT; | 625 | return -EFAULT; |
| 469 | 626 | ||
| 470 | return 0; | 627 | return 0; |
| 471 | 628 | ||
| 472 | case EVIOCSKEYCODE: | 629 | case EVIOCSKEYCODE: |
| 473 | if (get_user(t, ip) || get_user(v, ip + 1)) | 630 | if (get_user(t, ip) || get_user(v, ip + 1)) |
| 474 | return -EFAULT; | 631 | return -EFAULT; |
| 475 | 632 | ||
| 476 | return dev->setkeycode(dev, t, v); | 633 | return dev->setkeycode(dev, t, v); |
| 477 | 634 | ||
| 478 | case EVIOCSFF: | 635 | case EVIOCSFF: |
| 479 | if (copy_from_user(&effect, p, sizeof(effect))) | 636 | if (copy_from_user(&effect, p, sizeof(effect))) |
| 480 | return -EFAULT; | 637 | return -EFAULT; |
| 481 | 638 | ||
| 482 | error = input_ff_upload(dev, &effect, file); | 639 | error = input_ff_upload(dev, &effect, file); |
| 483 | 640 | ||
| 484 | if (put_user(effect.id, &(((struct ff_effect __user *)p)->id))) | 641 | if (put_user(effect.id, &(((struct ff_effect __user *)p)->id))) |
| 485 | return -EFAULT; | 642 | return -EFAULT; |
| 486 | 643 | ||
| 487 | return error; | 644 | return error; |
| 488 | 645 | ||
| 489 | case EVIOCRMFF: | 646 | case EVIOCRMFF: |
| 490 | return input_ff_erase(dev, (int)(unsigned long) p, file); | 647 | return input_ff_erase(dev, (int)(unsigned long) p, file); |
| 491 | 648 | ||
| 492 | case EVIOCGEFFECTS: | 649 | case EVIOCGEFFECTS: |
| 493 | i = test_bit(EV_FF, dev->evbit) ? dev->ff->max_effects : 0; | 650 | i = test_bit(EV_FF, dev->evbit) ? |
| 494 | if (put_user(i, ip)) | 651 | dev->ff->max_effects : 0; |
| 495 | return -EFAULT; | 652 | if (put_user(i, ip)) |
| 496 | return 0; | 653 | return -EFAULT; |
| 497 | 654 | return 0; | |
| 498 | case EVIOCGRAB: | 655 | |
| 499 | if (p) { | 656 | case EVIOCGRAB: |
| 500 | if (evdev->grab) | 657 | if (p) |
| 501 | return -EBUSY; | 658 | return evdev_grab(evdev, client); |
| 502 | if (input_grab_device(&evdev->handle)) | 659 | else |
| 503 | return -EBUSY; | 660 | return evdev_ungrab(evdev, client); |
| 504 | evdev->grab = client; | ||
| 505 | return 0; | ||
| 506 | } else { | ||
| 507 | if (evdev->grab != client) | ||
| 508 | return -EINVAL; | ||
| 509 | input_release_device(&evdev->handle); | ||
| 510 | evdev->grab = NULL; | ||
| 511 | return 0; | ||
| 512 | } | ||
| 513 | 661 | ||
| 514 | default: | 662 | default: |
| 515 | 663 | ||
| 516 | if (_IOC_TYPE(cmd) != 'E') | 664 | if (_IOC_TYPE(cmd) != 'E') |
| 517 | return -EINVAL; | 665 | return -EINVAL; |
| 518 | 666 | ||
| 519 | if (_IOC_DIR(cmd) == _IOC_READ) { | 667 | if (_IOC_DIR(cmd) == _IOC_READ) { |
| 520 | 668 | ||
| 521 | if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0,0))) { | 669 | if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0, 0))) { |
| 522 | 670 | ||
| 523 | unsigned long *bits; | 671 | unsigned long *bits; |
| 524 | int len; | 672 | int len; |
| 525 | 673 | ||
| 526 | switch (_IOC_NR(cmd) & EV_MAX) { | 674 | switch (_IOC_NR(cmd) & EV_MAX) { |
| 527 | case 0: bits = dev->evbit; len = EV_MAX; break; | ||
| 528 | case EV_KEY: bits = dev->keybit; len = KEY_MAX; break; | ||
| 529 | case EV_REL: bits = dev->relbit; len = REL_MAX; break; | ||
| 530 | case EV_ABS: bits = dev->absbit; len = ABS_MAX; break; | ||
| 531 | case EV_MSC: bits = dev->mscbit; len = MSC_MAX; break; | ||
| 532 | case EV_LED: bits = dev->ledbit; len = LED_MAX; break; | ||
| 533 | case EV_SND: bits = dev->sndbit; len = SND_MAX; break; | ||
| 534 | case EV_FF: bits = dev->ffbit; len = FF_MAX; break; | ||
| 535 | case EV_SW: bits = dev->swbit; len = SW_MAX; break; | ||
| 536 | default: return -EINVAL; | ||
| 537 | } | ||
| 538 | return bits_to_user(bits, len, _IOC_SIZE(cmd), p, compat_mode); | ||
| 539 | } | ||
| 540 | 675 | ||
| 541 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0))) | 676 | case 0: bits = dev->evbit; len = EV_MAX; break; |
| 542 | return bits_to_user(dev->key, KEY_MAX, _IOC_SIZE(cmd), | 677 | case EV_KEY: bits = dev->keybit; len = KEY_MAX; break; |
| 543 | p, compat_mode); | 678 | case EV_REL: bits = dev->relbit; len = REL_MAX; break; |
| 679 | case EV_ABS: bits = dev->absbit; len = ABS_MAX; break; | ||
| 680 | case EV_MSC: bits = dev->mscbit; len = MSC_MAX; break; | ||
| 681 | case EV_LED: bits = dev->ledbit; len = LED_MAX; break; | ||
| 682 | case EV_SND: bits = dev->sndbit; len = SND_MAX; break; | ||
| 683 | case EV_FF: bits = dev->ffbit; len = FF_MAX; break; | ||
| 684 | case EV_SW: bits = dev->swbit; len = SW_MAX; break; | ||
| 685 | default: return -EINVAL; | ||
| 686 | } | ||
| 687 | return bits_to_user(bits, len, _IOC_SIZE(cmd), p, compat_mode); | ||
| 688 | } | ||
| 544 | 689 | ||
| 545 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0))) | 690 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0))) |
| 546 | return bits_to_user(dev->led, LED_MAX, _IOC_SIZE(cmd), | 691 | return bits_to_user(dev->key, KEY_MAX, _IOC_SIZE(cmd), |
| 547 | p, compat_mode); | 692 | p, compat_mode); |
| 548 | 693 | ||
| 549 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0))) | 694 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0))) |
| 550 | return bits_to_user(dev->snd, SND_MAX, _IOC_SIZE(cmd), | 695 | return bits_to_user(dev->led, LED_MAX, _IOC_SIZE(cmd), |
| 551 | p, compat_mode); | 696 | p, compat_mode); |
| 552 | 697 | ||
| 553 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSW(0))) | 698 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0))) |
| 554 | return bits_to_user(dev->sw, SW_MAX, _IOC_SIZE(cmd), | 699 | return bits_to_user(dev->snd, SND_MAX, _IOC_SIZE(cmd), |
| 555 | p, compat_mode); | 700 | p, compat_mode); |
| 556 | 701 | ||
| 557 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) | 702 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSW(0))) |
| 558 | return str_to_user(dev->name, _IOC_SIZE(cmd), p); | 703 | return bits_to_user(dev->sw, SW_MAX, _IOC_SIZE(cmd), |
| 704 | p, compat_mode); | ||
| 559 | 705 | ||
| 560 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0))) | 706 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) |
| 561 | return str_to_user(dev->phys, _IOC_SIZE(cmd), p); | 707 | return str_to_user(dev->name, _IOC_SIZE(cmd), p); |
| 562 | 708 | ||
| 563 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0))) | 709 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0))) |
| 564 | return str_to_user(dev->uniq, _IOC_SIZE(cmd), p); | 710 | return str_to_user(dev->phys, _IOC_SIZE(cmd), p); |
| 565 | 711 | ||
| 566 | if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) { | 712 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0))) |
| 713 | return str_to_user(dev->uniq, _IOC_SIZE(cmd), p); | ||
| 567 | 714 | ||
| 568 | t = _IOC_NR(cmd) & ABS_MAX; | 715 | if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) { |
| 569 | 716 | ||
| 570 | abs.value = dev->abs[t]; | 717 | t = _IOC_NR(cmd) & ABS_MAX; |
| 571 | abs.minimum = dev->absmin[t]; | ||
| 572 | abs.maximum = dev->absmax[t]; | ||
| 573 | abs.fuzz = dev->absfuzz[t]; | ||
| 574 | abs.flat = dev->absflat[t]; | ||
| 575 | 718 | ||
| 576 | if (copy_to_user(p, &abs, sizeof(struct input_absinfo))) | 719 | abs.value = dev->abs[t]; |
| 577 | return -EFAULT; | 720 | abs.minimum = dev->absmin[t]; |
| 721 | abs.maximum = dev->absmax[t]; | ||
| 722 | abs.fuzz = dev->absfuzz[t]; | ||
| 723 | abs.flat = dev->absflat[t]; | ||
| 578 | 724 | ||
| 579 | return 0; | 725 | if (copy_to_user(p, &abs, sizeof(struct input_absinfo))) |
| 580 | } | 726 | return -EFAULT; |
| 581 | 727 | ||
| 728 | return 0; | ||
| 582 | } | 729 | } |
| 583 | 730 | ||
| 584 | if (_IOC_DIR(cmd) == _IOC_WRITE) { | 731 | } |
| 732 | |||
| 733 | if (_IOC_DIR(cmd) == _IOC_WRITE) { | ||
| 585 | 734 | ||
| 586 | if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) { | 735 | if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) { |
| 587 | 736 | ||
| 588 | t = _IOC_NR(cmd) & ABS_MAX; | 737 | t = _IOC_NR(cmd) & ABS_MAX; |
| 589 | 738 | ||
| 590 | if (copy_from_user(&abs, p, sizeof(struct input_absinfo))) | 739 | if (copy_from_user(&abs, p, |
| 591 | return -EFAULT; | 740 | sizeof(struct input_absinfo))) |
| 741 | return -EFAULT; | ||
| 592 | 742 | ||
| 593 | dev->abs[t] = abs.value; | 743 | /* |
| 594 | dev->absmin[t] = abs.minimum; | 744 | * Take event lock to ensure that we are not |
| 595 | dev->absmax[t] = abs.maximum; | 745 | * changing device parameters in the middle |
| 596 | dev->absfuzz[t] = abs.fuzz; | 746 | * of event. |
| 597 | dev->absflat[t] = abs.flat; | 747 | */ |
| 748 | spin_lock_irq(&dev->event_lock); | ||
| 598 | 749 | ||
| 599 | return 0; | 750 | dev->abs[t] = abs.value; |
| 600 | } | 751 | dev->absmin[t] = abs.minimum; |
| 752 | dev->absmax[t] = abs.maximum; | ||
| 753 | dev->absfuzz[t] = abs.fuzz; | ||
| 754 | dev->absflat[t] = abs.flat; | ||
| 755 | |||
| 756 | spin_unlock_irq(&dev->event_lock); | ||
| 757 | |||
| 758 | return 0; | ||
| 601 | } | 759 | } |
| 760 | } | ||
| 602 | } | 761 | } |
| 603 | return -EINVAL; | 762 | return -EINVAL; |
| 604 | } | 763 | } |
| 605 | 764 | ||
| 765 | static long evdev_ioctl_handler(struct file *file, unsigned int cmd, | ||
| 766 | void __user *p, int compat_mode) | ||
| 767 | { | ||
| 768 | struct evdev_client *client = file->private_data; | ||
| 769 | struct evdev *evdev = client->evdev; | ||
| 770 | int retval; | ||
| 771 | |||
| 772 | retval = mutex_lock_interruptible(&evdev->mutex); | ||
| 773 | if (retval) | ||
| 774 | return retval; | ||
| 775 | |||
| 776 | if (!evdev->exist) { | ||
| 777 | retval = -ENODEV; | ||
| 778 | goto out; | ||
| 779 | } | ||
| 780 | |||
| 781 | retval = evdev_do_ioctl(file, cmd, p, compat_mode); | ||
| 782 | |||
| 783 | out: | ||
| 784 | mutex_unlock(&evdev->mutex); | ||
| 785 | return retval; | ||
| 786 | } | ||
| 787 | |||
| 606 | static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | 788 | static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
| 607 | { | 789 | { |
| 608 | return evdev_ioctl_handler(file, cmd, (void __user *)arg, 0); | 790 | return evdev_ioctl_handler(file, cmd, (void __user *)arg, 0); |
| 609 | } | 791 | } |
| 610 | 792 | ||
| 611 | #ifdef CONFIG_COMPAT | 793 | #ifdef CONFIG_COMPAT |
| 612 | static long evdev_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg) | 794 | static long evdev_ioctl_compat(struct file *file, |
| 795 | unsigned int cmd, unsigned long arg) | ||
| 613 | { | 796 | { |
| 614 | return evdev_ioctl_handler(file, cmd, compat_ptr(arg), 1); | 797 | return evdev_ioctl_handler(file, cmd, compat_ptr(arg), 1); |
| 615 | } | 798 | } |
| 616 | #endif | 799 | #endif |
| 617 | 800 | ||
| 618 | static const struct file_operations evdev_fops = { | 801 | static const struct file_operations evdev_fops = { |
| 619 | .owner = THIS_MODULE, | 802 | .owner = THIS_MODULE, |
| 620 | .read = evdev_read, | 803 | .read = evdev_read, |
| 621 | .write = evdev_write, | 804 | .write = evdev_write, |
| 622 | .poll = evdev_poll, | 805 | .poll = evdev_poll, |
| 623 | .open = evdev_open, | 806 | .open = evdev_open, |
| 624 | .release = evdev_release, | 807 | .release = evdev_release, |
| 625 | .unlocked_ioctl = evdev_ioctl, | 808 | .unlocked_ioctl = evdev_ioctl, |
| 626 | #ifdef CONFIG_COMPAT | 809 | #ifdef CONFIG_COMPAT |
| 627 | .compat_ioctl = evdev_ioctl_compat, | 810 | .compat_ioctl = evdev_ioctl_compat, |
| 628 | #endif | 811 | #endif |
| 629 | .fasync = evdev_fasync, | 812 | .fasync = evdev_fasync, |
| 630 | .flush = evdev_flush | 813 | .flush = evdev_flush |
| 631 | }; | 814 | }; |
| 632 | 815 | ||
| 816 | static int evdev_install_chrdev(struct evdev *evdev) | ||
| 817 | { | ||
| 818 | /* | ||
| 819 | * No need to do any locking here as calls to connect and | ||
| 820 | * disconnect are serialized by the input core | ||
| 821 | */ | ||
| 822 | evdev_table[evdev->minor] = evdev; | ||
| 823 | return 0; | ||
| 824 | } | ||
| 825 | |||
| 826 | static void evdev_remove_chrdev(struct evdev *evdev) | ||
| 827 | { | ||
| 828 | /* | ||
| 829 | * Lock evdev table to prevent race with evdev_open() | ||
| 830 | */ | ||
| 831 | mutex_lock(&evdev_table_mutex); | ||
| 832 | evdev_table[evdev->minor] = NULL; | ||
| 833 | mutex_unlock(&evdev_table_mutex); | ||
| 834 | } | ||
| 835 | |||
| 836 | /* | ||
| 837 | * Mark device non-existent. This disables writes, ioctls and | ||
| 838 | * prevents new users from opening the device. Already posted | ||
| 839 | * blocking reads will stay, however new ones will fail. | ||
| 840 | */ | ||
| 841 | static void evdev_mark_dead(struct evdev *evdev) | ||
| 842 | { | ||
| 843 | mutex_lock(&evdev->mutex); | ||
| 844 | evdev->exist = 0; | ||
| 845 | mutex_unlock(&evdev->mutex); | ||
| 846 | } | ||
| 847 | |||
| 848 | static void evdev_cleanup(struct evdev *evdev) | ||
| 849 | { | ||
| 850 | struct input_handle *handle = &evdev->handle; | ||
| 851 | |||
| 852 | evdev_mark_dead(evdev); | ||
| 853 | evdev_hangup(evdev); | ||
| 854 | evdev_remove_chrdev(evdev); | ||
| 855 | |||
| 856 | /* evdev is marked dead so no one else accesses evdev->open */ | ||
| 857 | if (evdev->open) { | ||
| 858 | input_flush_device(handle, NULL); | ||
| 859 | input_close_device(handle); | ||
| 860 | } | ||
| 861 | } | ||
| 862 | |||
| 863 | /* | ||
| 864 | * Create new evdev device. Note that input core serializes calls | ||
| 865 | * to connect and disconnect so we don't need to lock evdev_table here. | ||
| 866 | */ | ||
| 633 | static int evdev_connect(struct input_handler *handler, struct input_dev *dev, | 867 | static int evdev_connect(struct input_handler *handler, struct input_dev *dev, |
| 634 | const struct input_device_id *id) | 868 | const struct input_device_id *id) |
| 635 | { | 869 | { |
| @@ -637,7 +871,10 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev, | |||
| 637 | int minor; | 871 | int minor; |
| 638 | int error; | 872 | int error; |
| 639 | 873 | ||
| 640 | for (minor = 0; minor < EVDEV_MINORS && evdev_table[minor]; minor++); | 874 | for (minor = 0; minor < EVDEV_MINORS; minor++) |
| 875 | if (!evdev_table[minor]) | ||
| 876 | break; | ||
| 877 | |||
| 641 | if (minor == EVDEV_MINORS) { | 878 | if (minor == EVDEV_MINORS) { |
| 642 | printk(KERN_ERR "evdev: no more free evdev devices\n"); | 879 | printk(KERN_ERR "evdev: no more free evdev devices\n"); |
| 643 | return -ENFILE; | 880 | return -ENFILE; |
| @@ -648,38 +885,44 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev, | |||
| 648 | return -ENOMEM; | 885 | return -ENOMEM; |
| 649 | 886 | ||
| 650 | INIT_LIST_HEAD(&evdev->client_list); | 887 | INIT_LIST_HEAD(&evdev->client_list); |
| 888 | spin_lock_init(&evdev->client_lock); | ||
| 889 | mutex_init(&evdev->mutex); | ||
| 651 | init_waitqueue_head(&evdev->wait); | 890 | init_waitqueue_head(&evdev->wait); |
| 652 | 891 | ||
| 892 | snprintf(evdev->name, sizeof(evdev->name), "event%d", minor); | ||
| 653 | evdev->exist = 1; | 893 | evdev->exist = 1; |
| 654 | evdev->minor = minor; | 894 | evdev->minor = minor; |
| 895 | |||
| 655 | evdev->handle.dev = dev; | 896 | evdev->handle.dev = dev; |
| 656 | evdev->handle.name = evdev->name; | 897 | evdev->handle.name = evdev->name; |
| 657 | evdev->handle.handler = handler; | 898 | evdev->handle.handler = handler; |
| 658 | evdev->handle.private = evdev; | 899 | evdev->handle.private = evdev; |
| 659 | snprintf(evdev->name, sizeof(evdev->name), "event%d", minor); | ||
| 660 | 900 | ||
| 661 | snprintf(evdev->dev.bus_id, sizeof(evdev->dev.bus_id), | 901 | strlcpy(evdev->dev.bus_id, evdev->name, sizeof(evdev->dev.bus_id)); |
| 662 | "event%d", minor); | 902 | evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor); |
| 663 | evdev->dev.class = &input_class; | 903 | evdev->dev.class = &input_class; |
| 664 | evdev->dev.parent = &dev->dev; | 904 | evdev->dev.parent = &dev->dev; |
| 665 | evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor); | ||
| 666 | evdev->dev.release = evdev_free; | 905 | evdev->dev.release = evdev_free; |
| 667 | device_initialize(&evdev->dev); | 906 | device_initialize(&evdev->dev); |
| 668 | 907 | ||
| 669 | evdev_table[minor] = evdev; | 908 | error = input_register_handle(&evdev->handle); |
| 670 | |||
| 671 | error = device_add(&evdev->dev); | ||
| 672 | if (error) | 909 | if (error) |
| 673 | goto err_free_evdev; | 910 | goto err_free_evdev; |
| 674 | 911 | ||
| 675 | error = input_register_handle(&evdev->handle); | 912 | error = evdev_install_chrdev(evdev); |
| 913 | if (error) | ||
| 914 | goto err_unregister_handle; | ||
| 915 | |||
| 916 | error = device_add(&evdev->dev); | ||
| 676 | if (error) | 917 | if (error) |
| 677 | goto err_delete_evdev; | 918 | goto err_cleanup_evdev; |
| 678 | 919 | ||
| 679 | return 0; | 920 | return 0; |
| 680 | 921 | ||
| 681 | err_delete_evdev: | 922 | err_cleanup_evdev: |
| 682 | device_del(&evdev->dev); | 923 | evdev_cleanup(evdev); |
| 924 | err_unregister_handle: | ||
| 925 | input_unregister_handle(&evdev->handle); | ||
| 683 | err_free_evdev: | 926 | err_free_evdev: |
| 684 | put_device(&evdev->dev); | 927 | put_device(&evdev->dev); |
| 685 | return error; | 928 | return error; |
| @@ -688,21 +931,10 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev, | |||
| 688 | static void evdev_disconnect(struct input_handle *handle) | 931 | static void evdev_disconnect(struct input_handle *handle) |
| 689 | { | 932 | { |
| 690 | struct evdev *evdev = handle->private; | 933 | struct evdev *evdev = handle->private; |
| 691 | struct evdev_client *client; | ||
| 692 | 934 | ||
| 693 | input_unregister_handle(handle); | ||
| 694 | device_del(&evdev->dev); | 935 | device_del(&evdev->dev); |
| 695 | 936 | evdev_cleanup(evdev); | |
| 696 | evdev->exist = 0; | 937 | input_unregister_handle(handle); |
| 697 | |||
| 698 | if (evdev->open) { | ||
| 699 | input_flush_device(handle, NULL); | ||
| 700 | input_close_device(handle); | ||
| 701 | list_for_each_entry(client, &evdev->client_list, node) | ||
| 702 | kill_fasync(&client->fasync, SIGIO, POLL_HUP); | ||
| 703 | wake_up_interruptible(&evdev->wait); | ||
| 704 | } | ||
| 705 | |||
| 706 | put_device(&evdev->dev); | 938 | put_device(&evdev->dev); |
| 707 | } | 939 | } |
| 708 | 940 | ||
| @@ -714,13 +946,13 @@ static const struct input_device_id evdev_ids[] = { | |||
| 714 | MODULE_DEVICE_TABLE(input, evdev_ids); | 946 | MODULE_DEVICE_TABLE(input, evdev_ids); |
| 715 | 947 | ||
| 716 | static struct input_handler evdev_handler = { | 948 | static struct input_handler evdev_handler = { |
| 717 | .event = evdev_event, | 949 | .event = evdev_event, |
| 718 | .connect = evdev_connect, | 950 | .connect = evdev_connect, |
| 719 | .disconnect = evdev_disconnect, | 951 | .disconnect = evdev_disconnect, |
| 720 | .fops = &evdev_fops, | 952 | .fops = &evdev_fops, |
| 721 | .minor = EVDEV_MINOR_BASE, | 953 | .minor = EVDEV_MINOR_BASE, |
| 722 | .name = "evdev", | 954 | .name = "evdev", |
| 723 | .id_table = evdev_ids, | 955 | .id_table = evdev_ids, |
| 724 | }; | 956 | }; |
| 725 | 957 | ||
| 726 | static int __init evdev_init(void) | 958 | static int __init evdev_init(void) |
diff --git a/drivers/input/input-polldev.c b/drivers/input/input-polldev.c index b773d4c756a6..92b359894e81 100644 --- a/drivers/input/input-polldev.c +++ b/drivers/input/input-polldev.c | |||
| @@ -70,6 +70,7 @@ static int input_open_polled_device(struct input_dev *input) | |||
| 70 | { | 70 | { |
| 71 | struct input_polled_dev *dev = input->private; | 71 | struct input_polled_dev *dev = input->private; |
| 72 | int error; | 72 | int error; |
| 73 | unsigned long ticks; | ||
| 73 | 74 | ||
| 74 | error = input_polldev_start_workqueue(); | 75 | error = input_polldev_start_workqueue(); |
| 75 | if (error) | 76 | if (error) |
| @@ -78,8 +79,10 @@ static int input_open_polled_device(struct input_dev *input) | |||
| 78 | if (dev->flush) | 79 | if (dev->flush) |
| 79 | dev->flush(dev); | 80 | dev->flush(dev); |
| 80 | 81 | ||
| 81 | queue_delayed_work(polldev_wq, &dev->work, | 82 | ticks = msecs_to_jiffies(dev->poll_interval); |
| 82 | msecs_to_jiffies(dev->poll_interval)); | 83 | if (ticks >= HZ) |
| 84 | ticks = round_jiffies(ticks); | ||
| 85 | queue_delayed_work(polldev_wq, &dev->work, ticks); | ||
| 83 | 86 | ||
| 84 | return 0; | 87 | return 0; |
| 85 | } | 88 | } |
diff --git a/drivers/input/input.c b/drivers/input/input.c index 5dc361c954e2..2f2b020cd629 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c | |||
| @@ -17,10 +17,10 @@ | |||
| 17 | #include <linux/major.h> | 17 | #include <linux/major.h> |
| 18 | #include <linux/proc_fs.h> | 18 | #include <linux/proc_fs.h> |
| 19 | #include <linux/seq_file.h> | 19 | #include <linux/seq_file.h> |
| 20 | #include <linux/interrupt.h> | ||
| 21 | #include <linux/poll.h> | 20 | #include <linux/poll.h> |
| 22 | #include <linux/device.h> | 21 | #include <linux/device.h> |
| 23 | #include <linux/mutex.h> | 22 | #include <linux/mutex.h> |
| 23 | #include <linux/rcupdate.h> | ||
| 24 | 24 | ||
| 25 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>"); | 25 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>"); |
| 26 | MODULE_DESCRIPTION("Input core"); | 26 | MODULE_DESCRIPTION("Input core"); |
| @@ -31,167 +31,245 @@ MODULE_LICENSE("GPL"); | |||
| 31 | static LIST_HEAD(input_dev_list); | 31 | static LIST_HEAD(input_dev_list); |
| 32 | static LIST_HEAD(input_handler_list); | 32 | static LIST_HEAD(input_handler_list); |
| 33 | 33 | ||
| 34 | /* | ||
| 35 | * input_mutex protects access to both input_dev_list and input_handler_list. | ||
| 36 | * This also causes input_[un]register_device and input_[un]register_handler | ||
| 37 | * be mutually exclusive which simplifies locking in drivers implementing | ||
| 38 | * input handlers. | ||
| 39 | */ | ||
| 40 | static DEFINE_MUTEX(input_mutex); | ||
| 41 | |||
| 34 | static struct input_handler *input_table[8]; | 42 | static struct input_handler *input_table[8]; |
| 35 | 43 | ||
| 36 | /** | 44 | static inline int is_event_supported(unsigned int code, |
| 37 | * input_event() - report new input event | 45 | unsigned long *bm, unsigned int max) |
| 38 | * @dev: device that generated the event | ||
| 39 | * @type: type of the event | ||
| 40 | * @code: event code | ||
| 41 | * @value: value of the event | ||
| 42 | * | ||
| 43 | * This function should be used by drivers implementing various input devices | ||
| 44 | * See also input_inject_event() | ||
| 45 | */ | ||
| 46 | void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) | ||
| 47 | { | 46 | { |
| 48 | struct input_handle *handle; | 47 | return code <= max && test_bit(code, bm); |
| 48 | } | ||
| 49 | 49 | ||
| 50 | if (type > EV_MAX || !test_bit(type, dev->evbit)) | 50 | static int input_defuzz_abs_event(int value, int old_val, int fuzz) |
| 51 | return; | 51 | { |
| 52 | if (fuzz) { | ||
| 53 | if (value > old_val - fuzz / 2 && value < old_val + fuzz / 2) | ||
| 54 | return old_val; | ||
| 52 | 55 | ||
| 53 | add_input_randomness(type, code, value); | 56 | if (value > old_val - fuzz && value < old_val + fuzz) |
| 57 | return (old_val * 3 + value) / 4; | ||
| 54 | 58 | ||
| 55 | switch (type) { | 59 | if (value > old_val - fuzz * 2 && value < old_val + fuzz * 2) |
| 56 | 60 | return (old_val + value) / 2; | |
| 57 | case EV_SYN: | 61 | } |
| 58 | switch (code) { | ||
| 59 | case SYN_CONFIG: | ||
| 60 | if (dev->event) | ||
| 61 | dev->event(dev, type, code, value); | ||
| 62 | break; | ||
| 63 | |||
| 64 | case SYN_REPORT: | ||
| 65 | if (dev->sync) | ||
| 66 | return; | ||
| 67 | dev->sync = 1; | ||
| 68 | break; | ||
| 69 | } | ||
| 70 | break; | ||
| 71 | 62 | ||
| 72 | case EV_KEY: | 63 | return value; |
| 64 | } | ||
| 73 | 65 | ||
| 74 | if (code > KEY_MAX || !test_bit(code, dev->keybit) || !!test_bit(code, dev->key) == value) | 66 | /* |
| 75 | return; | 67 | * Pass event through all open handles. This function is called with |
| 68 | * dev->event_lock held and interrupts disabled. | ||
| 69 | */ | ||
| 70 | static void input_pass_event(struct input_dev *dev, | ||
| 71 | unsigned int type, unsigned int code, int value) | ||
| 72 | { | ||
| 73 | struct input_handle *handle; | ||
| 76 | 74 | ||
| 77 | if (value == 2) | 75 | rcu_read_lock(); |
| 78 | break; | ||
| 79 | 76 | ||
| 80 | change_bit(code, dev->key); | 77 | handle = rcu_dereference(dev->grab); |
| 78 | if (handle) | ||
| 79 | handle->handler->event(handle, type, code, value); | ||
| 80 | else | ||
| 81 | list_for_each_entry_rcu(handle, &dev->h_list, d_node) | ||
| 82 | if (handle->open) | ||
| 83 | handle->handler->event(handle, | ||
| 84 | type, code, value); | ||
| 85 | rcu_read_unlock(); | ||
| 86 | } | ||
| 81 | 87 | ||
| 82 | if (test_bit(EV_REP, dev->evbit) && dev->rep[REP_PERIOD] && dev->rep[REP_DELAY] && dev->timer.data && value) { | 88 | /* |
| 83 | dev->repeat_key = code; | 89 | * Generate software autorepeat event. Note that we take |
| 84 | mod_timer(&dev->timer, jiffies + msecs_to_jiffies(dev->rep[REP_DELAY])); | 90 | * dev->event_lock here to avoid racing with input_event |
| 85 | } | 91 | * which may cause keys get "stuck". |
| 92 | */ | ||
| 93 | static void input_repeat_key(unsigned long data) | ||
| 94 | { | ||
| 95 | struct input_dev *dev = (void *) data; | ||
| 96 | unsigned long flags; | ||
| 86 | 97 | ||
| 87 | break; | 98 | spin_lock_irqsave(&dev->event_lock, flags); |
| 88 | 99 | ||
| 89 | case EV_SW: | 100 | if (test_bit(dev->repeat_key, dev->key) && |
| 101 | is_event_supported(dev->repeat_key, dev->keybit, KEY_MAX)) { | ||
| 90 | 102 | ||
| 91 | if (code > SW_MAX || !test_bit(code, dev->swbit) || !!test_bit(code, dev->sw) == value) | 103 | input_pass_event(dev, EV_KEY, dev->repeat_key, 2); |
| 92 | return; | ||
| 93 | 104 | ||
| 94 | change_bit(code, dev->sw); | 105 | if (dev->sync) { |
| 106 | /* | ||
| 107 | * Only send SYN_REPORT if we are not in a middle | ||
| 108 | * of driver parsing a new hardware packet. | ||
| 109 | * Otherwise assume that the driver will send | ||
| 110 | * SYN_REPORT once it's done. | ||
| 111 | */ | ||
| 112 | input_pass_event(dev, EV_SYN, SYN_REPORT, 1); | ||
| 113 | } | ||
| 95 | 114 | ||
| 96 | break; | 115 | if (dev->rep[REP_PERIOD]) |
| 116 | mod_timer(&dev->timer, jiffies + | ||
| 117 | msecs_to_jiffies(dev->rep[REP_PERIOD])); | ||
| 118 | } | ||
| 97 | 119 | ||
| 98 | case EV_ABS: | 120 | spin_unlock_irqrestore(&dev->event_lock, flags); |
| 121 | } | ||
| 99 | 122 | ||
| 100 | if (code > ABS_MAX || !test_bit(code, dev->absbit)) | 123 | static void input_start_autorepeat(struct input_dev *dev, int code) |
| 101 | return; | 124 | { |
| 125 | if (test_bit(EV_REP, dev->evbit) && | ||
| 126 | dev->rep[REP_PERIOD] && dev->rep[REP_DELAY] && | ||
| 127 | dev->timer.data) { | ||
| 128 | dev->repeat_key = code; | ||
| 129 | mod_timer(&dev->timer, | ||
| 130 | jiffies + msecs_to_jiffies(dev->rep[REP_DELAY])); | ||
| 131 | } | ||
| 132 | } | ||
| 102 | 133 | ||
| 103 | if (dev->absfuzz[code]) { | 134 | #define INPUT_IGNORE_EVENT 0 |
| 104 | if ((value > dev->abs[code] - (dev->absfuzz[code] >> 1)) && | 135 | #define INPUT_PASS_TO_HANDLERS 1 |
| 105 | (value < dev->abs[code] + (dev->absfuzz[code] >> 1))) | 136 | #define INPUT_PASS_TO_DEVICE 2 |
| 106 | return; | 137 | #define INPUT_PASS_TO_ALL (INPUT_PASS_TO_HANDLERS | INPUT_PASS_TO_DEVICE) |
| 107 | 138 | ||
| 108 | if ((value > dev->abs[code] - dev->absfuzz[code]) && | 139 | static void input_handle_event(struct input_dev *dev, |
| 109 | (value < dev->abs[code] + dev->absfuzz[code])) | 140 | unsigned int type, unsigned int code, int value) |
| 110 | value = (dev->abs[code] * 3 + value) >> 2; | 141 | { |
| 142 | int disposition = INPUT_IGNORE_EVENT; | ||
| 111 | 143 | ||
| 112 | if ((value > dev->abs[code] - (dev->absfuzz[code] << 1)) && | 144 | switch (type) { |
| 113 | (value < dev->abs[code] + (dev->absfuzz[code] << 1))) | ||
| 114 | value = (dev->abs[code] + value) >> 1; | ||
| 115 | } | ||
| 116 | 145 | ||
| 117 | if (dev->abs[code] == value) | 146 | case EV_SYN: |
| 118 | return; | 147 | switch (code) { |
| 148 | case SYN_CONFIG: | ||
| 149 | disposition = INPUT_PASS_TO_ALL; | ||
| 150 | break; | ||
| 119 | 151 | ||
| 120 | dev->abs[code] = value; | 152 | case SYN_REPORT: |
| 153 | if (!dev->sync) { | ||
| 154 | dev->sync = 1; | ||
| 155 | disposition = INPUT_PASS_TO_HANDLERS; | ||
| 156 | } | ||
| 121 | break; | 157 | break; |
| 158 | } | ||
| 159 | break; | ||
| 122 | 160 | ||
| 123 | case EV_REL: | 161 | case EV_KEY: |
| 162 | if (is_event_supported(code, dev->keybit, KEY_MAX) && | ||
| 163 | !!test_bit(code, dev->key) != value) { | ||
| 124 | 164 | ||
| 125 | if (code > REL_MAX || !test_bit(code, dev->relbit) || (value == 0)) | 165 | if (value != 2) { |
| 126 | return; | 166 | __change_bit(code, dev->key); |
| 167 | if (value) | ||
| 168 | input_start_autorepeat(dev, code); | ||
| 169 | } | ||
| 127 | 170 | ||
| 128 | break; | 171 | disposition = INPUT_PASS_TO_HANDLERS; |
| 172 | } | ||
| 173 | break; | ||
| 129 | 174 | ||
| 130 | case EV_MSC: | 175 | case EV_SW: |
| 176 | if (is_event_supported(code, dev->swbit, SW_MAX) && | ||
| 177 | !!test_bit(code, dev->sw) != value) { | ||
| 131 | 178 | ||
| 132 | if (code > MSC_MAX || !test_bit(code, dev->mscbit)) | 179 | __change_bit(code, dev->sw); |
| 133 | return; | 180 | disposition = INPUT_PASS_TO_HANDLERS; |
| 181 | } | ||
| 182 | break; | ||
| 134 | 183 | ||
| 135 | if (dev->event) | 184 | case EV_ABS: |
| 136 | dev->event(dev, type, code, value); | 185 | if (is_event_supported(code, dev->absbit, ABS_MAX)) { |
| 137 | 186 | ||
| 138 | break; | 187 | value = input_defuzz_abs_event(value, |
| 188 | dev->abs[code], dev->absfuzz[code]); | ||
| 189 | |||
| 190 | if (dev->abs[code] != value) { | ||
| 191 | dev->abs[code] = value; | ||
| 192 | disposition = INPUT_PASS_TO_HANDLERS; | ||
| 193 | } | ||
| 194 | } | ||
| 195 | break; | ||
| 139 | 196 | ||
| 140 | case EV_LED: | 197 | case EV_REL: |
| 198 | if (is_event_supported(code, dev->relbit, REL_MAX) && value) | ||
| 199 | disposition = INPUT_PASS_TO_HANDLERS; | ||
| 141 | 200 | ||
| 142 | if (code > LED_MAX || !test_bit(code, dev->ledbit) || !!test_bit(code, dev->led) == value) | 201 | break; |
| 143 | return; | ||
| 144 | 202 | ||
| 145 | change_bit(code, dev->led); | 203 | case EV_MSC: |
| 204 | if (is_event_supported(code, dev->mscbit, MSC_MAX)) | ||
| 205 | disposition = INPUT_PASS_TO_ALL; | ||
| 146 | 206 | ||
| 147 | if (dev->event) | 207 | break; |
| 148 | dev->event(dev, type, code, value); | ||
| 149 | 208 | ||
| 150 | break; | 209 | case EV_LED: |
| 210 | if (is_event_supported(code, dev->ledbit, LED_MAX) && | ||
| 211 | !!test_bit(code, dev->led) != value) { | ||
| 151 | 212 | ||
| 152 | case EV_SND: | 213 | __change_bit(code, dev->led); |
| 214 | disposition = INPUT_PASS_TO_ALL; | ||
| 215 | } | ||
| 216 | break; | ||
| 153 | 217 | ||
| 154 | if (code > SND_MAX || !test_bit(code, dev->sndbit)) | 218 | case EV_SND: |
| 155 | return; | 219 | if (is_event_supported(code, dev->sndbit, SND_MAX)) { |
| 156 | 220 | ||
| 157 | if (!!test_bit(code, dev->snd) != !!value) | 221 | if (!!test_bit(code, dev->snd) != !!value) |
| 158 | change_bit(code, dev->snd); | 222 | __change_bit(code, dev->snd); |
| 223 | disposition = INPUT_PASS_TO_ALL; | ||
| 224 | } | ||
| 225 | break; | ||
| 159 | 226 | ||
| 160 | if (dev->event) | 227 | case EV_REP: |
| 161 | dev->event(dev, type, code, value); | 228 | if (code <= REP_MAX && value >= 0 && dev->rep[code] != value) { |
| 229 | dev->rep[code] = value; | ||
| 230 | disposition = INPUT_PASS_TO_ALL; | ||
| 231 | } | ||
| 232 | break; | ||
| 162 | 233 | ||
| 163 | break; | 234 | case EV_FF: |
| 235 | if (value >= 0) | ||
| 236 | disposition = INPUT_PASS_TO_ALL; | ||
| 237 | break; | ||
| 238 | } | ||
| 164 | 239 | ||
| 165 | case EV_REP: | 240 | if (type != EV_SYN) |
| 241 | dev->sync = 0; | ||
| 166 | 242 | ||
| 167 | if (code > REP_MAX || value < 0 || dev->rep[code] == value) | 243 | if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event) |
| 168 | return; | 244 | dev->event(dev, type, code, value); |
| 169 | 245 | ||
| 170 | dev->rep[code] = value; | 246 | if (disposition & INPUT_PASS_TO_HANDLERS) |
| 171 | if (dev->event) | 247 | input_pass_event(dev, type, code, value); |
| 172 | dev->event(dev, type, code, value); | 248 | } |
| 173 | 249 | ||
| 174 | break; | 250 | /** |
| 251 | * input_event() - report new input event | ||
| 252 | * @dev: device that generated the event | ||
| 253 | * @type: type of the event | ||
| 254 | * @code: event code | ||
| 255 | * @value: value of the event | ||
| 256 | * | ||
| 257 | * This function should be used by drivers implementing various input | ||
| 258 | * devices. See also input_inject_event(). | ||
| 259 | */ | ||
| 175 | 260 | ||
| 176 | case EV_FF: | 261 | void input_event(struct input_dev *dev, |
| 262 | unsigned int type, unsigned int code, int value) | ||
| 263 | { | ||
| 264 | unsigned long flags; | ||
| 177 | 265 | ||
| 178 | if (value < 0) | 266 | if (is_event_supported(type, dev->evbit, EV_MAX)) { |
| 179 | return; | ||
| 180 | 267 | ||
| 181 | if (dev->event) | 268 | spin_lock_irqsave(&dev->event_lock, flags); |
| 182 | dev->event(dev, type, code, value); | 269 | add_input_randomness(type, code, value); |
| 183 | break; | 270 | input_handle_event(dev, type, code, value); |
| 271 | spin_unlock_irqrestore(&dev->event_lock, flags); | ||
| 184 | } | 272 | } |
| 185 | |||
| 186 | if (type != EV_SYN) | ||
| 187 | dev->sync = 0; | ||
| 188 | |||
| 189 | if (dev->grab) | ||
| 190 | dev->grab->handler->event(dev->grab, type, code, value); | ||
| 191 | else | ||
| 192 | list_for_each_entry(handle, &dev->h_list, d_node) | ||
| 193 | if (handle->open) | ||
| 194 | handle->handler->event(handle, type, code, value); | ||
| 195 | } | 273 | } |
| 196 | EXPORT_SYMBOL(input_event); | 274 | EXPORT_SYMBOL(input_event); |
| 197 | 275 | ||
| @@ -202,102 +280,228 @@ EXPORT_SYMBOL(input_event); | |||
| 202 | * @code: event code | 280 | * @code: event code |
| 203 | * @value: value of the event | 281 | * @value: value of the event |
| 204 | * | 282 | * |
| 205 | * Similar to input_event() but will ignore event if device is "grabbed" and handle | 283 | * Similar to input_event() but will ignore event if device is |
| 206 | * injecting event is not the one that owns the device. | 284 | * "grabbed" and handle injecting event is not the one that owns |
| 285 | * the device. | ||
| 207 | */ | 286 | */ |
| 208 | void input_inject_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) | 287 | void input_inject_event(struct input_handle *handle, |
| 209 | { | 288 | unsigned int type, unsigned int code, int value) |
| 210 | if (!handle->dev->grab || handle->dev->grab == handle) | ||
| 211 | input_event(handle->dev, type, code, value); | ||
| 212 | } | ||
| 213 | EXPORT_SYMBOL(input_inject_event); | ||
| 214 | |||
| 215 | static void input_repeat_key(unsigned long data) | ||
| 216 | { | 289 | { |
| 217 | struct input_dev *dev = (void *) data; | 290 | struct input_dev *dev = handle->dev; |
| 291 | struct input_handle *grab; | ||
| 292 | unsigned long flags; | ||
| 218 | 293 | ||
| 219 | if (!test_bit(dev->repeat_key, dev->key)) | 294 | if (is_event_supported(type, dev->evbit, EV_MAX)) { |
| 220 | return; | 295 | spin_lock_irqsave(&dev->event_lock, flags); |
| 221 | 296 | ||
| 222 | input_event(dev, EV_KEY, dev->repeat_key, 2); | 297 | rcu_read_lock(); |
| 223 | input_sync(dev); | 298 | grab = rcu_dereference(dev->grab); |
| 299 | if (!grab || grab == handle) | ||
| 300 | input_handle_event(dev, type, code, value); | ||
| 301 | rcu_read_unlock(); | ||
| 224 | 302 | ||
| 225 | if (dev->rep[REP_PERIOD]) | 303 | spin_unlock_irqrestore(&dev->event_lock, flags); |
| 226 | mod_timer(&dev->timer, jiffies + msecs_to_jiffies(dev->rep[REP_PERIOD])); | 304 | } |
| 227 | } | 305 | } |
| 306 | EXPORT_SYMBOL(input_inject_event); | ||
| 228 | 307 | ||
| 308 | /** | ||
| 309 | * input_grab_device - grabs device for exclusive use | ||
| 310 | * @handle: input handle that wants to own the device | ||
| 311 | * | ||
| 312 | * When a device is grabbed by an input handle all events generated by | ||
| 313 | * the device are delivered only to this handle. Also events injected | ||
| 314 | * by other input handles are ignored while device is grabbed. | ||
| 315 | */ | ||
| 229 | int input_grab_device(struct input_handle *handle) | 316 | int input_grab_device(struct input_handle *handle) |
| 230 | { | 317 | { |
| 231 | if (handle->dev->grab) | 318 | struct input_dev *dev = handle->dev; |
| 232 | return -EBUSY; | 319 | int retval; |
| 233 | 320 | ||
| 234 | handle->dev->grab = handle; | 321 | retval = mutex_lock_interruptible(&dev->mutex); |
| 235 | return 0; | 322 | if (retval) |
| 323 | return retval; | ||
| 324 | |||
| 325 | if (dev->grab) { | ||
| 326 | retval = -EBUSY; | ||
| 327 | goto out; | ||
| 328 | } | ||
| 329 | |||
| 330 | rcu_assign_pointer(dev->grab, handle); | ||
| 331 | synchronize_rcu(); | ||
| 332 | |||
| 333 | out: | ||
| 334 | mutex_unlock(&dev->mutex); | ||
| 335 | return retval; | ||
| 236 | } | 336 | } |
| 237 | EXPORT_SYMBOL(input_grab_device); | 337 | EXPORT_SYMBOL(input_grab_device); |
| 238 | 338 | ||
| 239 | void input_release_device(struct input_handle *handle) | 339 | static void __input_release_device(struct input_handle *handle) |
| 240 | { | 340 | { |
| 241 | struct input_dev *dev = handle->dev; | 341 | struct input_dev *dev = handle->dev; |
| 242 | 342 | ||
| 243 | if (dev->grab == handle) { | 343 | if (dev->grab == handle) { |
| 244 | dev->grab = NULL; | 344 | rcu_assign_pointer(dev->grab, NULL); |
| 345 | /* Make sure input_pass_event() notices that grab is gone */ | ||
| 346 | synchronize_rcu(); | ||
| 245 | 347 | ||
| 246 | list_for_each_entry(handle, &dev->h_list, d_node) | 348 | list_for_each_entry(handle, &dev->h_list, d_node) |
| 247 | if (handle->handler->start) | 349 | if (handle->open && handle->handler->start) |
| 248 | handle->handler->start(handle); | 350 | handle->handler->start(handle); |
| 249 | } | 351 | } |
| 250 | } | 352 | } |
| 353 | |||
| 354 | /** | ||
| 355 | * input_release_device - release previously grabbed device | ||
| 356 | * @handle: input handle that owns the device | ||
| 357 | * | ||
| 358 | * Releases previously grabbed device so that other input handles can | ||
| 359 | * start receiving input events. Upon release all handlers attached | ||
| 360 | * to the device have their start() method called so they have a change | ||
| 361 | * to synchronize device state with the rest of the system. | ||
| 362 | */ | ||
| 363 | void input_release_device(struct input_handle *handle) | ||
| 364 | { | ||
| 365 | struct input_dev *dev = handle->dev; | ||
| 366 | |||
| 367 | mutex_lock(&dev->mutex); | ||
| 368 | __input_release_device(handle); | ||
| 369 | mutex_unlock(&dev->mutex); | ||
| 370 | } | ||
| 251 | EXPORT_SYMBOL(input_release_device); | 371 | EXPORT_SYMBOL(input_release_device); |
| 252 | 372 | ||
| 373 | /** | ||
| 374 | * input_open_device - open input device | ||
| 375 | * @handle: handle through which device is being accessed | ||
| 376 | * | ||
| 377 | * This function should be called by input handlers when they | ||
| 378 | * want to start receive events from given input device. | ||
| 379 | */ | ||
| 253 | int input_open_device(struct input_handle *handle) | 380 | int input_open_device(struct input_handle *handle) |
| 254 | { | 381 | { |
| 255 | struct input_dev *dev = handle->dev; | 382 | struct input_dev *dev = handle->dev; |
| 256 | int err; | 383 | int retval; |
| 257 | 384 | ||
| 258 | err = mutex_lock_interruptible(&dev->mutex); | 385 | retval = mutex_lock_interruptible(&dev->mutex); |
| 259 | if (err) | 386 | if (retval) |
| 260 | return err; | 387 | return retval; |
| 388 | |||
| 389 | if (dev->going_away) { | ||
| 390 | retval = -ENODEV; | ||
| 391 | goto out; | ||
| 392 | } | ||
| 261 | 393 | ||
| 262 | handle->open++; | 394 | handle->open++; |
| 263 | 395 | ||
| 264 | if (!dev->users++ && dev->open) | 396 | if (!dev->users++ && dev->open) |
| 265 | err = dev->open(dev); | 397 | retval = dev->open(dev); |
| 266 | 398 | ||
| 267 | if (err) | 399 | if (retval) { |
| 268 | handle->open--; | 400 | dev->users--; |
| 401 | if (!--handle->open) { | ||
| 402 | /* | ||
| 403 | * Make sure we are not delivering any more events | ||
| 404 | * through this handle | ||
| 405 | */ | ||
| 406 | synchronize_rcu(); | ||
| 407 | } | ||
| 408 | } | ||
| 269 | 409 | ||
| 410 | out: | ||
| 270 | mutex_unlock(&dev->mutex); | 411 | mutex_unlock(&dev->mutex); |
| 271 | 412 | return retval; | |
| 272 | return err; | ||
| 273 | } | 413 | } |
| 274 | EXPORT_SYMBOL(input_open_device); | 414 | EXPORT_SYMBOL(input_open_device); |
| 275 | 415 | ||
| 276 | int input_flush_device(struct input_handle* handle, struct file* file) | 416 | int input_flush_device(struct input_handle *handle, struct file *file) |
| 277 | { | 417 | { |
| 278 | if (handle->dev->flush) | 418 | struct input_dev *dev = handle->dev; |
| 279 | return handle->dev->flush(handle->dev, file); | 419 | int retval; |
| 280 | 420 | ||
| 281 | return 0; | 421 | retval = mutex_lock_interruptible(&dev->mutex); |
| 422 | if (retval) | ||
| 423 | return retval; | ||
| 424 | |||
| 425 | if (dev->flush) | ||
| 426 | retval = dev->flush(dev, file); | ||
| 427 | |||
| 428 | mutex_unlock(&dev->mutex); | ||
| 429 | return retval; | ||
| 282 | } | 430 | } |
| 283 | EXPORT_SYMBOL(input_flush_device); | 431 | EXPORT_SYMBOL(input_flush_device); |
| 284 | 432 | ||
| 433 | /** | ||
| 434 | * input_close_device - close input device | ||
| 435 | * @handle: handle through which device is being accessed | ||
| 436 | * | ||
| 437 | * This function should be called by input handlers when they | ||
| 438 | * want to stop receive events from given input device. | ||
| 439 | */ | ||
| 285 | void input_close_device(struct input_handle *handle) | 440 | void input_close_device(struct input_handle *handle) |
| 286 | { | 441 | { |
| 287 | struct input_dev *dev = handle->dev; | 442 | struct input_dev *dev = handle->dev; |
| 288 | 443 | ||
| 289 | input_release_device(handle); | ||
| 290 | |||
| 291 | mutex_lock(&dev->mutex); | 444 | mutex_lock(&dev->mutex); |
| 292 | 445 | ||
| 446 | __input_release_device(handle); | ||
| 447 | |||
| 293 | if (!--dev->users && dev->close) | 448 | if (!--dev->users && dev->close) |
| 294 | dev->close(dev); | 449 | dev->close(dev); |
| 295 | handle->open--; | 450 | |
| 451 | if (!--handle->open) { | ||
| 452 | /* | ||
| 453 | * synchronize_rcu() makes sure that input_pass_event() | ||
| 454 | * completed and that no more input events are delivered | ||
| 455 | * through this handle | ||
| 456 | */ | ||
| 457 | synchronize_rcu(); | ||
| 458 | } | ||
| 296 | 459 | ||
| 297 | mutex_unlock(&dev->mutex); | 460 | mutex_unlock(&dev->mutex); |
| 298 | } | 461 | } |
| 299 | EXPORT_SYMBOL(input_close_device); | 462 | EXPORT_SYMBOL(input_close_device); |
| 300 | 463 | ||
| 464 | /* | ||
| 465 | * Prepare device for unregistering | ||
| 466 | */ | ||
| 467 | static void input_disconnect_device(struct input_dev *dev) | ||
| 468 | { | ||
| 469 | struct input_handle *handle; | ||
| 470 | int code; | ||
| 471 | |||
| 472 | /* | ||
| 473 | * Mark device as going away. Note that we take dev->mutex here | ||
| 474 | * not to protect access to dev->going_away but rather to ensure | ||
| 475 | * that there are no threads in the middle of input_open_device() | ||
| 476 | */ | ||
| 477 | mutex_lock(&dev->mutex); | ||
| 478 | dev->going_away = 1; | ||
| 479 | mutex_unlock(&dev->mutex); | ||
| 480 | |||
| 481 | spin_lock_irq(&dev->event_lock); | ||
| 482 | |||
| 483 | /* | ||
| 484 | * Simulate keyup events for all pressed keys so that handlers | ||
| 485 | * are not left with "stuck" keys. The driver may continue | ||
| 486 | * generate events even after we done here but they will not | ||
| 487 | * reach any handlers. | ||
| 488 | */ | ||
| 489 | if (is_event_supported(EV_KEY, dev->evbit, EV_MAX)) { | ||
| 490 | for (code = 0; code <= KEY_MAX; code++) { | ||
| 491 | if (is_event_supported(code, dev->keybit, KEY_MAX) && | ||
| 492 | test_bit(code, dev->key)) { | ||
| 493 | input_pass_event(dev, EV_KEY, code, 0); | ||
| 494 | } | ||
| 495 | } | ||
| 496 | input_pass_event(dev, EV_SYN, SYN_REPORT, 1); | ||
| 497 | } | ||
| 498 | |||
| 499 | list_for_each_entry(handle, &dev->h_list, d_node) | ||
| 500 | handle->open = 0; | ||
| 501 | |||
| 502 | spin_unlock_irq(&dev->event_lock); | ||
| 503 | } | ||
| 504 | |||
| 301 | static int input_fetch_keycode(struct input_dev *dev, int scancode) | 505 | static int input_fetch_keycode(struct input_dev *dev, int scancode) |
| 302 | { | 506 | { |
| 303 | switch (dev->keycodesize) { | 507 | switch (dev->keycodesize) { |
| @@ -473,7 +677,8 @@ static unsigned int input_proc_devices_poll(struct file *file, poll_table *wait) | |||
| 473 | 677 | ||
| 474 | static void *input_devices_seq_start(struct seq_file *seq, loff_t *pos) | 678 | static void *input_devices_seq_start(struct seq_file *seq, loff_t *pos) |
| 475 | { | 679 | { |
| 476 | /* acquire lock here ... Yes, we do need locking, I knowi, I know... */ | 680 | if (mutex_lock_interruptible(&input_mutex)) |
| 681 | return NULL; | ||
| 477 | 682 | ||
| 478 | return seq_list_start(&input_dev_list, *pos); | 683 | return seq_list_start(&input_dev_list, *pos); |
| 479 | } | 684 | } |
| @@ -485,7 +690,7 @@ static void *input_devices_seq_next(struct seq_file *seq, void *v, loff_t *pos) | |||
| 485 | 690 | ||
| 486 | static void input_devices_seq_stop(struct seq_file *seq, void *v) | 691 | static void input_devices_seq_stop(struct seq_file *seq, void *v) |
| 487 | { | 692 | { |
| 488 | /* release lock here */ | 693 | mutex_unlock(&input_mutex); |
| 489 | } | 694 | } |
| 490 | 695 | ||
| 491 | static void input_seq_print_bitmap(struct seq_file *seq, const char *name, | 696 | static void input_seq_print_bitmap(struct seq_file *seq, const char *name, |
| @@ -569,7 +774,9 @@ static const struct file_operations input_devices_fileops = { | |||
| 569 | 774 | ||
| 570 | static void *input_handlers_seq_start(struct seq_file *seq, loff_t *pos) | 775 | static void *input_handlers_seq_start(struct seq_file *seq, loff_t *pos) |
| 571 | { | 776 | { |
| 572 | /* acquire lock here ... Yes, we do need locking, I knowi, I know... */ | 777 | if (mutex_lock_interruptible(&input_mutex)) |
| 778 | return NULL; | ||
| 779 | |||
| 573 | seq->private = (void *)(unsigned long)*pos; | 780 | seq->private = (void *)(unsigned long)*pos; |
| 574 | return seq_list_start(&input_handler_list, *pos); | 781 | return seq_list_start(&input_handler_list, *pos); |
| 575 | } | 782 | } |
| @@ -582,7 +789,7 @@ static void *input_handlers_seq_next(struct seq_file *seq, void *v, loff_t *pos) | |||
| 582 | 789 | ||
| 583 | static void input_handlers_seq_stop(struct seq_file *seq, void *v) | 790 | static void input_handlers_seq_stop(struct seq_file *seq, void *v) |
| 584 | { | 791 | { |
| 585 | /* release lock here */ | 792 | mutex_unlock(&input_mutex); |
| 586 | } | 793 | } |
| 587 | 794 | ||
| 588 | static int input_handlers_seq_show(struct seq_file *seq, void *v) | 795 | static int input_handlers_seq_show(struct seq_file *seq, void *v) |
| @@ -983,6 +1190,7 @@ struct input_dev *input_allocate_device(void) | |||
| 983 | dev->dev.class = &input_class; | 1190 | dev->dev.class = &input_class; |
| 984 | device_initialize(&dev->dev); | 1191 | device_initialize(&dev->dev); |
| 985 | mutex_init(&dev->mutex); | 1192 | mutex_init(&dev->mutex); |
| 1193 | spin_lock_init(&dev->event_lock); | ||
| 986 | INIT_LIST_HEAD(&dev->h_list); | 1194 | INIT_LIST_HEAD(&dev->h_list); |
| 987 | INIT_LIST_HEAD(&dev->node); | 1195 | INIT_LIST_HEAD(&dev->node); |
| 988 | 1196 | ||
| @@ -1000,7 +1208,7 @@ EXPORT_SYMBOL(input_allocate_device); | |||
| 1000 | * This function should only be used if input_register_device() | 1208 | * This function should only be used if input_register_device() |
| 1001 | * was not called yet or if it failed. Once device was registered | 1209 | * was not called yet or if it failed. Once device was registered |
| 1002 | * use input_unregister_device() and memory will be freed once last | 1210 | * use input_unregister_device() and memory will be freed once last |
| 1003 | * refrence to the device is dropped. | 1211 | * reference to the device is dropped. |
| 1004 | * | 1212 | * |
| 1005 | * Device should be allocated by input_allocate_device(). | 1213 | * Device should be allocated by input_allocate_device(). |
| 1006 | * | 1214 | * |
| @@ -1070,6 +1278,18 @@ void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int | |||
| 1070 | } | 1278 | } |
| 1071 | EXPORT_SYMBOL(input_set_capability); | 1279 | EXPORT_SYMBOL(input_set_capability); |
| 1072 | 1280 | ||
| 1281 | /** | ||
| 1282 | * input_register_device - register device with input core | ||
| 1283 | * @dev: device to be registered | ||
| 1284 | * | ||
| 1285 | * This function registers device with input core. The device must be | ||
| 1286 | * allocated with input_allocate_device() and all it's capabilities | ||
| 1287 | * set up before registering. | ||
| 1288 | * If function fails the device must be freed with input_free_device(). | ||
| 1289 | * Once device has been successfully registered it can be unregistered | ||
| 1290 | * with input_unregister_device(); input_free_device() should not be | ||
| 1291 | * called in this case. | ||
| 1292 | */ | ||
| 1073 | int input_register_device(struct input_dev *dev) | 1293 | int input_register_device(struct input_dev *dev) |
| 1074 | { | 1294 | { |
| 1075 | static atomic_t input_no = ATOMIC_INIT(0); | 1295 | static atomic_t input_no = ATOMIC_INIT(0); |
| @@ -1077,7 +1297,7 @@ int input_register_device(struct input_dev *dev) | |||
| 1077 | const char *path; | 1297 | const char *path; |
| 1078 | int error; | 1298 | int error; |
| 1079 | 1299 | ||
| 1080 | set_bit(EV_SYN, dev->evbit); | 1300 | __set_bit(EV_SYN, dev->evbit); |
| 1081 | 1301 | ||
| 1082 | /* | 1302 | /* |
| 1083 | * If delay and period are pre-set by the driver, then autorepeating | 1303 | * If delay and period are pre-set by the driver, then autorepeating |
| @@ -1098,8 +1318,6 @@ int input_register_device(struct input_dev *dev) | |||
| 1098 | if (!dev->setkeycode) | 1318 | if (!dev->setkeycode) |
| 1099 | dev->setkeycode = input_default_setkeycode; | 1319 | dev->setkeycode = input_default_setkeycode; |
| 1100 | 1320 | ||
| 1101 | list_add_tail(&dev->node, &input_dev_list); | ||
| 1102 | |||
| 1103 | snprintf(dev->dev.bus_id, sizeof(dev->dev.bus_id), | 1321 | snprintf(dev->dev.bus_id, sizeof(dev->dev.bus_id), |
| 1104 | "input%ld", (unsigned long) atomic_inc_return(&input_no) - 1); | 1322 | "input%ld", (unsigned long) atomic_inc_return(&input_no) - 1); |
| 1105 | 1323 | ||
| @@ -1115,49 +1333,79 @@ int input_register_device(struct input_dev *dev) | |||
| 1115 | dev->name ? dev->name : "Unspecified device", path ? path : "N/A"); | 1333 | dev->name ? dev->name : "Unspecified device", path ? path : "N/A"); |
| 1116 | kfree(path); | 1334 | kfree(path); |
| 1117 | 1335 | ||
| 1336 | error = mutex_lock_interruptible(&input_mutex); | ||
| 1337 | if (error) { | ||
| 1338 | device_del(&dev->dev); | ||
| 1339 | return error; | ||
| 1340 | } | ||
| 1341 | |||
| 1342 | list_add_tail(&dev->node, &input_dev_list); | ||
| 1343 | |||
| 1118 | list_for_each_entry(handler, &input_handler_list, node) | 1344 | list_for_each_entry(handler, &input_handler_list, node) |
| 1119 | input_attach_handler(dev, handler); | 1345 | input_attach_handler(dev, handler); |
| 1120 | 1346 | ||
| 1121 | input_wakeup_procfs_readers(); | 1347 | input_wakeup_procfs_readers(); |
| 1122 | 1348 | ||
| 1349 | mutex_unlock(&input_mutex); | ||
| 1350 | |||
| 1123 | return 0; | 1351 | return 0; |
| 1124 | } | 1352 | } |
| 1125 | EXPORT_SYMBOL(input_register_device); | 1353 | EXPORT_SYMBOL(input_register_device); |
| 1126 | 1354 | ||
| 1355 | /** | ||
| 1356 | * input_unregister_device - unregister previously registered device | ||
| 1357 | * @dev: device to be unregistered | ||
| 1358 | * | ||
| 1359 | * This function unregisters an input device. Once device is unregistered | ||
| 1360 | * the caller should not try to access it as it may get freed at any moment. | ||
| 1361 | */ | ||
| 1127 | void input_unregister_device(struct input_dev *dev) | 1362 | void input_unregister_device(struct input_dev *dev) |
| 1128 | { | 1363 | { |
| 1129 | struct input_handle *handle, *next; | 1364 | struct input_handle *handle, *next; |
| 1130 | int code; | ||
| 1131 | 1365 | ||
| 1132 | for (code = 0; code <= KEY_MAX; code++) | 1366 | input_disconnect_device(dev); |
| 1133 | if (test_bit(code, dev->key)) | ||
| 1134 | input_report_key(dev, code, 0); | ||
| 1135 | input_sync(dev); | ||
| 1136 | 1367 | ||
| 1137 | del_timer_sync(&dev->timer); | 1368 | mutex_lock(&input_mutex); |
| 1138 | 1369 | ||
| 1139 | list_for_each_entry_safe(handle, next, &dev->h_list, d_node) | 1370 | list_for_each_entry_safe(handle, next, &dev->h_list, d_node) |
| 1140 | handle->handler->disconnect(handle); | 1371 | handle->handler->disconnect(handle); |
| 1141 | WARN_ON(!list_empty(&dev->h_list)); | 1372 | WARN_ON(!list_empty(&dev->h_list)); |
| 1142 | 1373 | ||
| 1374 | del_timer_sync(&dev->timer); | ||
| 1143 | list_del_init(&dev->node); | 1375 | list_del_init(&dev->node); |
| 1144 | 1376 | ||
| 1145 | device_unregister(&dev->dev); | ||
| 1146 | |||
| 1147 | input_wakeup_procfs_readers(); | 1377 | input_wakeup_procfs_readers(); |
| 1378 | |||
| 1379 | mutex_unlock(&input_mutex); | ||
| 1380 | |||
| 1381 | device_unregister(&dev->dev); | ||
| 1148 | } | 1382 | } |
| 1149 | EXPORT_SYMBOL(input_unregister_device); | 1383 | EXPORT_SYMBOL(input_unregister_device); |
| 1150 | 1384 | ||
| 1385 | /** | ||
| 1386 | * input_register_handler - register a new input handler | ||
| 1387 | * @handler: handler to be registered | ||
| 1388 | * | ||
| 1389 | * This function registers a new input handler (interface) for input | ||
| 1390 | * devices in the system and attaches it to all input devices that | ||
| 1391 | * are compatible with the handler. | ||
| 1392 | */ | ||
| 1151 | int input_register_handler(struct input_handler *handler) | 1393 | int input_register_handler(struct input_handler *handler) |
| 1152 | { | 1394 | { |
| 1153 | struct input_dev *dev; | 1395 | struct input_dev *dev; |
| 1396 | int retval; | ||
| 1397 | |||
| 1398 | retval = mutex_lock_interruptible(&input_mutex); | ||
| 1399 | if (retval) | ||
| 1400 | return retval; | ||
| 1154 | 1401 | ||
| 1155 | INIT_LIST_HEAD(&handler->h_list); | 1402 | INIT_LIST_HEAD(&handler->h_list); |
| 1156 | 1403 | ||
| 1157 | if (handler->fops != NULL) { | 1404 | if (handler->fops != NULL) { |
| 1158 | if (input_table[handler->minor >> 5]) | 1405 | if (input_table[handler->minor >> 5]) { |
| 1159 | return -EBUSY; | 1406 | retval = -EBUSY; |
| 1160 | 1407 | goto out; | |
| 1408 | } | ||
| 1161 | input_table[handler->minor >> 5] = handler; | 1409 | input_table[handler->minor >> 5] = handler; |
| 1162 | } | 1410 | } |
| 1163 | 1411 | ||
| @@ -1167,14 +1415,26 @@ int input_register_handler(struct input_handler *handler) | |||
| 1167 | input_attach_handler(dev, handler); | 1415 | input_attach_handler(dev, handler); |
| 1168 | 1416 | ||
| 1169 | input_wakeup_procfs_readers(); | 1417 | input_wakeup_procfs_readers(); |
| 1170 | return 0; | 1418 | |
| 1419 | out: | ||
| 1420 | mutex_unlock(&input_mutex); | ||
| 1421 | return retval; | ||
| 1171 | } | 1422 | } |
| 1172 | EXPORT_SYMBOL(input_register_handler); | 1423 | EXPORT_SYMBOL(input_register_handler); |
| 1173 | 1424 | ||
| 1425 | /** | ||
| 1426 | * input_unregister_handler - unregisters an input handler | ||
| 1427 | * @handler: handler to be unregistered | ||
| 1428 | * | ||
| 1429 | * This function disconnects a handler from its input devices and | ||
| 1430 | * removes it from lists of known handlers. | ||
| 1431 | */ | ||
| 1174 | void input_unregister_handler(struct input_handler *handler) | 1432 | void input_unregister_handler(struct input_handler *handler) |
| 1175 | { | 1433 | { |
| 1176 | struct input_handle *handle, *next; | 1434 | struct input_handle *handle, *next; |
| 1177 | 1435 | ||
| 1436 | mutex_lock(&input_mutex); | ||
| 1437 | |||
| 1178 | list_for_each_entry_safe(handle, next, &handler->h_list, h_node) | 1438 | list_for_each_entry_safe(handle, next, &handler->h_list, h_node) |
| 1179 | handler->disconnect(handle); | 1439 | handler->disconnect(handle); |
| 1180 | WARN_ON(!list_empty(&handler->h_list)); | 1440 | WARN_ON(!list_empty(&handler->h_list)); |
| @@ -1185,14 +1445,45 @@ void input_unregister_handler(struct input_handler *handler) | |||
| 1185 | input_table[handler->minor >> 5] = NULL; | 1445 | input_table[handler->minor >> 5] = NULL; |
| 1186 | 1446 | ||
| 1187 | input_wakeup_procfs_readers(); | 1447 | input_wakeup_procfs_readers(); |
| 1448 | |||
| 1449 | mutex_unlock(&input_mutex); | ||
| 1188 | } | 1450 | } |
| 1189 | EXPORT_SYMBOL(input_unregister_handler); | 1451 | EXPORT_SYMBOL(input_unregister_handler); |
| 1190 | 1452 | ||
| 1453 | /** | ||
| 1454 | * input_register_handle - register a new input handle | ||
| 1455 | * @handle: handle to register | ||
| 1456 | * | ||
| 1457 | * This function puts a new input handle onto device's | ||
| 1458 | * and handler's lists so that events can flow through | ||
| 1459 | * it once it is opened using input_open_device(). | ||
| 1460 | * | ||
| 1461 | * This function is supposed to be called from handler's | ||
| 1462 | * connect() method. | ||
| 1463 | */ | ||
| 1191 | int input_register_handle(struct input_handle *handle) | 1464 | int input_register_handle(struct input_handle *handle) |
| 1192 | { | 1465 | { |
| 1193 | struct input_handler *handler = handle->handler; | 1466 | struct input_handler *handler = handle->handler; |
| 1467 | struct input_dev *dev = handle->dev; | ||
| 1468 | int error; | ||
| 1469 | |||
| 1470 | /* | ||
| 1471 | * We take dev->mutex here to prevent race with | ||
| 1472 | * input_release_device(). | ||
| 1473 | */ | ||
| 1474 | error = mutex_lock_interruptible(&dev->mutex); | ||
| 1475 | if (error) | ||
| 1476 | return error; | ||
| 1477 | list_add_tail_rcu(&handle->d_node, &dev->h_list); | ||
| 1478 | mutex_unlock(&dev->mutex); | ||
| 1479 | synchronize_rcu(); | ||
| 1194 | 1480 | ||
| 1195 | list_add_tail(&handle->d_node, &handle->dev->h_list); | 1481 | /* |
| 1482 | * Since we are supposed to be called from ->connect() | ||
| 1483 | * which is mutually exclusive with ->disconnect() | ||
| 1484 | * we can't be racing with input_unregister_handle() | ||
| 1485 | * and so separate lock is not needed here. | ||
| 1486 | */ | ||
| 1196 | list_add_tail(&handle->h_node, &handler->h_list); | 1487 | list_add_tail(&handle->h_node, &handler->h_list); |
| 1197 | 1488 | ||
| 1198 | if (handler->start) | 1489 | if (handler->start) |
| @@ -1202,10 +1493,29 @@ int input_register_handle(struct input_handle *handle) | |||
| 1202 | } | 1493 | } |
| 1203 | EXPORT_SYMBOL(input_register_handle); | 1494 | EXPORT_SYMBOL(input_register_handle); |
| 1204 | 1495 | ||
| 1496 | /** | ||
| 1497 | * input_unregister_handle - unregister an input handle | ||
| 1498 | * @handle: handle to unregister | ||
| 1499 | * | ||
| 1500 | * This function removes input handle from device's | ||
| 1501 | * and handler's lists. | ||
| 1502 | * | ||
| 1503 | * This function is supposed to be called from handler's | ||
| 1504 | * disconnect() method. | ||
| 1505 | */ | ||
| 1205 | void input_unregister_handle(struct input_handle *handle) | 1506 | void input_unregister_handle(struct input_handle *handle) |
| 1206 | { | 1507 | { |
| 1508 | struct input_dev *dev = handle->dev; | ||
| 1509 | |||
| 1207 | list_del_init(&handle->h_node); | 1510 | list_del_init(&handle->h_node); |
| 1208 | list_del_init(&handle->d_node); | 1511 | |
| 1512 | /* | ||
| 1513 | * Take dev->mutex to prevent race with input_release_device(). | ||
| 1514 | */ | ||
| 1515 | mutex_lock(&dev->mutex); | ||
| 1516 | list_del_rcu(&handle->d_node); | ||
| 1517 | mutex_unlock(&dev->mutex); | ||
| 1518 | synchronize_rcu(); | ||
| 1209 | } | 1519 | } |
| 1210 | EXPORT_SYMBOL(input_unregister_handle); | 1520 | EXPORT_SYMBOL(input_unregister_handle); |
| 1211 | 1521 | ||
diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index a9a0180bfd46..2b201f9aa024 100644 --- a/drivers/input/joydev.c +++ b/drivers/input/joydev.c | |||
| @@ -43,6 +43,8 @@ struct joydev { | |||
| 43 | struct input_handle handle; | 43 | struct input_handle handle; |
| 44 | wait_queue_head_t wait; | 44 | wait_queue_head_t wait; |
| 45 | struct list_head client_list; | 45 | struct list_head client_list; |
| 46 | spinlock_t client_lock; /* protects client_list */ | ||
| 47 | struct mutex mutex; | ||
| 46 | struct device dev; | 48 | struct device dev; |
| 47 | 49 | ||
| 48 | struct js_corr corr[ABS_MAX + 1]; | 50 | struct js_corr corr[ABS_MAX + 1]; |
| @@ -61,31 +63,61 @@ struct joydev_client { | |||
| 61 | int head; | 63 | int head; |
| 62 | int tail; | 64 | int tail; |
| 63 | int startup; | 65 | int startup; |
| 66 | spinlock_t buffer_lock; /* protects access to buffer, head and tail */ | ||
| 64 | struct fasync_struct *fasync; | 67 | struct fasync_struct *fasync; |
| 65 | struct joydev *joydev; | 68 | struct joydev *joydev; |
| 66 | struct list_head node; | 69 | struct list_head node; |
| 67 | }; | 70 | }; |
| 68 | 71 | ||
| 69 | static struct joydev *joydev_table[JOYDEV_MINORS]; | 72 | static struct joydev *joydev_table[JOYDEV_MINORS]; |
| 73 | static DEFINE_MUTEX(joydev_table_mutex); | ||
| 70 | 74 | ||
| 71 | static int joydev_correct(int value, struct js_corr *corr) | 75 | static int joydev_correct(int value, struct js_corr *corr) |
| 72 | { | 76 | { |
| 73 | switch (corr->type) { | 77 | switch (corr->type) { |
| 74 | case JS_CORR_NONE: | 78 | |
| 75 | break; | 79 | case JS_CORR_NONE: |
| 76 | case JS_CORR_BROKEN: | 80 | break; |
| 77 | value = value > corr->coef[0] ? (value < corr->coef[1] ? 0 : | 81 | |
| 78 | ((corr->coef[3] * (value - corr->coef[1])) >> 14)) : | 82 | case JS_CORR_BROKEN: |
| 79 | ((corr->coef[2] * (value - corr->coef[0])) >> 14); | 83 | value = value > corr->coef[0] ? (value < corr->coef[1] ? 0 : |
| 80 | break; | 84 | ((corr->coef[3] * (value - corr->coef[1])) >> 14)) : |
| 81 | default: | 85 | ((corr->coef[2] * (value - corr->coef[0])) >> 14); |
| 82 | return 0; | 86 | break; |
| 87 | |||
| 88 | default: | ||
| 89 | return 0; | ||
| 83 | } | 90 | } |
| 84 | 91 | ||
| 85 | return value < -32767 ? -32767 : (value > 32767 ? 32767 : value); | 92 | return value < -32767 ? -32767 : (value > 32767 ? 32767 : value); |
| 86 | } | 93 | } |
| 87 | 94 | ||
| 88 | static void joydev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) | 95 | static void joydev_pass_event(struct joydev_client *client, |
| 96 | struct js_event *event) | ||
| 97 | { | ||
| 98 | struct joydev *joydev = client->joydev; | ||
| 99 | |||
| 100 | /* | ||
| 101 | * IRQs already disabled, just acquire the lock | ||
| 102 | */ | ||
| 103 | spin_lock(&client->buffer_lock); | ||
| 104 | |||
| 105 | client->buffer[client->head] = *event; | ||
| 106 | |||
| 107 | if (client->startup == joydev->nabs + joydev->nkey) { | ||
| 108 | client->head++; | ||
| 109 | client->head &= JOYDEV_BUFFER_SIZE - 1; | ||
| 110 | if (client->tail == client->head) | ||
| 111 | client->startup = 0; | ||
| 112 | } | ||
| 113 | |||
| 114 | spin_unlock(&client->buffer_lock); | ||
| 115 | |||
| 116 | kill_fasync(&client->fasync, SIGIO, POLL_IN); | ||
| 117 | } | ||
| 118 | |||
| 119 | static void joydev_event(struct input_handle *handle, | ||
| 120 | unsigned int type, unsigned int code, int value) | ||
| 89 | { | 121 | { |
| 90 | struct joydev *joydev = handle->private; | 122 | struct joydev *joydev = handle->private; |
| 91 | struct joydev_client *client; | 123 | struct joydev_client *client; |
| @@ -93,39 +125,34 @@ static void joydev_event(struct input_handle *handle, unsigned int type, unsigne | |||
| 93 | 125 | ||
| 94 | switch (type) { | 126 | switch (type) { |
| 95 | 127 | ||
| 96 | case EV_KEY: | 128 | case EV_KEY: |
| 97 | if (code < BTN_MISC || value == 2) | 129 | if (code < BTN_MISC || value == 2) |
| 98 | return; | 130 | return; |
| 99 | event.type = JS_EVENT_BUTTON; | 131 | event.type = JS_EVENT_BUTTON; |
| 100 | event.number = joydev->keymap[code - BTN_MISC]; | 132 | event.number = joydev->keymap[code - BTN_MISC]; |
| 101 | event.value = value; | 133 | event.value = value; |
| 102 | break; | 134 | break; |
| 103 | |||
| 104 | case EV_ABS: | ||
| 105 | event.type = JS_EVENT_AXIS; | ||
| 106 | event.number = joydev->absmap[code]; | ||
| 107 | event.value = joydev_correct(value, joydev->corr + event.number); | ||
| 108 | if (event.value == joydev->abs[event.number]) | ||
| 109 | return; | ||
| 110 | joydev->abs[event.number] = event.value; | ||
| 111 | break; | ||
| 112 | 135 | ||
| 113 | default: | 136 | case EV_ABS: |
| 137 | event.type = JS_EVENT_AXIS; | ||
| 138 | event.number = joydev->absmap[code]; | ||
| 139 | event.value = joydev_correct(value, | ||
| 140 | &joydev->corr[event.number]); | ||
| 141 | if (event.value == joydev->abs[event.number]) | ||
| 114 | return; | 142 | return; |
| 143 | joydev->abs[event.number] = event.value; | ||
| 144 | break; | ||
| 145 | |||
| 146 | default: | ||
| 147 | return; | ||
| 115 | } | 148 | } |
| 116 | 149 | ||
| 117 | event.time = jiffies_to_msecs(jiffies); | 150 | event.time = jiffies_to_msecs(jiffies); |
| 118 | 151 | ||
| 119 | list_for_each_entry(client, &joydev->client_list, node) { | 152 | rcu_read_lock(); |
| 120 | 153 | list_for_each_entry_rcu(client, &joydev->client_list, node) | |
| 121 | memcpy(client->buffer + client->head, &event, sizeof(struct js_event)); | 154 | joydev_pass_event(client, &event); |
| 122 | 155 | rcu_read_unlock(); | |
| 123 | if (client->startup == joydev->nabs + joydev->nkey) | ||
| 124 | if (client->tail == (client->head = (client->head + 1) & (JOYDEV_BUFFER_SIZE - 1))) | ||
| 125 | client->startup = 0; | ||
| 126 | |||
| 127 | kill_fasync(&client->fasync, SIGIO, POLL_IN); | ||
| 128 | } | ||
| 129 | 156 | ||
| 130 | wake_up_interruptible(&joydev->wait); | 157 | wake_up_interruptible(&joydev->wait); |
| 131 | } | 158 | } |
| @@ -144,23 +171,83 @@ static void joydev_free(struct device *dev) | |||
| 144 | { | 171 | { |
| 145 | struct joydev *joydev = container_of(dev, struct joydev, dev); | 172 | struct joydev *joydev = container_of(dev, struct joydev, dev); |
| 146 | 173 | ||
| 147 | joydev_table[joydev->minor] = NULL; | ||
| 148 | kfree(joydev); | 174 | kfree(joydev); |
| 149 | } | 175 | } |
| 150 | 176 | ||
| 177 | static void joydev_attach_client(struct joydev *joydev, | ||
| 178 | struct joydev_client *client) | ||
| 179 | { | ||
| 180 | spin_lock(&joydev->client_lock); | ||
| 181 | list_add_tail_rcu(&client->node, &joydev->client_list); | ||
| 182 | spin_unlock(&joydev->client_lock); | ||
| 183 | synchronize_rcu(); | ||
| 184 | } | ||
| 185 | |||
| 186 | static void joydev_detach_client(struct joydev *joydev, | ||
| 187 | struct joydev_client *client) | ||
| 188 | { | ||
| 189 | spin_lock(&joydev->client_lock); | ||
| 190 | list_del_rcu(&client->node); | ||
| 191 | spin_unlock(&joydev->client_lock); | ||
| 192 | synchronize_rcu(); | ||
| 193 | } | ||
| 194 | |||
| 195 | static int joydev_open_device(struct joydev *joydev) | ||
| 196 | { | ||
| 197 | int retval; | ||
| 198 | |||
| 199 | retval = mutex_lock_interruptible(&joydev->mutex); | ||
| 200 | if (retval) | ||
| 201 | return retval; | ||
| 202 | |||
| 203 | if (!joydev->exist) | ||
| 204 | retval = -ENODEV; | ||
| 205 | else if (!joydev->open++) { | ||
| 206 | retval = input_open_device(&joydev->handle); | ||
| 207 | if (retval) | ||
| 208 | joydev->open--; | ||
| 209 | } | ||
| 210 | |||
| 211 | mutex_unlock(&joydev->mutex); | ||
| 212 | return retval; | ||
| 213 | } | ||
| 214 | |||
| 215 | static void joydev_close_device(struct joydev *joydev) | ||
| 216 | { | ||
| 217 | mutex_lock(&joydev->mutex); | ||
| 218 | |||
| 219 | if (joydev->exist && !--joydev->open) | ||
| 220 | input_close_device(&joydev->handle); | ||
| 221 | |||
| 222 | mutex_unlock(&joydev->mutex); | ||
| 223 | } | ||
| 224 | |||
| 225 | /* | ||
| 226 | * Wake up users waiting for IO so they can disconnect from | ||
| 227 | * dead device. | ||
| 228 | */ | ||
| 229 | static void joydev_hangup(struct joydev *joydev) | ||
| 230 | { | ||
| 231 | struct joydev_client *client; | ||
| 232 | |||
| 233 | spin_lock(&joydev->client_lock); | ||
| 234 | list_for_each_entry(client, &joydev->client_list, node) | ||
| 235 | kill_fasync(&client->fasync, SIGIO, POLL_HUP); | ||
| 236 | spin_unlock(&joydev->client_lock); | ||
| 237 | |||
| 238 | wake_up_interruptible(&joydev->wait); | ||
| 239 | } | ||
| 240 | |||
| 151 | static int joydev_release(struct inode *inode, struct file *file) | 241 | static int joydev_release(struct inode *inode, struct file *file) |
| 152 | { | 242 | { |
| 153 | struct joydev_client *client = file->private_data; | 243 | struct joydev_client *client = file->private_data; |
| 154 | struct joydev *joydev = client->joydev; | 244 | struct joydev *joydev = client->joydev; |
| 155 | 245 | ||
| 156 | joydev_fasync(-1, file, 0); | 246 | joydev_fasync(-1, file, 0); |
| 157 | 247 | joydev_detach_client(joydev, client); | |
| 158 | list_del(&client->node); | ||
| 159 | kfree(client); | 248 | kfree(client); |
| 160 | 249 | ||
| 161 | if (!--joydev->open && joydev->exist) | 250 | joydev_close_device(joydev); |
| 162 | input_close_device(&joydev->handle); | ||
| 163 | |||
| 164 | put_device(&joydev->dev); | 251 | put_device(&joydev->dev); |
| 165 | 252 | ||
| 166 | return 0; | 253 | return 0; |
| @@ -176,11 +263,16 @@ static int joydev_open(struct inode *inode, struct file *file) | |||
| 176 | if (i >= JOYDEV_MINORS) | 263 | if (i >= JOYDEV_MINORS) |
| 177 | return -ENODEV; | 264 | return -ENODEV; |
| 178 | 265 | ||
| 266 | error = mutex_lock_interruptible(&joydev_table_mutex); | ||
| 267 | if (error) | ||
| 268 | return error; | ||
| 179 | joydev = joydev_table[i]; | 269 | joydev = joydev_table[i]; |
| 180 | if (!joydev || !joydev->exist) | 270 | if (joydev) |
| 181 | return -ENODEV; | 271 | get_device(&joydev->dev); |
| 272 | mutex_unlock(&joydev_table_mutex); | ||
| 182 | 273 | ||
| 183 | get_device(&joydev->dev); | 274 | if (!joydev) |
| 275 | return -ENODEV; | ||
| 184 | 276 | ||
| 185 | client = kzalloc(sizeof(struct joydev_client), GFP_KERNEL); | 277 | client = kzalloc(sizeof(struct joydev_client), GFP_KERNEL); |
| 186 | if (!client) { | 278 | if (!client) { |
| @@ -188,37 +280,129 @@ static int joydev_open(struct inode *inode, struct file *file) | |||
| 188 | goto err_put_joydev; | 280 | goto err_put_joydev; |
| 189 | } | 281 | } |
| 190 | 282 | ||
| 283 | spin_lock_init(&client->buffer_lock); | ||
| 191 | client->joydev = joydev; | 284 | client->joydev = joydev; |
| 192 | list_add_tail(&client->node, &joydev->client_list); | 285 | joydev_attach_client(joydev, client); |
| 193 | 286 | ||
| 194 | if (!joydev->open++ && joydev->exist) { | 287 | error = joydev_open_device(joydev); |
| 195 | error = input_open_device(&joydev->handle); | 288 | if (error) |
| 196 | if (error) | 289 | goto err_free_client; |
| 197 | goto err_free_client; | ||
| 198 | } | ||
| 199 | 290 | ||
| 200 | file->private_data = client; | 291 | file->private_data = client; |
| 201 | return 0; | 292 | return 0; |
| 202 | 293 | ||
| 203 | err_free_client: | 294 | err_free_client: |
| 204 | list_del(&client->node); | 295 | joydev_detach_client(joydev, client); |
| 205 | kfree(client); | 296 | kfree(client); |
| 206 | err_put_joydev: | 297 | err_put_joydev: |
| 207 | put_device(&joydev->dev); | 298 | put_device(&joydev->dev); |
| 208 | return error; | 299 | return error; |
| 209 | } | 300 | } |
| 210 | 301 | ||
| 211 | static ssize_t joydev_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) | 302 | static int joydev_generate_startup_event(struct joydev_client *client, |
| 303 | struct input_dev *input, | ||
| 304 | struct js_event *event) | ||
| 212 | { | 305 | { |
| 213 | return -EINVAL; | 306 | struct joydev *joydev = client->joydev; |
| 307 | int have_event; | ||
| 308 | |||
| 309 | spin_lock_irq(&client->buffer_lock); | ||
| 310 | |||
| 311 | have_event = client->startup < joydev->nabs + joydev->nkey; | ||
| 312 | |||
| 313 | if (have_event) { | ||
| 314 | |||
| 315 | event->time = jiffies_to_msecs(jiffies); | ||
| 316 | if (client->startup < joydev->nkey) { | ||
| 317 | event->type = JS_EVENT_BUTTON | JS_EVENT_INIT; | ||
| 318 | event->number = client->startup; | ||
| 319 | event->value = !!test_bit(joydev->keypam[event->number], | ||
| 320 | input->key); | ||
| 321 | } else { | ||
| 322 | event->type = JS_EVENT_AXIS | JS_EVENT_INIT; | ||
| 323 | event->number = client->startup - joydev->nkey; | ||
| 324 | event->value = joydev->abs[event->number]; | ||
| 325 | } | ||
| 326 | client->startup++; | ||
| 327 | } | ||
| 328 | |||
| 329 | spin_unlock_irq(&client->buffer_lock); | ||
| 330 | |||
| 331 | return have_event; | ||
| 332 | } | ||
| 333 | |||
| 334 | static int joydev_fetch_next_event(struct joydev_client *client, | ||
| 335 | struct js_event *event) | ||
| 336 | { | ||
| 337 | int have_event; | ||
| 338 | |||
| 339 | spin_lock_irq(&client->buffer_lock); | ||
| 340 | |||
| 341 | have_event = client->head != client->tail; | ||
| 342 | if (have_event) { | ||
| 343 | *event = client->buffer[client->tail++]; | ||
| 344 | client->tail &= JOYDEV_BUFFER_SIZE - 1; | ||
| 345 | } | ||
| 346 | |||
| 347 | spin_unlock_irq(&client->buffer_lock); | ||
| 348 | |||
| 349 | return have_event; | ||
| 350 | } | ||
| 351 | |||
| 352 | /* | ||
| 353 | * Old joystick interface | ||
| 354 | */ | ||
| 355 | static ssize_t joydev_0x_read(struct joydev_client *client, | ||
| 356 | struct input_dev *input, | ||
| 357 | char __user *buf) | ||
| 358 | { | ||
| 359 | struct joydev *joydev = client->joydev; | ||
| 360 | struct JS_DATA_TYPE data; | ||
| 361 | int i; | ||
| 362 | |||
| 363 | spin_lock_irq(&input->event_lock); | ||
| 364 | |||
| 365 | /* | ||
| 366 | * Get device state | ||
| 367 | */ | ||
| 368 | for (data.buttons = i = 0; i < 32 && i < joydev->nkey; i++) | ||
| 369 | data.buttons |= | ||
| 370 | test_bit(joydev->keypam[i], input->key) ? (1 << i) : 0; | ||
| 371 | data.x = (joydev->abs[0] / 256 + 128) >> joydev->glue.JS_CORR.x; | ||
| 372 | data.y = (joydev->abs[1] / 256 + 128) >> joydev->glue.JS_CORR.y; | ||
| 373 | |||
| 374 | /* | ||
| 375 | * Reset reader's event queue | ||
| 376 | */ | ||
| 377 | spin_lock(&client->buffer_lock); | ||
| 378 | client->startup = 0; | ||
| 379 | client->tail = client->head; | ||
| 380 | spin_unlock(&client->buffer_lock); | ||
| 381 | |||
| 382 | spin_unlock_irq(&input->event_lock); | ||
| 383 | |||
| 384 | if (copy_to_user(buf, &data, sizeof(struct JS_DATA_TYPE))) | ||
| 385 | return -EFAULT; | ||
| 386 | |||
| 387 | return sizeof(struct JS_DATA_TYPE); | ||
| 388 | } | ||
| 389 | |||
| 390 | static inline int joydev_data_pending(struct joydev_client *client) | ||
| 391 | { | ||
| 392 | struct joydev *joydev = client->joydev; | ||
| 393 | |||
| 394 | return client->startup < joydev->nabs + joydev->nkey || | ||
| 395 | client->head != client->tail; | ||
| 214 | } | 396 | } |
| 215 | 397 | ||
| 216 | static ssize_t joydev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) | 398 | static ssize_t joydev_read(struct file *file, char __user *buf, |
| 399 | size_t count, loff_t *ppos) | ||
| 217 | { | 400 | { |
| 218 | struct joydev_client *client = file->private_data; | 401 | struct joydev_client *client = file->private_data; |
| 219 | struct joydev *joydev = client->joydev; | 402 | struct joydev *joydev = client->joydev; |
| 220 | struct input_dev *input = joydev->handle.dev; | 403 | struct input_dev *input = joydev->handle.dev; |
| 221 | int retval = 0; | 404 | struct js_event event; |
| 405 | int retval; | ||
| 222 | 406 | ||
| 223 | if (!joydev->exist) | 407 | if (!joydev->exist) |
| 224 | return -ENODEV; | 408 | return -ENODEV; |
| @@ -226,68 +410,35 @@ static ssize_t joydev_read(struct file *file, char __user *buf, size_t count, lo | |||
| 226 | if (count < sizeof(struct js_event)) | 410 | if (count < sizeof(struct js_event)) |
| 227 | return -EINVAL; | 411 | return -EINVAL; |
| 228 | 412 | ||
| 229 | if (count == sizeof(struct JS_DATA_TYPE)) { | 413 | if (count == sizeof(struct JS_DATA_TYPE)) |
| 230 | 414 | return joydev_0x_read(client, input, buf); | |
| 231 | struct JS_DATA_TYPE data; | ||
| 232 | int i; | ||
| 233 | |||
| 234 | for (data.buttons = i = 0; i < 32 && i < joydev->nkey; i++) | ||
| 235 | data.buttons |= test_bit(joydev->keypam[i], input->key) ? (1 << i) : 0; | ||
| 236 | data.x = (joydev->abs[0] / 256 + 128) >> joydev->glue.JS_CORR.x; | ||
| 237 | data.y = (joydev->abs[1] / 256 + 128) >> joydev->glue.JS_CORR.y; | ||
| 238 | |||
| 239 | if (copy_to_user(buf, &data, sizeof(struct JS_DATA_TYPE))) | ||
| 240 | return -EFAULT; | ||
| 241 | |||
| 242 | client->startup = 0; | ||
| 243 | client->tail = client->head; | ||
| 244 | 415 | ||
| 245 | return sizeof(struct JS_DATA_TYPE); | 416 | if (!joydev_data_pending(client) && (file->f_flags & O_NONBLOCK)) |
| 246 | } | ||
| 247 | |||
| 248 | if (client->startup == joydev->nabs + joydev->nkey && | ||
| 249 | client->head == client->tail && (file->f_flags & O_NONBLOCK)) | ||
| 250 | return -EAGAIN; | 417 | return -EAGAIN; |
| 251 | 418 | ||
| 252 | retval = wait_event_interruptible(joydev->wait, | 419 | retval = wait_event_interruptible(joydev->wait, |
| 253 | !joydev->exist || | 420 | !joydev->exist || joydev_data_pending(client)); |
| 254 | client->startup < joydev->nabs + joydev->nkey || | ||
| 255 | client->head != client->tail); | ||
| 256 | if (retval) | 421 | if (retval) |
| 257 | return retval; | 422 | return retval; |
| 258 | 423 | ||
| 259 | if (!joydev->exist) | 424 | if (!joydev->exist) |
| 260 | return -ENODEV; | 425 | return -ENODEV; |
| 261 | 426 | ||
| 262 | while (client->startup < joydev->nabs + joydev->nkey && retval + sizeof(struct js_event) <= count) { | 427 | while (retval + sizeof(struct js_event) <= count && |
| 263 | 428 | joydev_generate_startup_event(client, input, &event)) { | |
| 264 | struct js_event event; | ||
| 265 | |||
| 266 | event.time = jiffies_to_msecs(jiffies); | ||
| 267 | |||
| 268 | if (client->startup < joydev->nkey) { | ||
| 269 | event.type = JS_EVENT_BUTTON | JS_EVENT_INIT; | ||
| 270 | event.number = client->startup; | ||
| 271 | event.value = !!test_bit(joydev->keypam[event.number], input->key); | ||
| 272 | } else { | ||
| 273 | event.type = JS_EVENT_AXIS | JS_EVENT_INIT; | ||
| 274 | event.number = client->startup - joydev->nkey; | ||
| 275 | event.value = joydev->abs[event.number]; | ||
| 276 | } | ||
| 277 | 429 | ||
| 278 | if (copy_to_user(buf + retval, &event, sizeof(struct js_event))) | 430 | if (copy_to_user(buf + retval, &event, sizeof(struct js_event))) |
| 279 | return -EFAULT; | 431 | return -EFAULT; |
| 280 | 432 | ||
| 281 | client->startup++; | ||
| 282 | retval += sizeof(struct js_event); | 433 | retval += sizeof(struct js_event); |
| 283 | } | 434 | } |
| 284 | 435 | ||
| 285 | while (client->head != client->tail && retval + sizeof(struct js_event) <= count) { | 436 | while (retval + sizeof(struct js_event) <= count && |
| 437 | joydev_fetch_next_event(client, &event)) { | ||
| 286 | 438 | ||
| 287 | if (copy_to_user(buf + retval, client->buffer + client->tail, sizeof(struct js_event))) | 439 | if (copy_to_user(buf + retval, &event, sizeof(struct js_event))) |
| 288 | return -EFAULT; | 440 | return -EFAULT; |
| 289 | 441 | ||
| 290 | client->tail = (client->tail + 1) & (JOYDEV_BUFFER_SIZE - 1); | ||
| 291 | retval += sizeof(struct js_event); | 442 | retval += sizeof(struct js_event); |
| 292 | } | 443 | } |
| 293 | 444 | ||
| @@ -301,126 +452,144 @@ static unsigned int joydev_poll(struct file *file, poll_table *wait) | |||
| 301 | struct joydev *joydev = client->joydev; | 452 | struct joydev *joydev = client->joydev; |
| 302 | 453 | ||
| 303 | poll_wait(file, &joydev->wait, wait); | 454 | poll_wait(file, &joydev->wait, wait); |
| 304 | return ((client->head != client->tail || client->startup < joydev->nabs + joydev->nkey) ? | 455 | return (joydev_data_pending(client) ? (POLLIN | POLLRDNORM) : 0) | |
| 305 | (POLLIN | POLLRDNORM) : 0) | (joydev->exist ? 0 : (POLLHUP | POLLERR)); | 456 | (joydev->exist ? 0 : (POLLHUP | POLLERR)); |
| 306 | } | 457 | } |
| 307 | 458 | ||
| 308 | static int joydev_ioctl_common(struct joydev *joydev, unsigned int cmd, void __user *argp) | 459 | static int joydev_ioctl_common(struct joydev *joydev, |
| 460 | unsigned int cmd, void __user *argp) | ||
| 309 | { | 461 | { |
| 310 | struct input_dev *dev = joydev->handle.dev; | 462 | struct input_dev *dev = joydev->handle.dev; |
| 311 | int i, j; | 463 | int i, j; |
| 312 | 464 | ||
| 313 | switch (cmd) { | 465 | switch (cmd) { |
| 314 | 466 | ||
| 315 | case JS_SET_CAL: | 467 | case JS_SET_CAL: |
| 316 | return copy_from_user(&joydev->glue.JS_CORR, argp, | 468 | return copy_from_user(&joydev->glue.JS_CORR, argp, |
| 317 | sizeof(joydev->glue.JS_CORR)) ? -EFAULT : 0; | 469 | sizeof(joydev->glue.JS_CORR)) ? -EFAULT : 0; |
| 318 | 470 | ||
| 319 | case JS_GET_CAL: | 471 | case JS_GET_CAL: |
| 320 | return copy_to_user(argp, &joydev->glue.JS_CORR, | 472 | return copy_to_user(argp, &joydev->glue.JS_CORR, |
| 321 | sizeof(joydev->glue.JS_CORR)) ? -EFAULT : 0; | 473 | sizeof(joydev->glue.JS_CORR)) ? -EFAULT : 0; |
| 322 | 474 | ||
| 323 | case JS_SET_TIMEOUT: | 475 | case JS_SET_TIMEOUT: |
| 324 | return get_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp); | 476 | return get_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp); |
| 325 | 477 | ||
| 326 | case JS_GET_TIMEOUT: | 478 | case JS_GET_TIMEOUT: |
| 327 | return put_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp); | 479 | return put_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp); |
| 328 | 480 | ||
| 329 | case JSIOCGVERSION: | 481 | case JSIOCGVERSION: |
| 330 | return put_user(JS_VERSION, (__u32 __user *) argp); | 482 | return put_user(JS_VERSION, (__u32 __user *) argp); |
| 331 | 483 | ||
| 332 | case JSIOCGAXES: | 484 | case JSIOCGAXES: |
| 333 | return put_user(joydev->nabs, (__u8 __user *) argp); | 485 | return put_user(joydev->nabs, (__u8 __user *) argp); |
| 334 | 486 | ||
| 335 | case JSIOCGBUTTONS: | 487 | case JSIOCGBUTTONS: |
| 336 | return put_user(joydev->nkey, (__u8 __user *) argp); | 488 | return put_user(joydev->nkey, (__u8 __user *) argp); |
| 337 | 489 | ||
| 338 | case JSIOCSCORR: | 490 | case JSIOCSCORR: |
| 339 | if (copy_from_user(joydev->corr, argp, | 491 | if (copy_from_user(joydev->corr, argp, |
| 340 | sizeof(joydev->corr[0]) * joydev->nabs)) | 492 | sizeof(joydev->corr[0]) * joydev->nabs)) |
| 341 | return -EFAULT; | 493 | return -EFAULT; |
| 342 | for (i = 0; i < joydev->nabs; i++) { | ||
| 343 | j = joydev->abspam[i]; | ||
| 344 | joydev->abs[i] = joydev_correct(dev->abs[j], joydev->corr + i); | ||
| 345 | } | ||
| 346 | return 0; | ||
| 347 | 494 | ||
| 348 | case JSIOCGCORR: | 495 | for (i = 0; i < joydev->nabs; i++) { |
| 349 | return copy_to_user(argp, joydev->corr, | 496 | j = joydev->abspam[i]; |
| 350 | sizeof(joydev->corr[0]) * joydev->nabs) ? -EFAULT : 0; | 497 | joydev->abs[i] = joydev_correct(dev->abs[j], |
| 498 | &joydev->corr[i]); | ||
| 499 | } | ||
| 500 | return 0; | ||
| 351 | 501 | ||
| 352 | case JSIOCSAXMAP: | 502 | case JSIOCGCORR: |
| 353 | if (copy_from_user(joydev->abspam, argp, sizeof(__u8) * (ABS_MAX + 1))) | 503 | return copy_to_user(argp, joydev->corr, |
| 354 | return -EFAULT; | 504 | sizeof(joydev->corr[0]) * joydev->nabs) ? -EFAULT : 0; |
| 355 | for (i = 0; i < joydev->nabs; i++) { | 505 | |
| 356 | if (joydev->abspam[i] > ABS_MAX) | 506 | case JSIOCSAXMAP: |
| 357 | return -EINVAL; | 507 | if (copy_from_user(joydev->abspam, argp, |
| 358 | joydev->absmap[joydev->abspam[i]] = i; | 508 | sizeof(__u8) * (ABS_MAX + 1))) |
| 359 | } | 509 | return -EFAULT; |
| 360 | return 0; | 510 | |
| 361 | 511 | for (i = 0; i < joydev->nabs; i++) { | |
| 362 | case JSIOCGAXMAP: | 512 | if (joydev->abspam[i] > ABS_MAX) |
| 363 | return copy_to_user(argp, joydev->abspam, | 513 | return -EINVAL; |
| 364 | sizeof(__u8) * (ABS_MAX + 1)) ? -EFAULT : 0; | 514 | joydev->absmap[joydev->abspam[i]] = i; |
| 365 | 515 | } | |
| 366 | case JSIOCSBTNMAP: | 516 | return 0; |
| 367 | if (copy_from_user(joydev->keypam, argp, sizeof(__u16) * (KEY_MAX - BTN_MISC + 1))) | 517 | |
| 518 | case JSIOCGAXMAP: | ||
| 519 | return copy_to_user(argp, joydev->abspam, | ||
| 520 | sizeof(__u8) * (ABS_MAX + 1)) ? -EFAULT : 0; | ||
| 521 | |||
| 522 | case JSIOCSBTNMAP: | ||
| 523 | if (copy_from_user(joydev->keypam, argp, | ||
| 524 | sizeof(__u16) * (KEY_MAX - BTN_MISC + 1))) | ||
| 525 | return -EFAULT; | ||
| 526 | |||
| 527 | for (i = 0; i < joydev->nkey; i++) { | ||
| 528 | if (joydev->keypam[i] > KEY_MAX || | ||
| 529 | joydev->keypam[i] < BTN_MISC) | ||
| 530 | return -EINVAL; | ||
| 531 | joydev->keymap[joydev->keypam[i] - BTN_MISC] = i; | ||
| 532 | } | ||
| 533 | |||
| 534 | return 0; | ||
| 535 | |||
| 536 | case JSIOCGBTNMAP: | ||
| 537 | return copy_to_user(argp, joydev->keypam, | ||
| 538 | sizeof(__u16) * (KEY_MAX - BTN_MISC + 1)) ? -EFAULT : 0; | ||
| 539 | |||
| 540 | default: | ||
| 541 | if ((cmd & ~IOCSIZE_MASK) == JSIOCGNAME(0)) { | ||
| 542 | int len; | ||
| 543 | if (!dev->name) | ||
| 544 | return 0; | ||
| 545 | len = strlen(dev->name) + 1; | ||
| 546 | if (len > _IOC_SIZE(cmd)) | ||
| 547 | len = _IOC_SIZE(cmd); | ||
| 548 | if (copy_to_user(argp, dev->name, len)) | ||
| 368 | return -EFAULT; | 549 | return -EFAULT; |
| 369 | for (i = 0; i < joydev->nkey; i++) { | 550 | return len; |
| 370 | if (joydev->keypam[i] > KEY_MAX || joydev->keypam[i] < BTN_MISC) | 551 | } |
| 371 | return -EINVAL; | ||
| 372 | joydev->keymap[joydev->keypam[i] - BTN_MISC] = i; | ||
| 373 | } | ||
| 374 | return 0; | ||
| 375 | |||
| 376 | case JSIOCGBTNMAP: | ||
| 377 | return copy_to_user(argp, joydev->keypam, | ||
| 378 | sizeof(__u16) * (KEY_MAX - BTN_MISC + 1)) ? -EFAULT : 0; | ||
| 379 | |||
| 380 | default: | ||
| 381 | if ((cmd & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT)) == JSIOCGNAME(0)) { | ||
| 382 | int len; | ||
| 383 | if (!dev->name) | ||
| 384 | return 0; | ||
| 385 | len = strlen(dev->name) + 1; | ||
| 386 | if (len > _IOC_SIZE(cmd)) | ||
| 387 | len = _IOC_SIZE(cmd); | ||
| 388 | if (copy_to_user(argp, dev->name, len)) | ||
| 389 | return -EFAULT; | ||
| 390 | return len; | ||
| 391 | } | ||
| 392 | } | 552 | } |
| 393 | return -EINVAL; | 553 | return -EINVAL; |
| 394 | } | 554 | } |
| 395 | 555 | ||
| 396 | #ifdef CONFIG_COMPAT | 556 | #ifdef CONFIG_COMPAT |
| 397 | static long joydev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | 557 | static long joydev_compat_ioctl(struct file *file, |
| 558 | unsigned int cmd, unsigned long arg) | ||
| 398 | { | 559 | { |
| 399 | struct joydev_client *client = file->private_data; | 560 | struct joydev_client *client = file->private_data; |
| 400 | struct joydev *joydev = client->joydev; | 561 | struct joydev *joydev = client->joydev; |
| 401 | void __user *argp = (void __user *)arg; | 562 | void __user *argp = (void __user *)arg; |
| 402 | s32 tmp32; | 563 | s32 tmp32; |
| 403 | struct JS_DATA_SAVE_TYPE_32 ds32; | 564 | struct JS_DATA_SAVE_TYPE_32 ds32; |
| 404 | int err; | 565 | int retval; |
| 405 | 566 | ||
| 406 | if (!joydev->exist) | 567 | retval = mutex_lock_interruptible(&joydev->mutex); |
| 407 | return -ENODEV; | 568 | if (retval) |
| 569 | return retval; | ||
| 570 | |||
| 571 | if (!joydev->exist) { | ||
| 572 | retval = -ENODEV; | ||
| 573 | goto out; | ||
| 574 | } | ||
| 575 | |||
| 576 | switch (cmd) { | ||
| 408 | 577 | ||
| 409 | switch(cmd) { | ||
| 410 | case JS_SET_TIMELIMIT: | 578 | case JS_SET_TIMELIMIT: |
| 411 | err = get_user(tmp32, (s32 __user *) arg); | 579 | retval = get_user(tmp32, (s32 __user *) arg); |
| 412 | if (err == 0) | 580 | if (retval == 0) |
| 413 | joydev->glue.JS_TIMELIMIT = tmp32; | 581 | joydev->glue.JS_TIMELIMIT = tmp32; |
| 414 | break; | 582 | break; |
| 583 | |||
| 415 | case JS_GET_TIMELIMIT: | 584 | case JS_GET_TIMELIMIT: |
| 416 | tmp32 = joydev->glue.JS_TIMELIMIT; | 585 | tmp32 = joydev->glue.JS_TIMELIMIT; |
| 417 | err = put_user(tmp32, (s32 __user *) arg); | 586 | retval = put_user(tmp32, (s32 __user *) arg); |
| 418 | break; | 587 | break; |
| 419 | 588 | ||
| 420 | case JS_SET_ALL: | 589 | case JS_SET_ALL: |
| 421 | err = copy_from_user(&ds32, argp, | 590 | retval = copy_from_user(&ds32, argp, |
| 422 | sizeof(ds32)) ? -EFAULT : 0; | 591 | sizeof(ds32)) ? -EFAULT : 0; |
| 423 | if (err == 0) { | 592 | if (retval == 0) { |
| 424 | joydev->glue.JS_TIMEOUT = ds32.JS_TIMEOUT; | 593 | joydev->glue.JS_TIMEOUT = ds32.JS_TIMEOUT; |
| 425 | joydev->glue.BUSY = ds32.BUSY; | 594 | joydev->glue.BUSY = ds32.BUSY; |
| 426 | joydev->glue.JS_EXPIRETIME = ds32.JS_EXPIRETIME; | 595 | joydev->glue.JS_EXPIRETIME = ds32.JS_EXPIRETIME; |
| @@ -438,55 +607,119 @@ static long joydev_compat_ioctl(struct file *file, unsigned int cmd, unsigned lo | |||
| 438 | ds32.JS_SAVE = joydev->glue.JS_SAVE; | 607 | ds32.JS_SAVE = joydev->glue.JS_SAVE; |
| 439 | ds32.JS_CORR = joydev->glue.JS_CORR; | 608 | ds32.JS_CORR = joydev->glue.JS_CORR; |
| 440 | 609 | ||
| 441 | err = copy_to_user(argp, &ds32, sizeof(ds32)) ? -EFAULT : 0; | 610 | retval = copy_to_user(argp, &ds32, sizeof(ds32)) ? -EFAULT : 0; |
| 442 | break; | 611 | break; |
| 443 | 612 | ||
| 444 | default: | 613 | default: |
| 445 | err = joydev_ioctl_common(joydev, cmd, argp); | 614 | retval = joydev_ioctl_common(joydev, cmd, argp); |
| 615 | break; | ||
| 446 | } | 616 | } |
| 447 | return err; | 617 | |
| 618 | out: | ||
| 619 | mutex_unlock(&joydev->mutex); | ||
| 620 | return retval; | ||
| 448 | } | 621 | } |
| 449 | #endif /* CONFIG_COMPAT */ | 622 | #endif /* CONFIG_COMPAT */ |
| 450 | 623 | ||
| 451 | static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) | 624 | static long joydev_ioctl(struct file *file, |
| 625 | unsigned int cmd, unsigned long arg) | ||
| 452 | { | 626 | { |
| 453 | struct joydev_client *client = file->private_data; | 627 | struct joydev_client *client = file->private_data; |
| 454 | struct joydev *joydev = client->joydev; | 628 | struct joydev *joydev = client->joydev; |
| 455 | void __user *argp = (void __user *)arg; | 629 | void __user *argp = (void __user *)arg; |
| 630 | int retval; | ||
| 456 | 631 | ||
| 457 | if (!joydev->exist) | 632 | retval = mutex_lock_interruptible(&joydev->mutex); |
| 458 | return -ENODEV; | 633 | if (retval) |
| 634 | return retval; | ||
| 635 | |||
| 636 | if (!joydev->exist) { | ||
| 637 | retval = -ENODEV; | ||
| 638 | goto out; | ||
| 639 | } | ||
| 640 | |||
| 641 | switch (cmd) { | ||
| 642 | |||
| 643 | case JS_SET_TIMELIMIT: | ||
| 644 | retval = get_user(joydev->glue.JS_TIMELIMIT, | ||
| 645 | (long __user *) arg); | ||
| 646 | break; | ||
| 647 | |||
| 648 | case JS_GET_TIMELIMIT: | ||
| 649 | retval = put_user(joydev->glue.JS_TIMELIMIT, | ||
| 650 | (long __user *) arg); | ||
| 651 | break; | ||
| 652 | |||
| 653 | case JS_SET_ALL: | ||
| 654 | retval = copy_from_user(&joydev->glue, argp, | ||
| 655 | sizeof(joydev->glue)) ? -EFAULT: 0; | ||
| 656 | break; | ||
| 657 | |||
| 658 | case JS_GET_ALL: | ||
| 659 | retval = copy_to_user(argp, &joydev->glue, | ||
| 660 | sizeof(joydev->glue)) ? -EFAULT : 0; | ||
| 661 | break; | ||
| 459 | 662 | ||
| 460 | switch(cmd) { | 663 | default: |
| 461 | case JS_SET_TIMELIMIT: | 664 | retval = joydev_ioctl_common(joydev, cmd, argp); |
| 462 | return get_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg); | 665 | break; |
| 463 | case JS_GET_TIMELIMIT: | ||
| 464 | return put_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg); | ||
| 465 | case JS_SET_ALL: | ||
| 466 | return copy_from_user(&joydev->glue, argp, | ||
| 467 | sizeof(joydev->glue)) ? -EFAULT : 0; | ||
| 468 | case JS_GET_ALL: | ||
| 469 | return copy_to_user(argp, &joydev->glue, | ||
| 470 | sizeof(joydev->glue)) ? -EFAULT : 0; | ||
| 471 | default: | ||
| 472 | return joydev_ioctl_common(joydev, cmd, argp); | ||
| 473 | } | 666 | } |
| 667 | out: | ||
| 668 | mutex_unlock(&joydev->mutex); | ||
| 669 | return retval; | ||
| 474 | } | 670 | } |
| 475 | 671 | ||
| 476 | static const struct file_operations joydev_fops = { | 672 | static const struct file_operations joydev_fops = { |
| 477 | .owner = THIS_MODULE, | 673 | .owner = THIS_MODULE, |
| 478 | .read = joydev_read, | 674 | .read = joydev_read, |
| 479 | .write = joydev_write, | 675 | .poll = joydev_poll, |
| 480 | .poll = joydev_poll, | 676 | .open = joydev_open, |
| 481 | .open = joydev_open, | 677 | .release = joydev_release, |
| 482 | .release = joydev_release, | 678 | .unlocked_ioctl = joydev_ioctl, |
| 483 | .ioctl = joydev_ioctl, | ||
| 484 | #ifdef CONFIG_COMPAT | 679 | #ifdef CONFIG_COMPAT |
| 485 | .compat_ioctl = joydev_compat_ioctl, | 680 | .compat_ioctl = joydev_compat_ioctl, |
| 486 | #endif | 681 | #endif |
| 487 | .fasync = joydev_fasync, | 682 | .fasync = joydev_fasync, |
| 488 | }; | 683 | }; |
| 489 | 684 | ||
| 685 | static int joydev_install_chrdev(struct joydev *joydev) | ||
| 686 | { | ||
| 687 | joydev_table[joydev->minor] = joydev; | ||
| 688 | return 0; | ||
| 689 | } | ||
| 690 | |||
| 691 | static void joydev_remove_chrdev(struct joydev *joydev) | ||
| 692 | { | ||
| 693 | mutex_lock(&joydev_table_mutex); | ||
| 694 | joydev_table[joydev->minor] = NULL; | ||
| 695 | mutex_unlock(&joydev_table_mutex); | ||
| 696 | } | ||
| 697 | |||
| 698 | /* | ||
| 699 | * Mark device non-existant. This disables writes, ioctls and | ||
| 700 | * prevents new users from opening the device. Already posted | ||
| 701 | * blocking reads will stay, however new ones will fail. | ||
| 702 | */ | ||
| 703 | static void joydev_mark_dead(struct joydev *joydev) | ||
| 704 | { | ||
| 705 | mutex_lock(&joydev->mutex); | ||
| 706 | joydev->exist = 0; | ||
| 707 | mutex_unlock(&joydev->mutex); | ||
| 708 | } | ||
| 709 | |||
| 710 | static void joydev_cleanup(struct joydev *joydev) | ||
| 711 | { | ||
| 712 | struct input_handle *handle = &joydev->handle; | ||
| 713 | |||
| 714 | joydev_mark_dead(joydev); | ||
| 715 | joydev_hangup(joydev); | ||
| 716 | joydev_remove_chrdev(joydev); | ||
| 717 | |||
| 718 | /* joydev is marked dead so noone else accesses joydev->open */ | ||
| 719 | if (joydev->open) | ||
| 720 | input_close_device(handle); | ||
| 721 | } | ||
| 722 | |||
| 490 | static int joydev_connect(struct input_handler *handler, struct input_dev *dev, | 723 | static int joydev_connect(struct input_handler *handler, struct input_dev *dev, |
| 491 | const struct input_device_id *id) | 724 | const struct input_device_id *id) |
| 492 | { | 725 | { |
| @@ -494,7 +727,10 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev, | |||
| 494 | int i, j, t, minor; | 727 | int i, j, t, minor; |
| 495 | int error; | 728 | int error; |
| 496 | 729 | ||
| 497 | for (minor = 0; minor < JOYDEV_MINORS && joydev_table[minor]; minor++); | 730 | for (minor = 0; minor < JOYDEV_MINORS; minor++) |
| 731 | if (!joydev_table[minor]) | ||
| 732 | break; | ||
| 733 | |||
| 498 | if (minor == JOYDEV_MINORS) { | 734 | if (minor == JOYDEV_MINORS) { |
| 499 | printk(KERN_ERR "joydev: no more free joydev devices\n"); | 735 | printk(KERN_ERR "joydev: no more free joydev devices\n"); |
| 500 | return -ENFILE; | 736 | return -ENFILE; |
| @@ -505,15 +741,19 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev, | |||
| 505 | return -ENOMEM; | 741 | return -ENOMEM; |
| 506 | 742 | ||
| 507 | INIT_LIST_HEAD(&joydev->client_list); | 743 | INIT_LIST_HEAD(&joydev->client_list); |
| 744 | spin_lock_init(&joydev->client_lock); | ||
| 745 | mutex_init(&joydev->mutex); | ||
| 508 | init_waitqueue_head(&joydev->wait); | 746 | init_waitqueue_head(&joydev->wait); |
| 509 | 747 | ||
| 748 | snprintf(joydev->name, sizeof(joydev->name), "js%d", minor); | ||
| 749 | joydev->exist = 1; | ||
| 510 | joydev->minor = minor; | 750 | joydev->minor = minor; |
| 751 | |||
| 511 | joydev->exist = 1; | 752 | joydev->exist = 1; |
| 512 | joydev->handle.dev = dev; | 753 | joydev->handle.dev = dev; |
| 513 | joydev->handle.name = joydev->name; | 754 | joydev->handle.name = joydev->name; |
| 514 | joydev->handle.handler = handler; | 755 | joydev->handle.handler = handler; |
| 515 | joydev->handle.private = joydev; | 756 | joydev->handle.private = joydev; |
| 516 | snprintf(joydev->name, sizeof(joydev->name), "js%d", minor); | ||
| 517 | 757 | ||
| 518 | for (i = 0; i < ABS_MAX + 1; i++) | 758 | for (i = 0; i < ABS_MAX + 1; i++) |
| 519 | if (test_bit(i, dev->absbit)) { | 759 | if (test_bit(i, dev->absbit)) { |
| @@ -545,67 +785,65 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev, | |||
| 545 | } | 785 | } |
| 546 | joydev->corr[i].type = JS_CORR_BROKEN; | 786 | joydev->corr[i].type = JS_CORR_BROKEN; |
| 547 | joydev->corr[i].prec = dev->absfuzz[j]; | 787 | joydev->corr[i].prec = dev->absfuzz[j]; |
| 548 | joydev->corr[i].coef[0] = (dev->absmax[j] + dev->absmin[j]) / 2 - dev->absflat[j]; | 788 | joydev->corr[i].coef[0] = |
| 549 | joydev->corr[i].coef[1] = (dev->absmax[j] + dev->absmin[j]) / 2 + dev->absflat[j]; | 789 | (dev->absmax[j] + dev->absmin[j]) / 2 - dev->absflat[j]; |
| 550 | if (!(t = ((dev->absmax[j] - dev->absmin[j]) / 2 - 2 * dev->absflat[j]))) | 790 | joydev->corr[i].coef[1] = |
| 551 | continue; | 791 | (dev->absmax[j] + dev->absmin[j]) / 2 + dev->absflat[j]; |
| 552 | joydev->corr[i].coef[2] = (1 << 29) / t; | 792 | |
| 553 | joydev->corr[i].coef[3] = (1 << 29) / t; | 793 | t = (dev->absmax[j] - dev->absmin[j]) / 2 - 2 * dev->absflat[j]; |
| 554 | 794 | if (t) { | |
| 555 | joydev->abs[i] = joydev_correct(dev->abs[j], joydev->corr + i); | 795 | joydev->corr[i].coef[2] = (1 << 29) / t; |
| 796 | joydev->corr[i].coef[3] = (1 << 29) / t; | ||
| 797 | |||
| 798 | joydev->abs[i] = joydev_correct(dev->abs[j], | ||
| 799 | joydev->corr + i); | ||
| 800 | } | ||
| 556 | } | 801 | } |
| 557 | 802 | ||
| 558 | snprintf(joydev->dev.bus_id, sizeof(joydev->dev.bus_id), | 803 | strlcpy(joydev->dev.bus_id, joydev->name, sizeof(joydev->dev.bus_id)); |
| 559 | "js%d", minor); | 804 | joydev->dev.devt = MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor); |
| 560 | joydev->dev.class = &input_class; | 805 | joydev->dev.class = &input_class; |
| 561 | joydev->dev.parent = &dev->dev; | 806 | joydev->dev.parent = &dev->dev; |
| 562 | joydev->dev.devt = MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor); | ||
| 563 | joydev->dev.release = joydev_free; | 807 | joydev->dev.release = joydev_free; |
| 564 | device_initialize(&joydev->dev); | 808 | device_initialize(&joydev->dev); |
| 565 | 809 | ||
| 566 | joydev_table[minor] = joydev; | 810 | error = input_register_handle(&joydev->handle); |
| 567 | |||
| 568 | error = device_add(&joydev->dev); | ||
| 569 | if (error) | 811 | if (error) |
| 570 | goto err_free_joydev; | 812 | goto err_free_joydev; |
| 571 | 813 | ||
| 572 | error = input_register_handle(&joydev->handle); | 814 | error = joydev_install_chrdev(joydev); |
| 573 | if (error) | 815 | if (error) |
| 574 | goto err_delete_joydev; | 816 | goto err_unregister_handle; |
| 817 | |||
| 818 | error = device_add(&joydev->dev); | ||
| 819 | if (error) | ||
| 820 | goto err_cleanup_joydev; | ||
| 575 | 821 | ||
| 576 | return 0; | 822 | return 0; |
| 577 | 823 | ||
| 578 | err_delete_joydev: | 824 | err_cleanup_joydev: |
| 579 | device_del(&joydev->dev); | 825 | joydev_cleanup(joydev); |
| 826 | err_unregister_handle: | ||
| 827 | input_unregister_handle(&joydev->handle); | ||
| 580 | err_free_joydev: | 828 | err_free_joydev: |
| 581 | put_device(&joydev->dev); | 829 | put_device(&joydev->dev); |
| 582 | return error; | 830 | return error; |
| 583 | } | 831 | } |
| 584 | 832 | ||
| 585 | |||
| 586 | static void joydev_disconnect(struct input_handle *handle) | 833 | static void joydev_disconnect(struct input_handle *handle) |
| 587 | { | 834 | { |
| 588 | struct joydev *joydev = handle->private; | 835 | struct joydev *joydev = handle->private; |
| 589 | struct joydev_client *client; | ||
| 590 | 836 | ||
| 591 | input_unregister_handle(handle); | ||
| 592 | device_del(&joydev->dev); | 837 | device_del(&joydev->dev); |
| 593 | 838 | joydev_cleanup(joydev); | |
| 594 | joydev->exist = 0; | 839 | input_unregister_handle(handle); |
| 595 | |||
| 596 | if (joydev->open) { | ||
| 597 | input_close_device(handle); | ||
| 598 | list_for_each_entry(client, &joydev->client_list, node) | ||
| 599 | kill_fasync(&client->fasync, SIGIO, POLL_HUP); | ||
| 600 | wake_up_interruptible(&joydev->wait); | ||
| 601 | } | ||
| 602 | |||
| 603 | put_device(&joydev->dev); | 840 | put_device(&joydev->dev); |
| 604 | } | 841 | } |
| 605 | 842 | ||
| 606 | static const struct input_device_id joydev_blacklist[] = { | 843 | static const struct input_device_id joydev_blacklist[] = { |
| 607 | { | 844 | { |
| 608 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, | 845 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | |
| 846 | INPUT_DEVICE_ID_MATCH_KEYBIT, | ||
| 609 | .evbit = { BIT(EV_KEY) }, | 847 | .evbit = { BIT(EV_KEY) }, |
| 610 | .keybit = { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) }, | 848 | .keybit = { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) }, |
| 611 | }, /* Avoid itouchpads, touchscreens and tablets */ | 849 | }, /* Avoid itouchpads, touchscreens and tablets */ |
| @@ -614,17 +852,20 @@ static const struct input_device_id joydev_blacklist[] = { | |||
| 614 | 852 | ||
| 615 | static const struct input_device_id joydev_ids[] = { | 853 | static const struct input_device_id joydev_ids[] = { |
| 616 | { | 854 | { |
| 617 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT, | 855 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | |
| 856 | INPUT_DEVICE_ID_MATCH_ABSBIT, | ||
| 618 | .evbit = { BIT(EV_ABS) }, | 857 | .evbit = { BIT(EV_ABS) }, |
| 619 | .absbit = { BIT(ABS_X) }, | 858 | .absbit = { BIT(ABS_X) }, |
| 620 | }, | 859 | }, |
| 621 | { | 860 | { |
| 622 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT, | 861 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | |
| 862 | INPUT_DEVICE_ID_MATCH_ABSBIT, | ||
| 623 | .evbit = { BIT(EV_ABS) }, | 863 | .evbit = { BIT(EV_ABS) }, |
| 624 | .absbit = { BIT(ABS_WHEEL) }, | 864 | .absbit = { BIT(ABS_WHEEL) }, |
| 625 | }, | 865 | }, |
| 626 | { | 866 | { |
| 627 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT, | 867 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | |
| 868 | INPUT_DEVICE_ID_MATCH_ABSBIT, | ||
| 628 | .evbit = { BIT(EV_ABS) }, | 869 | .evbit = { BIT(EV_ABS) }, |
| 629 | .absbit = { BIT(ABS_THROTTLE) }, | 870 | .absbit = { BIT(ABS_THROTTLE) }, |
| 630 | }, | 871 | }, |
| @@ -634,14 +875,14 @@ static const struct input_device_id joydev_ids[] = { | |||
| 634 | MODULE_DEVICE_TABLE(input, joydev_ids); | 875 | MODULE_DEVICE_TABLE(input, joydev_ids); |
| 635 | 876 | ||
| 636 | static struct input_handler joydev_handler = { | 877 | static struct input_handler joydev_handler = { |
| 637 | .event = joydev_event, | 878 | .event = joydev_event, |
| 638 | .connect = joydev_connect, | 879 | .connect = joydev_connect, |
| 639 | .disconnect = joydev_disconnect, | 880 | .disconnect = joydev_disconnect, |
| 640 | .fops = &joydev_fops, | 881 | .fops = &joydev_fops, |
| 641 | .minor = JOYDEV_MINOR_BASE, | 882 | .minor = JOYDEV_MINOR_BASE, |
| 642 | .name = "joydev", | 883 | .name = "joydev", |
| 643 | .id_table = joydev_ids, | 884 | .id_table = joydev_ids, |
| 644 | .blacklist = joydev_blacklist, | 885 | .blacklist = joydev_blacklist, |
| 645 | }; | 886 | }; |
| 646 | 887 | ||
| 647 | static int __init joydev_init(void) | 888 | static int __init joydev_init(void) |
diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index 28080395899c..623629a69b03 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c | |||
| @@ -223,12 +223,16 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d | |||
| 223 | struct input_dev *dev = xpad->dev; | 223 | struct input_dev *dev = xpad->dev; |
| 224 | 224 | ||
| 225 | /* left stick */ | 225 | /* left stick */ |
| 226 | input_report_abs(dev, ABS_X, (__s16) (((__s16)data[13] << 8) | data[12])); | 226 | input_report_abs(dev, ABS_X, |
| 227 | input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[15] << 8) | data[14])); | 227 | (__s16) le16_to_cpup((__le16 *)(data + 12))); |
| 228 | input_report_abs(dev, ABS_Y, | ||
| 229 | (__s16) le16_to_cpup((__le16 *)(data + 14))); | ||
| 228 | 230 | ||
| 229 | /* right stick */ | 231 | /* right stick */ |
| 230 | input_report_abs(dev, ABS_RX, (__s16) (((__s16)data[17] << 8) | data[16])); | 232 | input_report_abs(dev, ABS_RX, |
| 231 | input_report_abs(dev, ABS_RY, (__s16) (((__s16)data[19] << 8) | data[18])); | 233 | (__s16) le16_to_cpup((__le16 *)(data + 16))); |
| 234 | input_report_abs(dev, ABS_RY, | ||
| 235 | (__s16) le16_to_cpup((__le16 *)(data + 18))); | ||
| 232 | 236 | ||
| 233 | /* triggers left/right */ | 237 | /* triggers left/right */ |
| 234 | input_report_abs(dev, ABS_Z, data[10]); | 238 | input_report_abs(dev, ABS_Z, data[10]); |
| @@ -236,8 +240,10 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d | |||
| 236 | 240 | ||
| 237 | /* digital pad */ | 241 | /* digital pad */ |
| 238 | if (xpad->dpad_mapping == MAP_DPAD_TO_AXES) { | 242 | if (xpad->dpad_mapping == MAP_DPAD_TO_AXES) { |
| 239 | input_report_abs(dev, ABS_HAT0X, !!(data[2] & 0x08) - !!(data[2] & 0x04)); | 243 | input_report_abs(dev, ABS_HAT0X, |
| 240 | input_report_abs(dev, ABS_HAT0Y, !!(data[2] & 0x02) - !!(data[2] & 0x01)); | 244 | !!(data[2] & 0x08) - !!(data[2] & 0x04)); |
| 245 | input_report_abs(dev, ABS_HAT0Y, | ||
| 246 | !!(data[2] & 0x02) - !!(data[2] & 0x01)); | ||
| 241 | } else /* xpad->dpad_mapping == MAP_DPAD_TO_BUTTONS */ { | 247 | } else /* xpad->dpad_mapping == MAP_DPAD_TO_BUTTONS */ { |
| 242 | input_report_key(dev, BTN_LEFT, data[2] & 0x04); | 248 | input_report_key(dev, BTN_LEFT, data[2] & 0x04); |
| 243 | input_report_key(dev, BTN_RIGHT, data[2] & 0x08); | 249 | input_report_key(dev, BTN_RIGHT, data[2] & 0x08); |
| @@ -274,14 +280,17 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d | |||
| 274 | * http://www.free60.org/wiki/Gamepad | 280 | * http://www.free60.org/wiki/Gamepad |
| 275 | */ | 281 | */ |
| 276 | 282 | ||
| 277 | static void xpad360_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data) | 283 | static void xpad360_process_packet(struct usb_xpad *xpad, |
| 284 | u16 cmd, unsigned char *data) | ||
| 278 | { | 285 | { |
| 279 | struct input_dev *dev = xpad->dev; | 286 | struct input_dev *dev = xpad->dev; |
| 280 | 287 | ||
| 281 | /* digital pad */ | 288 | /* digital pad */ |
| 282 | if (xpad->dpad_mapping == MAP_DPAD_TO_AXES) { | 289 | if (xpad->dpad_mapping == MAP_DPAD_TO_AXES) { |
| 283 | input_report_abs(dev, ABS_HAT0X, !!(data[2] & 0x08) - !!(data[2] & 0x04)); | 290 | input_report_abs(dev, ABS_HAT0X, |
| 284 | input_report_abs(dev, ABS_HAT0Y, !!(data[2] & 0x02) - !!(data[2] & 0x01)); | 291 | !!(data[2] & 0x08) - !!(data[2] & 0x04)); |
| 292 | input_report_abs(dev, ABS_HAT0Y, | ||
| 293 | !!(data[2] & 0x02) - !!(data[2] & 0x01)); | ||
| 285 | } else if (xpad->dpad_mapping == MAP_DPAD_TO_BUTTONS) { | 294 | } else if (xpad->dpad_mapping == MAP_DPAD_TO_BUTTONS) { |
| 286 | /* dpad as buttons (right, left, down, up) */ | 295 | /* dpad as buttons (right, left, down, up) */ |
| 287 | input_report_key(dev, BTN_LEFT, data[2] & 0x04); | 296 | input_report_key(dev, BTN_LEFT, data[2] & 0x04); |
| @@ -308,12 +317,16 @@ static void xpad360_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char | |||
| 308 | input_report_key(dev, BTN_MODE, data[3] & 0x04); | 317 | input_report_key(dev, BTN_MODE, data[3] & 0x04); |
| 309 | 318 | ||
| 310 | /* left stick */ | 319 | /* left stick */ |
| 311 | input_report_abs(dev, ABS_X, (__s16) (((__s16)data[7] << 8) | (__s16)data[6])); | 320 | input_report_abs(dev, ABS_X, |
| 312 | input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[9] << 8) | (__s16)data[8])); | 321 | (__s16) le16_to_cpup((__le16 *)(data + 6))); |
| 322 | input_report_abs(dev, ABS_Y, | ||
| 323 | (__s16) le16_to_cpup((__le16 *)(data + 8))); | ||
| 313 | 324 | ||
| 314 | /* right stick */ | 325 | /* right stick */ |
| 315 | input_report_abs(dev, ABS_RX, (__s16) (((__s16)data[11] << 8) | (__s16)data[10])); | 326 | input_report_abs(dev, ABS_RX, |
| 316 | input_report_abs(dev, ABS_RY, (__s16) (((__s16)data[13] << 8) | (__s16)data[12])); | 327 | (__s16) le16_to_cpup((__le16 *)(data + 10))); |
| 328 | input_report_abs(dev, ABS_RY, | ||
| 329 | (__s16) le16_to_cpup((__le16 *)(data + 12))); | ||
| 317 | 330 | ||
| 318 | /* triggers left/right */ | 331 | /* triggers left/right */ |
| 319 | input_report_abs(dev, ABS_Z, data[4]); | 332 | input_report_abs(dev, ABS_Z, data[4]); |
| @@ -335,10 +348,12 @@ static void xpad_irq_in(struct urb *urb) | |||
| 335 | case -ENOENT: | 348 | case -ENOENT: |
| 336 | case -ESHUTDOWN: | 349 | case -ESHUTDOWN: |
| 337 | /* this urb is terminated, clean up */ | 350 | /* this urb is terminated, clean up */ |
| 338 | dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status); | 351 | dbg("%s - urb shutting down with status: %d", |
| 352 | __FUNCTION__, urb->status); | ||
| 339 | return; | 353 | return; |
| 340 | default: | 354 | default: |
| 341 | dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status); | 355 | dbg("%s - nonzero urb status received: %d", |
| 356 | __FUNCTION__, urb->status); | ||
| 342 | goto exit; | 357 | goto exit; |
| 343 | } | 358 | } |
| 344 | 359 | ||
| @@ -367,10 +382,12 @@ static void xpad_irq_out(struct urb *urb) | |||
| 367 | case -ENOENT: | 382 | case -ENOENT: |
| 368 | case -ESHUTDOWN: | 383 | case -ESHUTDOWN: |
| 369 | /* this urb is terminated, clean up */ | 384 | /* this urb is terminated, clean up */ |
| 370 | dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status); | 385 | dbg("%s - urb shutting down with status: %d", |
| 386 | __FUNCTION__, urb->status); | ||
| 371 | return; | 387 | return; |
| 372 | default: | 388 | default: |
| 373 | dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status); | 389 | dbg("%s - nonzero urb status received: %d", |
| 390 | __FUNCTION__, urb->status); | ||
| 374 | goto exit; | 391 | goto exit; |
| 375 | } | 392 | } |
| 376 | 393 | ||
| @@ -378,7 +395,7 @@ exit: | |||
| 378 | retval = usb_submit_urb(urb, GFP_ATOMIC); | 395 | retval = usb_submit_urb(urb, GFP_ATOMIC); |
| 379 | if (retval) | 396 | if (retval) |
| 380 | err("%s - usb_submit_urb failed with result %d", | 397 | err("%s - usb_submit_urb failed with result %d", |
| 381 | __FUNCTION__, retval); | 398 | __FUNCTION__, retval); |
| 382 | } | 399 | } |
| 383 | 400 | ||
| 384 | static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad) | 401 | static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad) |
| @@ -595,7 +612,7 @@ static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs) | |||
| 595 | 612 | ||
| 596 | static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id) | 613 | static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id) |
| 597 | { | 614 | { |
| 598 | struct usb_device *udev = interface_to_usbdev (intf); | 615 | struct usb_device *udev = interface_to_usbdev(intf); |
| 599 | struct usb_xpad *xpad; | 616 | struct usb_xpad *xpad; |
| 600 | struct input_dev *input_dev; | 617 | struct input_dev *input_dev; |
| 601 | struct usb_endpoint_descriptor *ep_irq_in; | 618 | struct usb_endpoint_descriptor *ep_irq_in; |
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index c97d5eb0075d..2316a018fae6 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig | |||
| @@ -208,6 +208,27 @@ config KEYBOARD_HIL | |||
| 208 | This driver implements support for HIL-keyboards attached | 208 | This driver implements support for HIL-keyboards attached |
| 209 | to your machine, so normally you should say Y here. | 209 | to your machine, so normally you should say Y here. |
| 210 | 210 | ||
| 211 | config KEYBOARD_HP6XX | ||
| 212 | tristate "HP Jornada 6XX Keyboard support" | ||
| 213 | depends on SH_HP6XX | ||
| 214 | select INPUT_POLLDEV | ||
| 215 | help | ||
| 216 | This adds support for the onboard keyboard found on | ||
| 217 | HP Jornada 620/660/680/690. | ||
| 218 | |||
| 219 | To compile this driver as a module, choose M here: the | ||
| 220 | module will be called jornada680_kbd. | ||
| 221 | |||
| 222 | config KEYBOARD_HP7XX | ||
| 223 | tristate "HP Jornada 7XX Keyboard Driver" | ||
| 224 | depends on SA1100_JORNADA720_SSP && SA1100_SSP | ||
| 225 | help | ||
| 226 | Say Y here to add support for the HP Jornada 7xx (710/720/728) | ||
| 227 | onboard keyboard. | ||
| 228 | |||
| 229 | To compile this driver as a module, choose M here: the | ||
| 230 | module will be called jornada720_kbd. | ||
| 231 | |||
| 211 | config KEYBOARD_OMAP | 232 | config KEYBOARD_OMAP |
| 212 | tristate "TI OMAP keypad support" | 233 | tristate "TI OMAP keypad support" |
| 213 | depends on (ARCH_OMAP1 || ARCH_OMAP2) | 234 | depends on (ARCH_OMAP1 || ARCH_OMAP2) |
| @@ -253,4 +274,23 @@ config KEYBOARD_GPIO | |||
| 253 | To compile this driver as a module, choose M here: the | 274 | To compile this driver as a module, choose M here: the |
| 254 | module will be called gpio-keys. | 275 | module will be called gpio-keys. |
| 255 | 276 | ||
| 277 | config KEYBOARD_MAPLE | ||
| 278 | tristate "Maple bus keyboard" | ||
| 279 | depends on SH_DREAMCAST && MAPLE | ||
| 280 | help | ||
| 281 | Say Y here if you have a Dreamcast console running Linux and have | ||
| 282 | a keyboard attached to its Maple bus. | ||
| 283 | |||
| 284 | To compile this driver as a module, choose M here: the | ||
| 285 | module will be called maple_keyb. | ||
| 286 | |||
| 287 | config KEYBOARD_BFIN | ||
| 288 | tristate "Blackfin BF54x keypad support" | ||
| 289 | depends on BF54x | ||
| 290 | help | ||
| 291 | Say Y here if you want to use the BF54x keypad. | ||
| 292 | |||
| 293 | To compile this driver as a module, choose M here: the | ||
| 294 | module will be called bf54x-keys. | ||
| 295 | |||
| 256 | endif | 296 | endif |
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index 28d211b87b14..e97455fdcc83 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile | |||
| @@ -21,4 +21,7 @@ obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o | |||
| 21 | obj-$(CONFIG_KEYBOARD_PXA27x) += pxa27x_keyboard.o | 21 | obj-$(CONFIG_KEYBOARD_PXA27x) += pxa27x_keyboard.o |
| 22 | obj-$(CONFIG_KEYBOARD_AAED2000) += aaed2000_kbd.o | 22 | obj-$(CONFIG_KEYBOARD_AAED2000) += aaed2000_kbd.o |
| 23 | obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o | 23 | obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o |
| 24 | 24 | obj-$(CONFIG_KEYBOARD_HP6XX) += jornada680_kbd.o | |
| 25 | obj-$(CONFIG_KEYBOARD_HP7XX) += jornada720_kbd.o | ||
| 26 | obj-$(CONFIG_KEYBOARD_MAPLE) += maple_keyb.o | ||
| 27 | obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o | ||
diff --git a/drivers/input/keyboard/atakbd.c b/drivers/input/keyboard/atakbd.c index f948d3a14a93..a1800151b6ce 100644 --- a/drivers/input/keyboard/atakbd.c +++ b/drivers/input/keyboard/atakbd.c | |||
| @@ -217,7 +217,7 @@ static void atakbd_interrupt(unsigned char scancode, char down) | |||
| 217 | 217 | ||
| 218 | static int __init atakbd_init(void) | 218 | static int __init atakbd_init(void) |
| 219 | { | 219 | { |
| 220 | int i; | 220 | int i, error; |
| 221 | 221 | ||
| 222 | if (!MACH_IS_ATARI || !ATARIHW_PRESENT(ST_MFP)) | 222 | if (!MACH_IS_ATARI || !ATARIHW_PRESENT(ST_MFP)) |
| 223 | return -EIO; | 223 | return -EIO; |
| @@ -247,9 +247,10 @@ static int __init atakbd_init(void) | |||
| 247 | } | 247 | } |
| 248 | 248 | ||
| 249 | /* error check */ | 249 | /* error check */ |
| 250 | if (input_register_device(atakbd_dev)) { | 250 | error = input_register_device(atakbd_dev); |
| 251 | if (error) { | ||
| 251 | input_free_device(atakbd_dev); | 252 | input_free_device(atakbd_dev); |
| 252 | return -ENOMEM; | 253 | return error; |
| 253 | } | 254 | } |
| 254 | 255 | ||
| 255 | atari_input_keyboard_interrupt_hook = atakbd_interrupt; | 256 | atari_input_keyboard_interrupt_hook = atakbd_interrupt; |
diff --git a/drivers/input/keyboard/bf54x-keys.c b/drivers/input/keyboard/bf54x-keys.c new file mode 100644 index 000000000000..a67b29b089ef --- /dev/null +++ b/drivers/input/keyboard/bf54x-keys.c | |||
| @@ -0,0 +1,382 @@ | |||
| 1 | /* | ||
| 2 | * File: drivers/input/keyboard/bf54x-keys.c | ||
| 3 | * Based on: | ||
| 4 | * Author: Michael Hennerich <hennerich@blackfin.uclinux.org> | ||
| 5 | * | ||
| 6 | * Created: | ||
| 7 | * Description: keypad driver for Analog Devices Blackfin BF54x Processors | ||
| 8 | * | ||
| 9 | * | ||
| 10 | * Modified: | ||
| 11 | * Copyright 2007 Analog Devices Inc. | ||
| 12 | * | ||
| 13 | * Bugs: Enter bugs at http://blackfin.uclinux.org/ | ||
| 14 | * | ||
| 15 | * This program is free software; you can redistribute it and/or modify | ||
| 16 | * it under the terms of the GNU General Public License as published by | ||
| 17 | * the Free Software Foundation; either version 2 of the License, or | ||
| 18 | * (at your option) any later version. | ||
| 19 | * | ||
| 20 | * This program is distributed in the hope that it will be useful, | ||
| 21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 23 | * GNU General Public License for more details. | ||
| 24 | * | ||
| 25 | * You should have received a copy of the GNU General Public License | ||
| 26 | * along with this program; if not, see the file COPYING, or write | ||
| 27 | * to the Free Software Foundation, Inc., | ||
| 28 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 29 | */ | ||
| 30 | |||
| 31 | #include <linux/module.h> | ||
| 32 | #include <linux/version.h> | ||
| 33 | |||
| 34 | #include <linux/init.h> | ||
| 35 | #include <linux/fs.h> | ||
| 36 | #include <linux/interrupt.h> | ||
| 37 | #include <linux/irq.h> | ||
| 38 | #include <linux/sched.h> | ||
| 39 | #include <linux/pm.h> | ||
| 40 | #include <linux/sysctl.h> | ||
| 41 | #include <linux/proc_fs.h> | ||
| 42 | #include <linux/delay.h> | ||
| 43 | #include <linux/platform_device.h> | ||
| 44 | #include <linux/input.h> | ||
| 45 | #include <linux/irq.h> | ||
| 46 | |||
| 47 | #include <asm/portmux.h> | ||
| 48 | #include <asm/mach/bf54x_keys.h> | ||
| 49 | |||
| 50 | #define DRV_NAME "bf54x-keys" | ||
| 51 | #define TIME_SCALE 100 /* 100 ns */ | ||
| 52 | #define MAX_MULT (0xFF * TIME_SCALE) | ||
| 53 | #define MAX_RC 8 /* Max Row/Col */ | ||
| 54 | |||
| 55 | static const u16 per_rows[] = { | ||
| 56 | P_KEY_ROW7, | ||
| 57 | P_KEY_ROW6, | ||
| 58 | P_KEY_ROW5, | ||
| 59 | P_KEY_ROW4, | ||
| 60 | P_KEY_ROW3, | ||
| 61 | P_KEY_ROW2, | ||
| 62 | P_KEY_ROW1, | ||
| 63 | P_KEY_ROW0, | ||
| 64 | 0 | ||
| 65 | }; | ||
| 66 | |||
| 67 | static const u16 per_cols[] = { | ||
| 68 | P_KEY_COL7, | ||
| 69 | P_KEY_COL6, | ||
| 70 | P_KEY_COL5, | ||
| 71 | P_KEY_COL4, | ||
| 72 | P_KEY_COL3, | ||
| 73 | P_KEY_COL2, | ||
| 74 | P_KEY_COL1, | ||
| 75 | P_KEY_COL0, | ||
| 76 | 0 | ||
| 77 | }; | ||
| 78 | |||
| 79 | struct bf54x_kpad { | ||
| 80 | struct input_dev *input; | ||
| 81 | int irq; | ||
| 82 | unsigned short lastkey; | ||
| 83 | unsigned short *keycode; | ||
| 84 | struct timer_list timer; | ||
| 85 | unsigned int keyup_test_jiffies; | ||
| 86 | }; | ||
| 87 | |||
| 88 | static inline int bfin_kpad_find_key(struct bf54x_kpad *bf54x_kpad, | ||
| 89 | struct input_dev *input, u16 keyident) | ||
| 90 | { | ||
| 91 | u16 i; | ||
| 92 | |||
| 93 | for (i = 0; i < input->keycodemax; i++) | ||
| 94 | if (bf54x_kpad->keycode[i + input->keycodemax] == keyident) | ||
| 95 | return bf54x_kpad->keycode[i]; | ||
| 96 | return -1; | ||
| 97 | } | ||
| 98 | |||
| 99 | static inline void bfin_keycodecpy(unsigned short *keycode, | ||
| 100 | const unsigned int *pdata_kc, | ||
| 101 | unsigned short keymapsize) | ||
| 102 | { | ||
| 103 | unsigned int i; | ||
| 104 | |||
| 105 | for (i = 0; i < keymapsize; i++) { | ||
| 106 | keycode[i] = pdata_kc[i] & 0xffff; | ||
| 107 | keycode[i + keymapsize] = pdata_kc[i] >> 16; | ||
| 108 | } | ||
| 109 | } | ||
| 110 | |||
| 111 | static inline u16 bfin_kpad_get_prescale(u32 timescale) | ||
| 112 | { | ||
| 113 | u32 sclk = get_sclk(); | ||
| 114 | |||
| 115 | return ((((sclk / 1000) * timescale) / 1024) - 1); | ||
| 116 | } | ||
| 117 | |||
| 118 | static inline u16 bfin_kpad_get_keypressed(struct bf54x_kpad *bf54x_kpad) | ||
| 119 | { | ||
| 120 | return (bfin_read_KPAD_STAT() & KPAD_PRESSED); | ||
| 121 | } | ||
| 122 | |||
| 123 | static inline void bfin_kpad_clear_irq(void) | ||
| 124 | { | ||
| 125 | bfin_write_KPAD_STAT(0xFFFF); | ||
| 126 | bfin_write_KPAD_ROWCOL(0xFFFF); | ||
| 127 | } | ||
| 128 | |||
| 129 | static void bfin_kpad_timer(unsigned long data) | ||
| 130 | { | ||
| 131 | struct platform_device *pdev = (struct platform_device *) data; | ||
| 132 | struct bf54x_kpad *bf54x_kpad = platform_get_drvdata(pdev); | ||
| 133 | |||
| 134 | if (bfin_kpad_get_keypressed(bf54x_kpad)) { | ||
| 135 | /* Try again later */ | ||
| 136 | mod_timer(&bf54x_kpad->timer, | ||
| 137 | jiffies + bf54x_kpad->keyup_test_jiffies); | ||
| 138 | return; | ||
| 139 | } | ||
| 140 | |||
| 141 | input_report_key(bf54x_kpad->input, bf54x_kpad->lastkey, 0); | ||
| 142 | input_sync(bf54x_kpad->input); | ||
| 143 | |||
| 144 | /* Clear IRQ Status */ | ||
| 145 | |||
| 146 | bfin_kpad_clear_irq(); | ||
| 147 | enable_irq(bf54x_kpad->irq); | ||
| 148 | } | ||
| 149 | |||
| 150 | static irqreturn_t bfin_kpad_isr(int irq, void *dev_id) | ||
| 151 | { | ||
| 152 | struct platform_device *pdev = dev_id; | ||
| 153 | struct bf54x_kpad *bf54x_kpad = platform_get_drvdata(pdev); | ||
| 154 | struct input_dev *input = bf54x_kpad->input; | ||
| 155 | int key; | ||
| 156 | u16 rowcol = bfin_read_KPAD_ROWCOL(); | ||
| 157 | |||
| 158 | key = bfin_kpad_find_key(bf54x_kpad, input, rowcol); | ||
| 159 | |||
| 160 | input_report_key(input, key, 1); | ||
| 161 | input_sync(input); | ||
| 162 | |||
| 163 | if (bfin_kpad_get_keypressed(bf54x_kpad)) { | ||
| 164 | disable_irq(bf54x_kpad->irq); | ||
| 165 | bf54x_kpad->lastkey = key; | ||
| 166 | mod_timer(&bf54x_kpad->timer, | ||
| 167 | jiffies + bf54x_kpad->keyup_test_jiffies); | ||
| 168 | } else { | ||
| 169 | input_report_key(input, key, 0); | ||
| 170 | input_sync(input); | ||
| 171 | |||
| 172 | bfin_kpad_clear_irq(); | ||
| 173 | } | ||
| 174 | |||
| 175 | return IRQ_HANDLED; | ||
| 176 | } | ||
| 177 | |||
| 178 | static int __devinit bfin_kpad_probe(struct platform_device *pdev) | ||
| 179 | { | ||
| 180 | struct bf54x_kpad *bf54x_kpad; | ||
| 181 | struct bfin_kpad_platform_data *pdata = pdev->dev.platform_data; | ||
| 182 | struct input_dev *input; | ||
| 183 | int i, error; | ||
| 184 | |||
| 185 | if (!pdata->rows || !pdata->cols || !pdata->keymap) { | ||
| 186 | printk(KERN_ERR DRV_NAME | ||
| 187 | ": No rows, cols or keymap from pdata\n"); | ||
| 188 | return -EINVAL; | ||
| 189 | } | ||
| 190 | |||
| 191 | if (!pdata->keymapsize || | ||
| 192 | pdata->keymapsize > (pdata->rows * pdata->cols)) { | ||
| 193 | printk(KERN_ERR DRV_NAME ": Invalid keymapsize\n"); | ||
| 194 | return -EINVAL; | ||
| 195 | } | ||
| 196 | |||
| 197 | bf54x_kpad = kzalloc(sizeof(struct bf54x_kpad), GFP_KERNEL); | ||
| 198 | if (!bf54x_kpad) | ||
| 199 | return -ENOMEM; | ||
| 200 | |||
| 201 | platform_set_drvdata(pdev, bf54x_kpad); | ||
| 202 | |||
| 203 | /* Allocate memory for keymap followed by private LUT */ | ||
| 204 | bf54x_kpad->keycode = kmalloc(pdata->keymapsize * | ||
| 205 | sizeof(unsigned short) * 2, GFP_KERNEL); | ||
| 206 | if (!bf54x_kpad->keycode) { | ||
| 207 | error = -ENOMEM; | ||
| 208 | goto out; | ||
| 209 | } | ||
| 210 | |||
| 211 | if (!pdata->debounce_time || !pdata->debounce_time > MAX_MULT || | ||
| 212 | !pdata->coldrive_time || !pdata->coldrive_time > MAX_MULT) { | ||
| 213 | printk(KERN_ERR DRV_NAME | ||
| 214 | ": Invalid Debounce/Columdrive Time from pdata\n"); | ||
| 215 | bfin_write_KPAD_MSEL(0xFF0); /* Default MSEL */ | ||
| 216 | } else { | ||
| 217 | bfin_write_KPAD_MSEL( | ||
| 218 | ((pdata->debounce_time / TIME_SCALE) | ||
| 219 | & DBON_SCALE) | | ||
| 220 | (((pdata->coldrive_time / TIME_SCALE) << 8) | ||
| 221 | & COLDRV_SCALE)); | ||
| 222 | |||
| 223 | } | ||
| 224 | |||
| 225 | if (!pdata->keyup_test_interval) | ||
| 226 | bf54x_kpad->keyup_test_jiffies = msecs_to_jiffies(50); | ||
| 227 | else | ||
| 228 | bf54x_kpad->keyup_test_jiffies = | ||
| 229 | msecs_to_jiffies(pdata->keyup_test_interval); | ||
| 230 | |||
| 231 | if (peripheral_request_list((u16 *)&per_rows[MAX_RC - pdata->rows], | ||
| 232 | DRV_NAME)) { | ||
| 233 | printk(KERN_ERR DRV_NAME | ||
| 234 | ": Requesting Peripherals failed\n"); | ||
| 235 | error = -EFAULT; | ||
| 236 | goto out0; | ||
| 237 | } | ||
| 238 | |||
| 239 | if (peripheral_request_list((u16 *)&per_cols[MAX_RC - pdata->cols], | ||
| 240 | DRV_NAME)) { | ||
| 241 | printk(KERN_ERR DRV_NAME | ||
| 242 | ": Requesting Peripherals failed\n"); | ||
| 243 | error = -EFAULT; | ||
| 244 | goto out1; | ||
| 245 | } | ||
| 246 | |||
| 247 | bf54x_kpad->irq = platform_get_irq(pdev, 0); | ||
| 248 | if (bf54x_kpad->irq < 0) { | ||
| 249 | error = -ENODEV; | ||
| 250 | goto out2; | ||
| 251 | } | ||
| 252 | |||
| 253 | error = request_irq(bf54x_kpad->irq, bfin_kpad_isr, | ||
| 254 | IRQF_SAMPLE_RANDOM, DRV_NAME, pdev); | ||
| 255 | if (error) { | ||
| 256 | printk(KERN_ERR DRV_NAME | ||
| 257 | ": unable to claim irq %d; error %d\n", | ||
| 258 | bf54x_kpad->irq, error); | ||
| 259 | error = -EBUSY; | ||
| 260 | goto out2; | ||
| 261 | } | ||
| 262 | |||
| 263 | input = input_allocate_device(); | ||
| 264 | if (!input) { | ||
| 265 | error = -ENOMEM; | ||
| 266 | goto out3; | ||
| 267 | } | ||
| 268 | |||
| 269 | bf54x_kpad->input = input; | ||
| 270 | |||
| 271 | input->name = pdev->name; | ||
| 272 | input->phys = "bf54x-keys/input0"; | ||
| 273 | input->dev.parent = &pdev->dev; | ||
| 274 | |||
| 275 | input_set_drvdata(input, bf54x_kpad); | ||
| 276 | |||
| 277 | input->id.bustype = BUS_HOST; | ||
| 278 | input->id.vendor = 0x0001; | ||
| 279 | input->id.product = 0x0001; | ||
| 280 | input->id.version = 0x0100; | ||
| 281 | |||
| 282 | input->keycodesize = sizeof(unsigned short); | ||
| 283 | input->keycodemax = pdata->keymapsize; | ||
| 284 | input->keycode = bf54x_kpad->keycode; | ||
| 285 | |||
| 286 | bfin_keycodecpy(bf54x_kpad->keycode, pdata->keymap, pdata->keymapsize); | ||
| 287 | |||
| 288 | /* setup input device */ | ||
| 289 | __set_bit(EV_KEY, input->evbit); | ||
| 290 | |||
| 291 | if (pdata->repeat) | ||
| 292 | __set_bit(EV_REP, input->evbit); | ||
| 293 | |||
| 294 | for (i = 0; i < input->keycodemax; i++) | ||
| 295 | __set_bit(bf54x_kpad->keycode[i] & KEY_MAX, input->keybit); | ||
| 296 | __clear_bit(KEY_RESERVED, input->keybit); | ||
| 297 | |||
| 298 | error = input_register_device(input); | ||
| 299 | if (error) { | ||
| 300 | printk(KERN_ERR DRV_NAME | ||
| 301 | ": Unable to register input device (%d)\n", error); | ||
| 302 | goto out4; | ||
| 303 | } | ||
| 304 | |||
| 305 | /* Init Keypad Key Up/Release test timer */ | ||
| 306 | |||
| 307 | setup_timer(&bf54x_kpad->timer, bfin_kpad_timer, (unsigned long) pdev); | ||
| 308 | |||
| 309 | bfin_write_KPAD_PRESCALE(bfin_kpad_get_prescale(TIME_SCALE)); | ||
| 310 | |||
| 311 | bfin_write_KPAD_CTL((((pdata->cols - 1) << 13) & KPAD_COLEN) | | ||
| 312 | (((pdata->rows - 1) << 10) & KPAD_ROWEN) | | ||
| 313 | (2 & KPAD_IRQMODE)); | ||
| 314 | |||
| 315 | bfin_write_KPAD_CTL(bfin_read_KPAD_CTL() | KPAD_EN); | ||
| 316 | |||
| 317 | printk(KERN_ERR DRV_NAME | ||
| 318 | ": Blackfin BF54x Keypad registered IRQ %d\n", bf54x_kpad->irq); | ||
| 319 | |||
| 320 | return 0; | ||
| 321 | |||
| 322 | out4: | ||
| 323 | input_free_device(input); | ||
| 324 | out3: | ||
| 325 | free_irq(bf54x_kpad->irq, pdev); | ||
| 326 | out2: | ||
| 327 | peripheral_free_list((u16 *)&per_cols[MAX_RC - pdata->cols]); | ||
| 328 | out1: | ||
| 329 | peripheral_free_list((u16 *)&per_rows[MAX_RC - pdata->rows]); | ||
| 330 | out0: | ||
| 331 | kfree(bf54x_kpad->keycode); | ||
| 332 | out: | ||
| 333 | kfree(bf54x_kpad); | ||
| 334 | platform_set_drvdata(pdev, NULL); | ||
| 335 | |||
| 336 | return error; | ||
| 337 | } | ||
| 338 | |||
| 339 | static int __devexit bfin_kpad_remove(struct platform_device *pdev) | ||
| 340 | { | ||
| 341 | struct bfin_kpad_platform_data *pdata = pdev->dev.platform_data; | ||
| 342 | struct bf54x_kpad *bf54x_kpad = platform_get_drvdata(pdev); | ||
| 343 | |||
| 344 | del_timer_sync(&bf54x_kpad->timer); | ||
| 345 | free_irq(bf54x_kpad->irq, pdev); | ||
| 346 | |||
| 347 | input_unregister_device(bf54x_kpad->input); | ||
| 348 | |||
| 349 | peripheral_free_list((u16 *)&per_rows[MAX_RC - pdata->rows]); | ||
| 350 | peripheral_free_list((u16 *)&per_cols[MAX_RC - pdata->cols]); | ||
| 351 | |||
| 352 | kfree(bf54x_kpad->keycode); | ||
| 353 | kfree(bf54x_kpad); | ||
| 354 | platform_set_drvdata(pdev, NULL); | ||
| 355 | |||
| 356 | return 0; | ||
| 357 | } | ||
| 358 | |||
| 359 | struct platform_driver bfin_kpad_device_driver = { | ||
| 360 | .probe = bfin_kpad_probe, | ||
| 361 | .remove = __devexit_p(bfin_kpad_remove), | ||
| 362 | .driver = { | ||
| 363 | .name = DRV_NAME, | ||
| 364 | } | ||
| 365 | }; | ||
| 366 | |||
| 367 | static int __init bfin_kpad_init(void) | ||
| 368 | { | ||
| 369 | return platform_driver_register(&bfin_kpad_device_driver); | ||
| 370 | } | ||
| 371 | |||
| 372 | static void __exit bfin_kpad_exit(void) | ||
| 373 | { | ||
| 374 | platform_driver_unregister(&bfin_kpad_device_driver); | ||
| 375 | } | ||
| 376 | |||
| 377 | module_init(bfin_kpad_init); | ||
| 378 | module_exit(bfin_kpad_exit); | ||
| 379 | |||
| 380 | MODULE_LICENSE("GPL"); | ||
| 381 | MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); | ||
| 382 | MODULE_DESCRIPTION("Keypad driver for BF54x Processors"); | ||
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index f0b22b8b2769..e2a3293bc67e 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c | |||
| @@ -54,6 +54,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev) | |||
| 54 | struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; | 54 | struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; |
| 55 | struct input_dev *input; | 55 | struct input_dev *input; |
| 56 | int i, error; | 56 | int i, error; |
| 57 | int wakeup = 0; | ||
| 57 | 58 | ||
| 58 | input = input_allocate_device(); | 59 | input = input_allocate_device(); |
| 59 | if (!input) | 60 | if (!input) |
| @@ -77,31 +78,51 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev) | |||
| 77 | int irq = gpio_to_irq(button->gpio); | 78 | int irq = gpio_to_irq(button->gpio); |
| 78 | unsigned int type = button->type ?: EV_KEY; | 79 | unsigned int type = button->type ?: EV_KEY; |
| 79 | 80 | ||
| 80 | set_irq_type(irq, IRQ_TYPE_EDGE_BOTH); | 81 | if (irq < 0) { |
| 81 | error = request_irq(irq, gpio_keys_isr, IRQF_SAMPLE_RANDOM, | 82 | error = irq; |
| 82 | button->desc ? button->desc : "gpio_keys", | 83 | printk(KERN_ERR |
| 83 | pdev); | 84 | "gpio-keys: " |
| 85 | "Unable to get irq number for GPIO %d," | ||
| 86 | "error %d\n", | ||
| 87 | button->gpio, error); | ||
| 88 | goto fail; | ||
| 89 | } | ||
| 90 | |||
| 91 | error = request_irq(irq, gpio_keys_isr, | ||
| 92 | IRQF_SAMPLE_RANDOM | IRQF_TRIGGER_RISING | | ||
| 93 | IRQF_TRIGGER_FALLING, | ||
| 94 | button->desc ? button->desc : "gpio_keys", | ||
| 95 | pdev); | ||
| 84 | if (error) { | 96 | if (error) { |
| 85 | printk(KERN_ERR "gpio-keys: unable to claim irq %d; error %d\n", | 97 | printk(KERN_ERR |
| 98 | "gpio-keys: Unable to claim irq %d; error %d\n", | ||
| 86 | irq, error); | 99 | irq, error); |
| 87 | goto fail; | 100 | goto fail; |
| 88 | } | 101 | } |
| 89 | 102 | ||
| 103 | if (button->wakeup) | ||
| 104 | wakeup = 1; | ||
| 105 | |||
| 90 | input_set_capability(input, type, button->code); | 106 | input_set_capability(input, type, button->code); |
| 91 | } | 107 | } |
| 92 | 108 | ||
| 93 | error = input_register_device(input); | 109 | error = input_register_device(input); |
| 94 | if (error) { | 110 | if (error) { |
| 95 | printk(KERN_ERR "Unable to register gpio-keys input device\n"); | 111 | printk(KERN_ERR |
| 112 | "gpio-keys: Unable to register input device, " | ||
| 113 | "error: %d\n", error); | ||
| 96 | goto fail; | 114 | goto fail; |
| 97 | } | 115 | } |
| 98 | 116 | ||
| 117 | device_init_wakeup(&pdev->dev, wakeup); | ||
| 118 | |||
| 99 | return 0; | 119 | return 0; |
| 100 | 120 | ||
| 101 | fail: | 121 | fail: |
| 102 | for (i = i - 1; i >= 0; i--) | 122 | while (--i >= 0) |
| 103 | free_irq(gpio_to_irq(pdata->buttons[i].gpio), pdev); | 123 | free_irq(gpio_to_irq(pdata->buttons[i].gpio), pdev); |
| 104 | 124 | ||
| 125 | platform_set_drvdata(pdev, NULL); | ||
| 105 | input_free_device(input); | 126 | input_free_device(input); |
| 106 | 127 | ||
| 107 | return error; | 128 | return error; |
| @@ -113,6 +134,8 @@ static int __devexit gpio_keys_remove(struct platform_device *pdev) | |||
| 113 | struct input_dev *input = platform_get_drvdata(pdev); | 134 | struct input_dev *input = platform_get_drvdata(pdev); |
| 114 | int i; | 135 | int i; |
| 115 | 136 | ||
| 137 | device_init_wakeup(&pdev->dev, 0); | ||
| 138 | |||
| 116 | for (i = 0; i < pdata->nbuttons; i++) { | 139 | for (i = 0; i < pdata->nbuttons; i++) { |
| 117 | int irq = gpio_to_irq(pdata->buttons[i].gpio); | 140 | int irq = gpio_to_irq(pdata->buttons[i].gpio); |
| 118 | free_irq(irq, pdev); | 141 | free_irq(irq, pdev); |
| @@ -123,9 +146,53 @@ static int __devexit gpio_keys_remove(struct platform_device *pdev) | |||
| 123 | return 0; | 146 | return 0; |
| 124 | } | 147 | } |
| 125 | 148 | ||
| 149 | |||
| 150 | #ifdef CONFIG_PM | ||
| 151 | static int gpio_keys_suspend(struct platform_device *pdev, pm_message_t state) | ||
| 152 | { | ||
| 153 | struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; | ||
| 154 | int i; | ||
| 155 | |||
| 156 | if (device_may_wakeup(&pdev->dev)) { | ||
| 157 | for (i = 0; i < pdata->nbuttons; i++) { | ||
| 158 | struct gpio_keys_button *button = &pdata->buttons[i]; | ||
| 159 | if (button->wakeup) { | ||
| 160 | int irq = gpio_to_irq(button->gpio); | ||
| 161 | enable_irq_wake(irq); | ||
| 162 | } | ||
| 163 | } | ||
| 164 | } | ||
| 165 | |||
| 166 | return 0; | ||
| 167 | } | ||
| 168 | |||
| 169 | static int gpio_keys_resume(struct platform_device *pdev) | ||
| 170 | { | ||
| 171 | struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; | ||
| 172 | int i; | ||
| 173 | |||
| 174 | if (device_may_wakeup(&pdev->dev)) { | ||
| 175 | for (i = 0; i < pdata->nbuttons; i++) { | ||
| 176 | struct gpio_keys_button *button = &pdata->buttons[i]; | ||
| 177 | if (button->wakeup) { | ||
| 178 | int irq = gpio_to_irq(button->gpio); | ||
| 179 | disable_irq_wake(irq); | ||
| 180 | } | ||
| 181 | } | ||
| 182 | } | ||
| 183 | |||
| 184 | return 0; | ||
| 185 | } | ||
| 186 | #else | ||
| 187 | #define gpio_keys_suspend NULL | ||
| 188 | #define gpio_keys_resume NULL | ||
| 189 | #endif | ||
| 190 | |||
| 126 | struct platform_driver gpio_keys_device_driver = { | 191 | struct platform_driver gpio_keys_device_driver = { |
| 127 | .probe = gpio_keys_probe, | 192 | .probe = gpio_keys_probe, |
| 128 | .remove = __devexit_p(gpio_keys_remove), | 193 | .remove = __devexit_p(gpio_keys_remove), |
| 194 | .suspend = gpio_keys_suspend, | ||
| 195 | .resume = gpio_keys_resume, | ||
| 129 | .driver = { | 196 | .driver = { |
| 130 | .name = "gpio-keys", | 197 | .name = "gpio-keys", |
| 131 | } | 198 | } |
diff --git a/drivers/input/keyboard/jornada680_kbd.c b/drivers/input/keyboard/jornada680_kbd.c new file mode 100644 index 000000000000..bec1cf483723 --- /dev/null +++ b/drivers/input/keyboard/jornada680_kbd.c | |||
| @@ -0,0 +1,277 @@ | |||
| 1 | /* | ||
| 2 | * drivers/input/keyboard/jornada680_kbd.c | ||
| 3 | * | ||
| 4 | * HP Jornada 620/660/680/690 scan keyboard platform driver | ||
| 5 | * Copyright (C) 2007 Kristoffer Ericson <Kristoffer.Ericson@gmail.com> | ||
| 6 | * | ||
| 7 | * Based on hp680_keyb.c | ||
| 8 | * Copyright (C) 2006 Paul Mundt | ||
| 9 | * Copyright (C) 2005 Andriy Skulysh | ||
| 10 | * Split from drivers/input/keyboard/hp600_keyb.c | ||
| 11 | * Copyright (C) 2000 Yaegashi Takeshi (hp6xx kbd scan routine and translation table) | ||
| 12 | * Copyright (C) 2000 Niibe Yutaka (HP620 Keyb translation table) | ||
| 13 | * | ||
| 14 | * This program is free software; you can redistribute it and/or modify it | ||
| 15 | * under the terms of the GNU General Public License version 2 as | ||
| 16 | * published by the Free Software Foundation. | ||
| 17 | */ | ||
| 18 | |||
| 19 | #include <linux/input.h> | ||
| 20 | #include <linux/kernel.h> | ||
| 21 | #include <linux/module.h> | ||
| 22 | #include <linux/init.h> | ||
| 23 | #include <linux/input-polldev.h> | ||
| 24 | #include <linux/jiffies.h> | ||
| 25 | #include <linux/platform_device.h> | ||
| 26 | #include <linux/interrupt.h> | ||
| 27 | |||
| 28 | #include <asm/delay.h> | ||
| 29 | #include <asm/io.h> | ||
| 30 | |||
| 31 | #define PCCR 0xa4000104 | ||
| 32 | #define PDCR 0xa4000106 | ||
| 33 | #define PECR 0xa4000108 | ||
| 34 | #define PFCR 0xa400010a | ||
| 35 | #define PCDR 0xa4000124 | ||
| 36 | #define PDDR 0xa4000126 | ||
| 37 | #define PEDR 0xa4000128 | ||
| 38 | #define PFDR 0xa400012a | ||
| 39 | #define PGDR 0xa400012c | ||
| 40 | #define PHDR 0xa400012e | ||
| 41 | #define PJDR 0xa4000130 | ||
| 42 | #define PKDR 0xa4000132 | ||
| 43 | #define PLDR 0xa4000134 | ||
| 44 | |||
| 45 | static const unsigned short jornada_scancodes[] = { | ||
| 46 | /* PTD1 */ KEY_CAPSLOCK, KEY_MACRO, KEY_LEFTCTRL, 0, KEY_ESC, 0, 0, 0, /* 1 -> 8 */ | ||
| 47 | KEY_F1, KEY_F2, KEY_F3, KEY_F8, KEY_F7, KEY_F2, KEY_F4, KEY_F5, /* 9 -> 16 */ | ||
| 48 | /* PTD5 */ KEY_SLASH, KEY_APOSTROPHE, KEY_ENTER, 0, KEY_Z, 0, 0, 0, /* 17 -> 24 */ | ||
| 49 | KEY_X, KEY_C, KEY_V, KEY_DOT, KEY_COMMA, KEY_M, KEY_B, KEY_N, /* 25 -> 32 */ | ||
| 50 | /* PTD7 */ KEY_KP2, KEY_KP6, 0, 0, 0, 0, 0, 0, /* 33 -> 40 */ | ||
| 51 | 0, 0, 0, KEY_KP4, 0, 0, KEY_LEFTALT, KEY_HANJA, /* 41 -> 48 */ | ||
| 52 | /* PTE0 */ 0, 0, 0, 0, KEY_FINANCE, 0, 0, 0, /* 49 -> 56 */ | ||
| 53 | KEY_LEFTCTRL, 0, KEY_SPACE, KEY_KPDOT, KEY_VOLUMEUP, 249, 0, 0, /* 57 -> 64 */ | ||
| 54 | /* PTE1 */ KEY_SEMICOLON, KEY_RIGHTBRACE, KEY_BACKSLASH, 0, KEY_A, 0, 0, 0,/* 65 -> 72 */ | ||
| 55 | KEY_S, KEY_D, KEY_F, KEY_L, KEY_K, KEY_J, KEY_G, KEY_H, /* 73 -> 80 */ | ||
| 56 | /* PTE3 */ KEY_KP8, KEY_LEFTMETA, KEY_RIGHTSHIFT, 0, KEY_TAB, 0, 0,0, /* 81 -> 88 */ | ||
| 57 | 0, KEY_LEFTSHIFT, 0, 0, 0, 0, 0, 0, /* 89 -> 96 */ | ||
| 58 | /* PTE6 */ KEY_P, KEY_LEFTBRACE, KEY_BACKSPACE, 0, KEY_Q, 0, 0, 0, /* 97 -> 104 */ | ||
| 59 | KEY_W, KEY_E, KEY_R, KEY_O, KEY_I, KEY_U, KEY_T, KEY_R, /* 105 -> 112 */ | ||
| 60 | /* PTE7 */ KEY_0, KEY_MINUS, KEY_EQUAL, 0, KEY_1, 0, 0, 0, /* 113 -> 120 */ | ||
| 61 | KEY_2, KEY_3, KEY_4, KEY_9, KEY_8, KEY_7, KEY_5, KEY_6, /* 121 -> 128 */ | ||
| 62 | /* **** */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 63 | 0, 0, 0, 0, 0 | ||
| 64 | }; | ||
| 65 | |||
| 66 | #define JORNADA_SCAN_SIZE 18 | ||
| 67 | |||
| 68 | struct jornadakbd { | ||
| 69 | struct input_polled_dev *poll_dev; | ||
| 70 | unsigned short keymap[ARRAY_SIZE(jornada_scancodes)]; | ||
| 71 | unsigned char length; | ||
| 72 | unsigned char old_scan[JORNADA_SCAN_SIZE]; | ||
| 73 | unsigned char new_scan[JORNADA_SCAN_SIZE]; | ||
| 74 | }; | ||
| 75 | |||
| 76 | static void jornada_parse_kbd(struct jornadakbd *jornadakbd) | ||
| 77 | { | ||
| 78 | struct input_dev *input_dev = jornadakbd->poll_dev->input; | ||
| 79 | unsigned short *keymap = jornadakbd->keymap; | ||
| 80 | unsigned int sync_me = 0; | ||
| 81 | unsigned int i, j; | ||
| 82 | |||
| 83 | for (i = 0; i < JORNADA_SCAN_SIZE; i++) { | ||
| 84 | unsigned char new = jornadakbd->new_scan[i]; | ||
| 85 | unsigned char old = jornadakbd->old_scan[i]; | ||
| 86 | unsigned int xor = new ^ old; | ||
| 87 | |||
| 88 | if (xor == 0) | ||
| 89 | continue; | ||
| 90 | |||
| 91 | for (j = 0; j < 8; j++) { | ||
| 92 | unsigned int bit = 1 << j; | ||
| 93 | if (xor & bit) { | ||
| 94 | unsigned int scancode = (i << 3) + j; | ||
| 95 | input_event(input_dev, | ||
| 96 | EV_MSC, MSC_SCAN, scancode); | ||
| 97 | input_report_key(input_dev, | ||
| 98 | keymap[scancode], | ||
| 99 | !(new & bit)); | ||
| 100 | sync_me = 1; | ||
| 101 | } | ||
| 102 | } | ||
| 103 | } | ||
| 104 | |||
| 105 | if (sync_me) | ||
| 106 | input_sync(input_dev); | ||
| 107 | } | ||
| 108 | |||
| 109 | static void jornada_scan_keyb(unsigned char *s) | ||
| 110 | { | ||
| 111 | int i; | ||
| 112 | unsigned short ec_static, dc_static; /* = UINT16_t */ | ||
| 113 | unsigned char matrix_switch[] = { | ||
| 114 | 0xfd, 0xff, /* PTD1 PD(1) */ | ||
| 115 | 0xdf, 0xff, /* PTD5 PD(5) */ | ||
| 116 | 0x7f, 0xff, /* PTD7 PD(7) */ | ||
| 117 | 0xff, 0xfe, /* PTE0 PE(0) */ | ||
| 118 | 0xff, 0xfd, /* PTE1 PE(1) */ | ||
| 119 | 0xff, 0xf7, /* PTE3 PE(3) */ | ||
| 120 | 0xff, 0xbf, /* PTE6 PE(6) */ | ||
| 121 | 0xff, 0x7f, /* PTE7 PE(7) */ | ||
| 122 | }, *t = matrix_switch; | ||
| 123 | /* PD(x) : | ||
| 124 | 1. 0xcc0c & (1~(1 << (2*(x)+1))))) | ||
| 125 | 2. (0xf0cf & 0xfffff) */ | ||
| 126 | /* PE(x) : | ||
| 127 | 1. 0xcc0c & 0xffff | ||
| 128 | 2. 0xf0cf & (1~(1 << (2*(x)+1))))) */ | ||
| 129 | unsigned short matrix_PDE[] = { | ||
| 130 | 0xcc04, 0xf0cf, /* PD(1) */ | ||
| 131 | 0xc40c, 0xf0cf, /* PD(5) */ | ||
| 132 | 0x4c0c, 0xf0cf, /* PD(7) */ | ||
| 133 | 0xcc0c, 0xf0cd, /* PE(0) */ | ||
| 134 | 0xcc0c, 0xf0c7, /* PE(1) */ | ||
| 135 | 0xcc0c, 0xf04f, /* PE(3) */ | ||
| 136 | 0xcc0c, 0xd0cf, /* PE(6) */ | ||
| 137 | 0xcc0c, 0x70cf, /* PE(7) */ | ||
| 138 | }, *y = matrix_PDE; | ||
| 139 | |||
| 140 | /* Save these control reg bits */ | ||
| 141 | dc_static = (ctrl_inw(PDCR) & (~0xcc0c)); | ||
| 142 | ec_static = (ctrl_inw(PECR) & (~0xf0cf)); | ||
| 143 | |||
| 144 | for (i = 0; i < 8; i++) { | ||
| 145 | /* disable output for all but the one we want to scan */ | ||
| 146 | ctrl_outw((dc_static | *y++), PDCR); | ||
| 147 | ctrl_outw((ec_static | *y++), PECR); | ||
| 148 | udelay(5); | ||
| 149 | |||
| 150 | /* Get scanline row */ | ||
| 151 | ctrl_outb(*t++, PDDR); | ||
| 152 | ctrl_outb(*t++, PEDR); | ||
| 153 | udelay(50); | ||
| 154 | |||
| 155 | /* Read data */ | ||
| 156 | *s++ = ctrl_inb(PCDR); | ||
| 157 | *s++ = ctrl_inb(PFDR); | ||
| 158 | } | ||
| 159 | /* Scan no lines */ | ||
| 160 | ctrl_outb(0xff, PDDR); | ||
| 161 | ctrl_outb(0xff, PEDR); | ||
| 162 | |||
| 163 | /* Enable all scanlines */ | ||
| 164 | ctrl_outw((dc_static | (0x5555 & 0xcc0c)),PDCR); | ||
| 165 | ctrl_outw((ec_static | (0x5555 & 0xf0cf)),PECR); | ||
| 166 | |||
| 167 | /* Ignore extra keys and events */ | ||
| 168 | *s++ = ctrl_inb(PGDR); | ||
| 169 | *s++ = ctrl_inb(PHDR); | ||
| 170 | } | ||
| 171 | |||
| 172 | static void jornadakbd680_poll(struct input_polled_dev *dev) | ||
| 173 | { | ||
| 174 | struct jornadakbd *jornadakbd = dev->private; | ||
| 175 | |||
| 176 | jornada_scan_keyb(jornadakbd->new_scan); | ||
| 177 | jornada_parse_kbd(jornadakbd); | ||
| 178 | memcpy(jornadakbd->old_scan, jornadakbd->new_scan, JORNADA_SCAN_SIZE); | ||
| 179 | } | ||
| 180 | |||
| 181 | static int __devinit jornada680kbd_probe(struct platform_device *pdev) | ||
| 182 | { | ||
| 183 | struct jornadakbd *jornadakbd; | ||
| 184 | struct input_polled_dev *poll_dev; | ||
| 185 | struct input_dev *input_dev; | ||
| 186 | int i, error; | ||
| 187 | |||
| 188 | jornadakbd = kzalloc(sizeof(struct jornadakbd), GFP_KERNEL); | ||
| 189 | if (!jornadakbd) | ||
| 190 | return -ENOMEM; | ||
| 191 | |||
| 192 | poll_dev = input_allocate_polled_device(); | ||
| 193 | if (!poll_dev) { | ||
| 194 | error = -ENOMEM; | ||
| 195 | goto failed; | ||
| 196 | } | ||
| 197 | |||
| 198 | platform_set_drvdata(pdev, jornadakbd); | ||
| 199 | |||
| 200 | jornadakbd->poll_dev = poll_dev; | ||
| 201 | |||
| 202 | memcpy(jornadakbd->keymap, jornada_scancodes, | ||
| 203 | sizeof(jornadakbd->keymap)); | ||
| 204 | |||
| 205 | poll_dev->private = jornadakbd; | ||
| 206 | poll_dev->poll = jornadakbd680_poll; | ||
| 207 | poll_dev->poll_interval = 50; /* msec */ | ||
| 208 | |||
| 209 | input_dev = poll_dev->input; | ||
| 210 | input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP); | ||
| 211 | input_dev->name = "HP Jornada 680 keyboard"; | ||
| 212 | input_dev->phys = "jornadakbd/input0"; | ||
| 213 | input_dev->keycode = jornadakbd->keymap; | ||
| 214 | input_dev->keycodesize = sizeof(unsigned short); | ||
| 215 | input_dev->keycodemax = ARRAY_SIZE(jornada_scancodes); | ||
| 216 | input_dev->dev.parent = &pdev->dev; | ||
| 217 | input_dev->id.bustype = BUS_HOST; | ||
| 218 | |||
| 219 | for (i = 0; i < 128; i++) | ||
| 220 | if (jornadakbd->keymap[i]) | ||
| 221 | __set_bit(jornadakbd->keymap[i], input_dev->keybit); | ||
| 222 | __clear_bit(KEY_RESERVED, input_dev->keybit); | ||
| 223 | |||
| 224 | input_set_capability(input_dev, EV_MSC, MSC_SCAN); | ||
| 225 | |||
| 226 | error = input_register_polled_device(jornadakbd->poll_dev); | ||
| 227 | if (error) | ||
| 228 | goto failed; | ||
| 229 | |||
| 230 | return 0; | ||
| 231 | |||
| 232 | failed: | ||
| 233 | printk(KERN_ERR "Jornadakbd: failed to register driver, error: %d\n", | ||
| 234 | error); | ||
| 235 | platform_set_drvdata(pdev, NULL); | ||
| 236 | input_free_polled_device(poll_dev); | ||
| 237 | kfree(jornadakbd); | ||
| 238 | return error; | ||
| 239 | |||
| 240 | } | ||
| 241 | |||
| 242 | static int __devexit jornada680kbd_remove(struct platform_device *pdev) | ||
| 243 | { | ||
| 244 | struct jornadakbd *jornadakbd = platform_get_drvdata(pdev); | ||
| 245 | |||
| 246 | platform_set_drvdata(pdev, NULL); | ||
| 247 | input_unregister_polled_device(jornadakbd->poll_dev); | ||
| 248 | input_free_polled_device(jornadakbd->poll_dev); | ||
| 249 | kfree(jornadakbd); | ||
| 250 | |||
| 251 | return 0; | ||
| 252 | } | ||
| 253 | |||
| 254 | static struct platform_driver jornada680kbd_driver = { | ||
| 255 | .driver = { | ||
| 256 | .name = "jornada680_kbd", | ||
| 257 | }, | ||
| 258 | .probe = jornada680kbd_probe, | ||
| 259 | .remove = __devexit_p(jornada680kbd_remove), | ||
| 260 | }; | ||
| 261 | |||
| 262 | static int __init jornada680kbd_init(void) | ||
| 263 | { | ||
| 264 | return platform_driver_register(&jornada680kbd_driver); | ||
| 265 | } | ||
| 266 | |||
| 267 | static void __exit jornada680kbd_exit(void) | ||
| 268 | { | ||
| 269 | platform_driver_unregister(&jornada680kbd_driver); | ||
| 270 | } | ||
| 271 | |||
| 272 | module_init(jornada680kbd_init); | ||
| 273 | module_exit(jornada680kbd_exit); | ||
| 274 | |||
| 275 | MODULE_AUTHOR("Kristoffer Ericson <kristoffer.ericson@gmail.com>"); | ||
| 276 | MODULE_DESCRIPTION("HP Jornada 620/660/680/690 Keyboard Driver"); | ||
| 277 | MODULE_LICENSE("GPLv2"); | ||
diff --git a/drivers/input/keyboard/jornada720_kbd.c b/drivers/input/keyboard/jornada720_kbd.c new file mode 100644 index 000000000000..e6696b3c9416 --- /dev/null +++ b/drivers/input/keyboard/jornada720_kbd.c | |||
| @@ -0,0 +1,185 @@ | |||
| 1 | /* | ||
| 2 | * drivers/input/keyboard/jornada720_kbd.c | ||
| 3 | * | ||
| 4 | * HP Jornada 720 keyboard platform driver | ||
| 5 | * | ||
| 6 | * Copyright (C) 2006/2007 Kristoffer Ericson <Kristoffer.Ericson@Gmail.com> | ||
| 7 | * | ||
| 8 | * Copyright (C) 2006 jornada 720 kbd driver by | ||
| 9 | Filip Zyzniewsk <Filip.Zyzniewski@tefnet.plX | ||
| 10 | * based on (C) 2004 jornada 720 kbd driver by | ||
| 11 | Alex Lange <chicken@handhelds.org> | ||
| 12 | * | ||
| 13 | * This program is free software; you can redistribute it and/or modify | ||
| 14 | * it under the terms of the GNU General Public License version 2 as | ||
| 15 | * published by the Free Software Foundation. | ||
| 16 | * | ||
| 17 | */ | ||
| 18 | #include <linux/device.h> | ||
| 19 | #include <linux/errno.h> | ||
| 20 | #include <linux/init.h> | ||
| 21 | #include <linux/interrupt.h> | ||
| 22 | #include <linux/init.h> | ||
| 23 | #include <linux/input.h> | ||
| 24 | #include <linux/kernel.h> | ||
| 25 | #include <linux/module.h> | ||
| 26 | #include <linux/platform_device.h> | ||
| 27 | |||
| 28 | #include <asm/arch/jornada720.h> | ||
| 29 | #include <asm/hardware.h> | ||
| 30 | |||
| 31 | MODULE_AUTHOR("Kristoffer Ericson <Kristoffer.Ericson@gmail.com>"); | ||
| 32 | MODULE_DESCRIPTION("HP Jornada 710/720/728 keyboard driver"); | ||
| 33 | MODULE_LICENSE("GPLv2"); | ||
| 34 | |||
| 35 | static unsigned short jornada_std_keymap[128] = { /* ROW */ | ||
| 36 | 0, KEY_ESC, KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7, /* #1 */ | ||
| 37 | KEY_F8, KEY_F9, KEY_F10, KEY_F11, KEY_VOLUMEUP, KEY_VOLUMEDOWN, KEY_MUTE, /* -> */ | ||
| 38 | 0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9, /* #2 */ | ||
| 39 | KEY_0, KEY_MINUS, KEY_EQUAL,0, 0, 0, /* -> */ | ||
| 40 | 0, KEY_Q, KEY_W, KEY_E, KEY_R, KEY_T, KEY_Y, KEY_U, KEY_I, KEY_O, /* #3 */ | ||
| 41 | KEY_P, KEY_BACKSLASH, KEY_BACKSPACE, 0, 0, 0, /* -> */ | ||
| 42 | 0, KEY_A, KEY_S, KEY_D, KEY_F, KEY_G, KEY_H, KEY_J, KEY_K, KEY_L, /* #4 */ | ||
| 43 | KEY_SEMICOLON, KEY_LEFTBRACE, KEY_RIGHTBRACE, 0, 0, 0, /* -> */ | ||
| 44 | 0, KEY_Z, KEY_X, KEY_C, KEY_V, KEY_B, KEY_N, KEY_M, KEY_COMMA, /* #5 */ | ||
| 45 | KEY_DOT, KEY_KPMINUS, KEY_APOSTROPHE, KEY_ENTER, 0, 0,0, /* -> */ | ||
| 46 | 0, KEY_TAB, 0, KEY_LEFTSHIFT, 0, KEY_APOSTROPHE, 0, 0, 0, 0, /* #6 */ | ||
| 47 | KEY_UP, 0, KEY_RIGHTSHIFT, 0, 0, 0,0, 0, 0, 0, 0, KEY_LEFTALT, KEY_GRAVE, /* -> */ | ||
| 48 | 0, 0, KEY_LEFT, KEY_DOWN, KEY_RIGHT, 0, 0, 0, 0,0, KEY_KPASTERISK, /* -> */ | ||
| 49 | KEY_LEFTCTRL, 0, KEY_SPACE, 0, 0, 0, KEY_SLASH, KEY_DELETE, 0, 0, /* -> */ | ||
| 50 | 0, 0, 0, KEY_POWER, /* -> */ | ||
| 51 | }; | ||
| 52 | |||
| 53 | struct jornadakbd { | ||
| 54 | unsigned short keymap[ARRAY_SIZE(jornada_std_keymap)]; | ||
| 55 | struct input_dev *input; | ||
| 56 | }; | ||
| 57 | |||
| 58 | static irqreturn_t jornada720_kbd_interrupt(int irq, void *dev_id) | ||
| 59 | { | ||
| 60 | struct platform_device *pdev = dev_id; | ||
| 61 | struct jornadakbd *jornadakbd = platform_get_drvdata(pdev); | ||
| 62 | struct input_dev *input = jornadakbd->input; | ||
| 63 | u8 count, kbd_data, scan_code; | ||
| 64 | |||
| 65 | /* startup ssp with spinlock */ | ||
| 66 | jornada_ssp_start(); | ||
| 67 | |||
| 68 | if (jornada_ssp_inout(GETSCANKEYCODE) != TXDUMMY) { | ||
| 69 | printk(KERN_DEBUG | ||
| 70 | "jornada720_kbd: " | ||
| 71 | "GetKeycode command failed with ETIMEDOUT, " | ||
| 72 | "flushed bus\n"); | ||
| 73 | } else { | ||
| 74 | /* How many keycodes are waiting for us? */ | ||
| 75 | count = jornada_ssp_byte(TXDUMMY); | ||
| 76 | |||
| 77 | /* Lets drag them out one at a time */ | ||
| 78 | while (count--) { | ||
| 79 | /* Exchange TxDummy for location (keymap[kbddata]) */ | ||
| 80 | kbd_data = jornada_ssp_byte(TXDUMMY); | ||
| 81 | scan_code = kbd_data & 0x7f; | ||
| 82 | |||
| 83 | input_event(input, EV_MSC, MSC_SCAN, scan_code); | ||
| 84 | input_report_key(input, jornadakbd->keymap[scan_code], | ||
| 85 | !(kbd_data & 0x80)); | ||
| 86 | input_sync(input); | ||
| 87 | } | ||
| 88 | } | ||
| 89 | |||
| 90 | /* release spinlock and turn off ssp */ | ||
| 91 | jornada_ssp_end(); | ||
| 92 | |||
| 93 | return IRQ_HANDLED; | ||
| 94 | }; | ||
| 95 | |||
| 96 | static int __devinit jornada720_kbd_probe(struct platform_device *pdev) | ||
| 97 | { | ||
| 98 | struct jornadakbd *jornadakbd; | ||
| 99 | struct input_dev *input_dev; | ||
| 100 | int i, err; | ||
| 101 | |||
| 102 | jornadakbd = kzalloc(sizeof(struct jornadakbd), GFP_KERNEL); | ||
| 103 | input_dev = input_allocate_device(); | ||
| 104 | if (!jornadakbd || !input_dev) { | ||
| 105 | err = -ENOMEM; | ||
| 106 | goto fail1; | ||
| 107 | } | ||
| 108 | |||
| 109 | platform_set_drvdata(pdev, jornadakbd); | ||
| 110 | |||
| 111 | memcpy(jornadakbd->keymap, jornada_std_keymap, | ||
| 112 | sizeof(jornada_std_keymap)); | ||
| 113 | jornadakbd->input = input_dev; | ||
| 114 | |||
| 115 | input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP); | ||
| 116 | input_dev->name = "HP Jornada 720 keyboard"; | ||
| 117 | input_dev->phys = "jornadakbd/input0"; | ||
| 118 | input_dev->keycode = jornadakbd->keymap; | ||
| 119 | input_dev->keycodesize = sizeof(unsigned short); | ||
| 120 | input_dev->keycodemax = ARRAY_SIZE(jornada_std_keymap); | ||
| 121 | input_dev->id.bustype = BUS_HOST; | ||
| 122 | input_dev->dev.parent = &pdev->dev; | ||
| 123 | |||
| 124 | for (i = 0; i < ARRAY_SIZE(jornadakbd->keymap); i++) | ||
| 125 | __set_bit(jornadakbd->keymap[i], input_dev->keybit); | ||
| 126 | __clear_bit(KEY_RESERVED, input_dev->keybit); | ||
| 127 | |||
| 128 | input_set_capability(input_dev, EV_MSC, MSC_SCAN); | ||
| 129 | |||
| 130 | err = request_irq(IRQ_GPIO0, | ||
| 131 | jornada720_kbd_interrupt, | ||
| 132 | IRQF_DISABLED | IRQF_TRIGGER_FALLING, | ||
| 133 | "jornadakbd", pdev); | ||
| 134 | if (err) { | ||
| 135 | printk(KERN_INFO "jornadakbd720_kbd: Unable to grab IRQ\n"); | ||
| 136 | goto fail1; | ||
| 137 | } | ||
| 138 | |||
| 139 | err = input_register_device(jornadakbd->input); | ||
| 140 | if (err) | ||
| 141 | goto fail2; | ||
| 142 | |||
| 143 | return 0; | ||
| 144 | |||
| 145 | fail2: /* IRQ, DEVICE, MEMORY */ | ||
| 146 | free_irq(IRQ_GPIO0, pdev); | ||
| 147 | fail1: /* DEVICE, MEMORY */ | ||
| 148 | platform_set_drvdata(pdev, NULL); | ||
| 149 | input_free_device(input_dev); | ||
| 150 | kfree(jornadakbd); | ||
| 151 | return err; | ||
| 152 | }; | ||
| 153 | |||
| 154 | static int __devexit jornada720_kbd_remove(struct platform_device *pdev) | ||
| 155 | { | ||
| 156 | struct jornadakbd *jornadakbd = platform_get_drvdata(pdev); | ||
| 157 | |||
| 158 | free_irq(IRQ_GPIO0, pdev); | ||
| 159 | platform_set_drvdata(pdev, NULL); | ||
| 160 | input_unregister_device(jornadakbd->input); | ||
| 161 | kfree(jornadakbd); | ||
| 162 | |||
| 163 | return 0; | ||
| 164 | } | ||
| 165 | |||
| 166 | static struct platform_driver jornada720_kbd_driver = { | ||
| 167 | .driver = { | ||
| 168 | .name = "jornada720_kbd", | ||
| 169 | }, | ||
| 170 | .probe = jornada720_kbd_probe, | ||
| 171 | .remove = __devexit_p(jornada720_kbd_remove), | ||
| 172 | }; | ||
| 173 | |||
| 174 | static int __init jornada720_kbd_init(void) | ||
| 175 | { | ||
| 176 | return platform_driver_register(&jornada720_kbd_driver); | ||
| 177 | } | ||
| 178 | |||
| 179 | static void __exit jornada720_kbd_exit(void) | ||
| 180 | { | ||
| 181 | platform_driver_unregister(&jornada720_kbd_driver); | ||
| 182 | } | ||
| 183 | |||
| 184 | module_init(jornada720_kbd_init); | ||
| 185 | module_exit(jornada720_kbd_exit); | ||
diff --git a/drivers/input/keyboard/maple_keyb.c b/drivers/input/keyboard/maple_keyb.c new file mode 100644 index 000000000000..2b404284c28a --- /dev/null +++ b/drivers/input/keyboard/maple_keyb.c | |||
| @@ -0,0 +1,252 @@ | |||
| 1 | /* | ||
| 2 | * SEGA Dreamcast keyboard driver | ||
| 3 | * Based on drivers/usb/usbkbd.c | ||
| 4 | * Copyright YAEGASHI Takeshi, 2001 | ||
| 5 | * Porting to 2.6 Copyright Adrian McMenamin, 2007 | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License as published by | ||
| 9 | * the Free Software Foundation; either version 2 of the License, or | ||
| 10 | * (at your option) any later version. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License | ||
| 18 | * along with this program; if not, see the file COPYING, or write | ||
| 19 | * to the Free Software Foundation, Inc., | ||
| 20 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 21 | */ | ||
| 22 | |||
| 23 | #include <linux/kernel.h> | ||
| 24 | #include <linux/slab.h> | ||
| 25 | #include <linux/input.h> | ||
| 26 | #include <linux/module.h> | ||
| 27 | #include <linux/init.h> | ||
| 28 | #include <linux/timer.h> | ||
| 29 | #include <linux/maple.h> | ||
| 30 | #include <asm/mach/maple.h> | ||
| 31 | |||
| 32 | /* Very simple mutex to ensure proper cleanup */ | ||
| 33 | static DEFINE_MUTEX(maple_keyb_mutex); | ||
| 34 | |||
| 35 | #define NR_SCANCODES 256 | ||
| 36 | |||
| 37 | MODULE_AUTHOR("YAEGASHI Takeshi, Adrian McMenamin"); | ||
| 38 | MODULE_DESCRIPTION("SEGA Dreamcast keyboard driver"); | ||
| 39 | MODULE_LICENSE("GPL"); | ||
| 40 | |||
| 41 | struct dc_kbd { | ||
| 42 | struct input_dev *dev; | ||
| 43 | unsigned short keycode[NR_SCANCODES]; | ||
| 44 | unsigned char new[8]; | ||
| 45 | unsigned char old[8]; | ||
| 46 | }; | ||
| 47 | |||
| 48 | static const unsigned short dc_kbd_keycode[NR_SCANCODES] = { | ||
| 49 | KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_A, KEY_B, KEY_C, KEY_D, | ||
| 50 | KEY_E, KEY_F, KEY_G, KEY_H, KEY_I, KEY_J, KEY_K, KEY_L, | ||
| 51 | KEY_M, KEY_N, KEY_O, KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T, | ||
| 52 | KEY_U, KEY_V, KEY_W, KEY_X, KEY_Y, KEY_Z, KEY_1, KEY_2, | ||
| 53 | KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9, KEY_0, | ||
| 54 | KEY_ENTER, KEY_ESC, KEY_BACKSPACE, KEY_TAB, KEY_SPACE, KEY_MINUS, KEY_EQUAL, KEY_LEFTBRACE, | ||
| 55 | KEY_RIGHTBRACE, KEY_BACKSLASH, KEY_BACKSLASH, KEY_SEMICOLON, KEY_APOSTROPHE, KEY_GRAVE, KEY_COMMA, | ||
| 56 | KEY_DOT, KEY_SLASH, KEY_CAPSLOCK, KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, | ||
| 57 | KEY_F7, KEY_F8, KEY_F9, KEY_F10, KEY_F11, KEY_F12, KEY_SYSRQ, | ||
| 58 | KEY_SCROLLLOCK, KEY_PAUSE, KEY_INSERT, KEY_HOME, KEY_PAGEUP, KEY_DELETE, | ||
| 59 | KEY_END, KEY_PAGEDOWN, KEY_RIGHT, KEY_LEFT, KEY_DOWN, KEY_UP, | ||
| 60 | KEY_NUMLOCK, KEY_KPSLASH, KEY_KPASTERISK, KEY_KPMINUS, KEY_KPPLUS, KEY_KPENTER, KEY_KP1, KEY_KP2, | ||
| 61 | KEY_KP3, KEY_KP4, KEY_KP5, KEY_KP6, KEY_KP7, KEY_KP8, KEY_KP9, KEY_KP0, KEY_KPDOT, | ||
| 62 | KEY_102ND, KEY_COMPOSE, KEY_POWER, KEY_KPEQUAL, KEY_F13, KEY_F14, KEY_F15, | ||
| 63 | KEY_F16, KEY_F17, KEY_F18, KEY_F19, KEY_F20, | ||
| 64 | KEY_F21, KEY_F22, KEY_F23, KEY_F24, KEY_OPEN, KEY_HELP, KEY_PROPS, KEY_FRONT, | ||
| 65 | KEY_STOP, KEY_AGAIN, KEY_UNDO, KEY_CUT, KEY_COPY, KEY_PASTE, KEY_FIND, KEY_MUTE, | ||
| 66 | KEY_VOLUMEUP, KEY_VOLUMEDOWN, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_KPCOMMA, KEY_RESERVED, KEY_RO, KEY_KATAKANAHIRAGANA , KEY_YEN, | ||
| 67 | KEY_HENKAN, KEY_MUHENKAN, KEY_KPJPCOMMA, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
| 68 | KEY_HANGEUL, KEY_HANJA, KEY_KATAKANA, KEY_HIRAGANA, KEY_ZENKAKUHANKAKU, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
| 69 | KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
| 70 | KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
| 71 | KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
| 72 | KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
| 73 | KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
| 74 | KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
| 75 | KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
| 76 | KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
| 77 | KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, | ||
| 78 | KEY_LEFTCTRL, KEY_LEFTSHIFT, KEY_LEFTALT, KEY_LEFTMETA, KEY_RIGHTCTRL, KEY_RIGHTSHIFT, KEY_RIGHTALT, KEY_RIGHTMETA, | ||
| 79 | KEY_PLAYPAUSE, KEY_STOPCD, KEY_PREVIOUSSONG, KEY_NEXTSONG, KEY_EJECTCD, KEY_VOLUMEUP, KEY_VOLUMEDOWN, KEY_MUTE, | ||
| 80 | KEY_WWW, KEY_BACK, KEY_FORWARD, KEY_STOP, KEY_FIND, KEY_SCROLLUP, KEY_SCROLLDOWN, KEY_EDIT, KEY_SLEEP, | ||
| 81 | KEY_SCREENLOCK, KEY_REFRESH, KEY_CALC, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED, KEY_RESERVED | ||
| 82 | }; | ||
| 83 | |||
| 84 | static void dc_scan_kbd(struct dc_kbd *kbd) | ||
| 85 | { | ||
| 86 | struct input_dev *dev = kbd->dev; | ||
| 87 | void *ptr; | ||
| 88 | int code, keycode; | ||
| 89 | int i; | ||
| 90 | |||
| 91 | for (i = 0; i < 8; i++) { | ||
| 92 | code = i + 224; | ||
| 93 | keycode = kbd->keycode[code]; | ||
| 94 | input_event(dev, EV_MSC, MSC_SCAN, code); | ||
| 95 | input_report_key(dev, keycode, (kbd->new[0] >> i) & 1); | ||
| 96 | } | ||
| 97 | |||
| 98 | for (i = 2; i < 8; i++) { | ||
| 99 | ptr = memchr(kbd->new + 2, kbd->old[i], 6); | ||
| 100 | code = kbd->old[i]; | ||
| 101 | if (code > 3 && ptr == NULL) { | ||
| 102 | keycode = kbd->keycode[code]; | ||
| 103 | if (keycode) { | ||
| 104 | input_event(dev, EV_MSC, MSC_SCAN, code); | ||
| 105 | input_report_key(dev, keycode, 0); | ||
| 106 | } else | ||
| 107 | printk(KERN_DEBUG "maple_keyb: " | ||
| 108 | "Unknown key (scancode %#x) released.", | ||
| 109 | code); | ||
| 110 | } | ||
| 111 | ptr = memchr(kbd->old + 2, kbd->new[i], 6); | ||
| 112 | code = kbd->new[i]; | ||
| 113 | if (code > 3 && ptr) { | ||
| 114 | keycode = kbd->keycode[code]; | ||
| 115 | if (keycode) { | ||
| 116 | input_event(dev, EV_MSC, MSC_SCAN, code); | ||
| 117 | input_report_key(dev, keycode, 1); | ||
| 118 | } else | ||
| 119 | printk(KERN_DEBUG "maple_keyb: " | ||
| 120 | "Unknown key (scancode %#x) pressed.", | ||
| 121 | code); | ||
| 122 | } | ||
| 123 | } | ||
| 124 | input_sync(dev); | ||
| 125 | memcpy(kbd->old, kbd->new, 8); | ||
| 126 | } | ||
| 127 | |||
| 128 | static void dc_kbd_callback(struct mapleq *mq) | ||
| 129 | { | ||
| 130 | struct maple_device *mapledev = mq->dev; | ||
| 131 | struct dc_kbd *kbd = mapledev->private_data; | ||
| 132 | unsigned long *buf = mq->recvbuf; | ||
| 133 | |||
| 134 | /* | ||
| 135 | * We should always be getting the lock because the only | ||
| 136 | * time it may be locked if driver is in cleanup phase. | ||
| 137 | */ | ||
| 138 | if (likely(mutex_trylock(&maple_keyb_mutex))) { | ||
| 139 | |||
| 140 | if (buf[1] == mapledev->function) { | ||
| 141 | memcpy(kbd->new, buf + 2, 8); | ||
| 142 | dc_scan_kbd(kbd); | ||
| 143 | } | ||
| 144 | |||
| 145 | mutex_unlock(&maple_keyb_mutex); | ||
| 146 | } | ||
| 147 | } | ||
| 148 | |||
| 149 | static int dc_kbd_connect(struct maple_device *mdev) | ||
| 150 | { | ||
| 151 | int i, error; | ||
| 152 | struct dc_kbd *kbd; | ||
| 153 | struct input_dev *dev; | ||
| 154 | |||
| 155 | if (!(mdev->function & MAPLE_FUNC_KEYBOARD)) | ||
| 156 | return -EINVAL; | ||
| 157 | |||
| 158 | kbd = kzalloc(sizeof(struct dc_kbd), GFP_KERNEL); | ||
| 159 | dev = input_allocate_device(); | ||
| 160 | if (!kbd || !dev) { | ||
| 161 | error = -ENOMEM; | ||
| 162 | goto fail; | ||
| 163 | } | ||
| 164 | |||
| 165 | mdev->private_data = kbd; | ||
| 166 | |||
| 167 | kbd->dev = dev; | ||
| 168 | memcpy(kbd->keycode, dc_kbd_keycode, sizeof(kbd->keycode)); | ||
| 169 | |||
| 170 | dev->name = mdev->product_name; | ||
| 171 | dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP); | ||
| 172 | dev->keycode = kbd->keycode; | ||
| 173 | dev->keycodesize = sizeof (unsigned short); | ||
| 174 | dev->keycodemax = ARRAY_SIZE(kbd->keycode); | ||
| 175 | dev->id.bustype = BUS_HOST; | ||
| 176 | dev->dev.parent = &mdev->dev; | ||
| 177 | |||
| 178 | for (i = 0; i < NR_SCANCODES; i++) | ||
| 179 | __set_bit(dc_kbd_keycode[i], dev->keybit); | ||
| 180 | __clear_bit(KEY_RESERVED, dev->keybit); | ||
| 181 | |||
| 182 | input_set_capability(dev, EV_MSC, MSC_SCAN); | ||
| 183 | input_set_drvdata(dev, kbd); | ||
| 184 | |||
| 185 | error = input_register_device(dev); | ||
| 186 | if (error) | ||
| 187 | goto fail; | ||
| 188 | |||
| 189 | /* Maple polling is locked to VBLANK - which may be just 50/s */ | ||
| 190 | maple_getcond_callback(mdev, dc_kbd_callback, HZ/50, MAPLE_FUNC_KEYBOARD); | ||
| 191 | return 0; | ||
| 192 | |||
| 193 | fail: | ||
| 194 | input_free_device(dev); | ||
| 195 | kfree(kbd); | ||
| 196 | mdev->private_data = NULL; | ||
| 197 | return error; | ||
| 198 | } | ||
| 199 | |||
| 200 | static void dc_kbd_disconnect(struct maple_device *mdev) | ||
| 201 | { | ||
| 202 | struct dc_kbd *kbd; | ||
| 203 | |||
| 204 | mutex_lock(&maple_keyb_mutex); | ||
| 205 | |||
| 206 | kbd = mdev->private_data; | ||
| 207 | mdev->private_data = NULL; | ||
| 208 | input_unregister_device(kbd->dev); | ||
| 209 | kfree(kbd); | ||
| 210 | |||
| 211 | mutex_unlock(&maple_keyb_mutex); | ||
| 212 | } | ||
| 213 | |||
| 214 | /* allow the keyboard to be used */ | ||
| 215 | static int probe_maple_kbd(struct device *dev) | ||
| 216 | { | ||
| 217 | struct maple_device *mdev = to_maple_dev(dev); | ||
| 218 | struct maple_driver *mdrv = to_maple_driver(dev->driver); | ||
| 219 | int error; | ||
| 220 | |||
| 221 | error = dc_kbd_connect(mdev); | ||
| 222 | if (error) | ||
| 223 | return error; | ||
| 224 | |||
| 225 | mdev->driver = mdrv; | ||
| 226 | mdev->registered = 1; | ||
| 227 | |||
| 228 | return 0; | ||
| 229 | } | ||
| 230 | |||
| 231 | static struct maple_driver dc_kbd_driver = { | ||
| 232 | .function = MAPLE_FUNC_KEYBOARD, | ||
| 233 | .connect = dc_kbd_connect, | ||
| 234 | .disconnect = dc_kbd_disconnect, | ||
| 235 | .drv = { | ||
| 236 | .name = "Dreamcast_keyboard", | ||
| 237 | .probe = probe_maple_kbd, | ||
| 238 | }, | ||
| 239 | }; | ||
| 240 | |||
| 241 | static int __init dc_kbd_init(void) | ||
| 242 | { | ||
| 243 | return maple_driver_register(&dc_kbd_driver.drv); | ||
| 244 | } | ||
| 245 | |||
| 246 | static void __exit dc_kbd_exit(void) | ||
| 247 | { | ||
| 248 | driver_unregister(&dc_kbd_driver.drv); | ||
| 249 | } | ||
| 250 | |||
| 251 | module_init(dc_kbd_init); | ||
| 252 | module_exit(dc_kbd_exit); | ||
diff --git a/drivers/input/keyboard/omap-keypad.c b/drivers/input/keyboard/omap-keypad.c index 3a228634f101..76f1969552c5 100644 --- a/drivers/input/keyboard/omap-keypad.c +++ b/drivers/input/keyboard/omap-keypad.c | |||
| @@ -233,7 +233,7 @@ static void omap_kp_tasklet(unsigned long data) | |||
| 233 | omap_writew(0, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT); | 233 | omap_writew(0, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT); |
| 234 | kp_cur_group = -1; | 234 | kp_cur_group = -1; |
| 235 | } | 235 | } |
| 236 | } | 236 | } |
| 237 | } | 237 | } |
| 238 | 238 | ||
| 239 | static ssize_t omap_kp_enable_show(struct device *dev, | 239 | static ssize_t omap_kp_enable_show(struct device *dev, |
| @@ -318,7 +318,7 @@ static int __init omap_kp_probe(struct platform_device *pdev) | |||
| 318 | keymap = pdata->keymap; | 318 | keymap = pdata->keymap; |
| 319 | 319 | ||
| 320 | if (pdata->rep) | 320 | if (pdata->rep) |
| 321 | set_bit(EV_REP, input_dev->evbit); | 321 | __set_bit(EV_REP, input_dev->evbit); |
| 322 | 322 | ||
| 323 | if (pdata->delay) | 323 | if (pdata->delay) |
| 324 | omap_kp->delay = pdata->delay; | 324 | omap_kp->delay = pdata->delay; |
| @@ -365,9 +365,9 @@ static int __init omap_kp_probe(struct platform_device *pdev) | |||
| 365 | goto err2; | 365 | goto err2; |
| 366 | 366 | ||
| 367 | /* setup input device */ | 367 | /* setup input device */ |
| 368 | set_bit(EV_KEY, input_dev->evbit); | 368 | __set_bit(EV_KEY, input_dev->evbit); |
| 369 | for (i = 0; keymap[i] != 0; i++) | 369 | for (i = 0; keymap[i] != 0; i++) |
| 370 | set_bit(keymap[i] & KEY_MAX, input_dev->keybit); | 370 | __set_bit(keymap[i] & KEY_MAX, input_dev->keybit); |
| 371 | input_dev->name = "omap-keypad"; | 371 | input_dev->name = "omap-keypad"; |
| 372 | input_dev->phys = "omap-keypad/input0"; | 372 | input_dev->phys = "omap-keypad/input0"; |
| 373 | input_dev->dev.parent = &pdev->dev; | 373 | input_dev->dev.parent = &pdev->dev; |
| @@ -377,10 +377,6 @@ static int __init omap_kp_probe(struct platform_device *pdev) | |||
| 377 | input_dev->id.product = 0x0001; | 377 | input_dev->id.product = 0x0001; |
| 378 | input_dev->id.version = 0x0100; | 378 | input_dev->id.version = 0x0100; |
| 379 | 379 | ||
| 380 | input_dev->keycode = keymap; | ||
| 381 | input_dev->keycodesize = sizeof(unsigned int); | ||
| 382 | input_dev->keycodemax = pdata->keymapsize; | ||
| 383 | |||
| 384 | ret = input_register_device(omap_kp->input); | 380 | ret = input_register_device(omap_kp->input); |
| 385 | if (ret < 0) { | 381 | if (ret < 0) { |
| 386 | printk(KERN_ERR "Unable to register omap-keypad input device\n"); | 382 | printk(KERN_ERR "Unable to register omap-keypad input device\n"); |
| @@ -403,15 +399,15 @@ static int __init omap_kp_probe(struct platform_device *pdev) | |||
| 403 | } else { | 399 | } else { |
| 404 | for (irq_idx = 0; irq_idx < omap_kp->rows; irq_idx++) { | 400 | for (irq_idx = 0; irq_idx < omap_kp->rows; irq_idx++) { |
| 405 | if (request_irq(OMAP_GPIO_IRQ(row_gpios[irq_idx]), | 401 | if (request_irq(OMAP_GPIO_IRQ(row_gpios[irq_idx]), |
| 406 | omap_kp_interrupt, | 402 | omap_kp_interrupt, |
| 407 | IRQF_TRIGGER_FALLING, | 403 | IRQF_TRIGGER_FALLING, |
| 408 | "omap-keypad", omap_kp) < 0) | 404 | "omap-keypad", omap_kp) < 0) |
| 409 | goto err5; | 405 | goto err5; |
| 410 | } | 406 | } |
| 411 | } | 407 | } |
| 412 | return 0; | 408 | return 0; |
| 413 | err5: | 409 | err5: |
| 414 | for (i = irq_idx-1; i >=0; i--) | 410 | for (i = irq_idx - 1; i >=0; i--) |
| 415 | free_irq(row_gpios[i], 0); | 411 | free_irq(row_gpios[i], 0); |
| 416 | err4: | 412 | err4: |
| 417 | input_unregister_device(omap_kp->input); | 413 | input_unregister_device(omap_kp->input); |
| @@ -440,9 +436,9 @@ static int omap_kp_remove(struct platform_device *pdev) | |||
| 440 | if (cpu_is_omap24xx()) { | 436 | if (cpu_is_omap24xx()) { |
| 441 | int i; | 437 | int i; |
| 442 | for (i = 0; i < omap_kp->cols; i++) | 438 | for (i = 0; i < omap_kp->cols; i++) |
| 443 | omap_free_gpio(col_gpios[i]); | 439 | omap_free_gpio(col_gpios[i]); |
| 444 | for (i = 0; i < omap_kp->rows; i++) { | 440 | for (i = 0; i < omap_kp->rows; i++) { |
| 445 | omap_free_gpio(row_gpios[i]); | 441 | omap_free_gpio(row_gpios[i]); |
| 446 | free_irq(OMAP_GPIO_IRQ(row_gpios[i]), 0); | 442 | free_irq(OMAP_GPIO_IRQ(row_gpios[i]), 0); |
| 447 | } | 443 | } |
| 448 | } else { | 444 | } else { |
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index 2c5f11a4f6b4..64d70a9b714c 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c | |||
| @@ -48,11 +48,13 @@ static const struct alps_model_info alps_model_data[] = { | |||
| 48 | { { 0x63, 0x02, 0x50 }, 0xef, 0xef, ALPS_FW_BK_1 }, /* NEC Versa L320 */ | 48 | { { 0x63, 0x02, 0x50 }, 0xef, 0xef, ALPS_FW_BK_1 }, /* NEC Versa L320 */ |
| 49 | { { 0x63, 0x02, 0x64 }, 0xf8, 0xf8, 0 }, | 49 | { { 0x63, 0x02, 0x64 }, 0xf8, 0xf8, 0 }, |
| 50 | { { 0x63, 0x03, 0xc8 }, 0xf8, 0xf8, ALPS_PASS }, /* Dell Latitude D800 */ | 50 | { { 0x63, 0x03, 0xc8 }, 0xf8, 0xf8, ALPS_PASS }, /* Dell Latitude D800 */ |
| 51 | { { 0x73, 0x00, 0x0a }, 0xf8, 0xf8, ALPS_DUALPOINT }, /* ThinkPad R61 8918-5QG */ | ||
| 51 | { { 0x73, 0x02, 0x0a }, 0xf8, 0xf8, 0 }, | 52 | { { 0x73, 0x02, 0x0a }, 0xf8, 0xf8, 0 }, |
| 52 | { { 0x73, 0x02, 0x14 }, 0xf8, 0xf8, ALPS_FW_BK_2 }, /* Ahtec Laptop */ | 53 | { { 0x73, 0x02, 0x14 }, 0xf8, 0xf8, ALPS_FW_BK_2 }, /* Ahtec Laptop */ |
| 53 | { { 0x20, 0x02, 0x0e }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* XXX */ | 54 | { { 0x20, 0x02, 0x0e }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* XXX */ |
| 54 | { { 0x22, 0x02, 0x0a }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, | 55 | { { 0x22, 0x02, 0x0a }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, |
| 55 | { { 0x22, 0x02, 0x14 }, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D600 */ | 56 | { { 0x22, 0x02, 0x14 }, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D600 */ |
| 57 | { { 0x73, 0x02, 0x50 }, 0xcf, 0xff, ALPS_FW_BK_1 } /* Dell Vostro 1400 */ | ||
| 56 | }; | 58 | }; |
| 57 | 59 | ||
| 58 | /* | 60 | /* |
diff --git a/drivers/input/mouse/appletouch.c b/drivers/input/mouse/appletouch.c index a1804bfdbb8c..0117817bf538 100644 --- a/drivers/input/mouse/appletouch.c +++ b/drivers/input/mouse/appletouch.c | |||
| @@ -502,18 +502,23 @@ static void atp_complete(struct urb* urb) | |||
| 502 | 502 | ||
| 503 | /* reset the accumulator on release */ | 503 | /* reset the accumulator on release */ |
| 504 | memset(dev->xy_acc, 0, sizeof(dev->xy_acc)); | 504 | memset(dev->xy_acc, 0, sizeof(dev->xy_acc)); |
| 505 | } | ||
| 506 | |||
| 507 | /* Geyser 3 will continue to send packets continually after | ||
| 508 | the first touch unless reinitialised. Do so if it's been | ||
| 509 | idle for a while in order to avoid waking the kernel up | ||
| 510 | several hundred times a second */ | ||
| 505 | 511 | ||
| 506 | /* Geyser 3 will continue to send packets continually after | 512 | if (atp_is_geyser_3(dev)) { |
| 507 | the first touch unless reinitialised. Do so if it's been | 513 | if (!x && !y && !key) { |
| 508 | idle for a while in order to avoid waking the kernel up | ||
| 509 | several hundred times a second */ | ||
| 510 | if (!key && atp_is_geyser_3(dev)) { | ||
| 511 | dev->idlecount++; | 514 | dev->idlecount++; |
| 512 | if (dev->idlecount == 10) { | 515 | if (dev->idlecount == 10) { |
| 513 | dev->valid = 0; | 516 | dev->valid = 0; |
| 514 | schedule_work(&dev->work); | 517 | schedule_work(&dev->work); |
| 515 | } | 518 | } |
| 516 | } | 519 | } |
| 520 | else | ||
| 521 | dev->idlecount = 0; | ||
| 517 | } | 522 | } |
| 518 | 523 | ||
| 519 | input_report_key(dev->input, BTN_LEFT, key); | 524 | input_report_key(dev->input, BTN_LEFT, key); |
diff --git a/drivers/input/mouse/lifebook.c b/drivers/input/mouse/lifebook.c index 608674d0be8b..d7de4c53b3d8 100644 --- a/drivers/input/mouse/lifebook.c +++ b/drivers/input/mouse/lifebook.c | |||
| @@ -97,6 +97,14 @@ static const struct dmi_system_id lifebook_dmi_table[] = { | |||
| 97 | .callback = lifebook_set_6byte_proto, | 97 | .callback = lifebook_set_6byte_proto, |
| 98 | }, | 98 | }, |
| 99 | { | 99 | { |
| 100 | .ident = "CF-72", | ||
| 101 | .matches = { | ||
| 102 | DMI_MATCH(DMI_PRODUCT_NAME, "CF-72"), | ||
| 103 | }, | ||
| 104 | .callback = lifebook_set_serio_phys, | ||
| 105 | .driver_data = "isa0060/serio3", | ||
| 106 | }, | ||
| 107 | { | ||
| 100 | .ident = "Lifebook B142", | 108 | .ident = "Lifebook B142", |
| 101 | .matches = { | 109 | .matches = { |
| 102 | DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook B142"), | 110 | DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook B142"), |
| @@ -282,7 +290,7 @@ static int lifebook_create_relative_device(struct psmouse *psmouse) | |||
| 282 | int lifebook_init(struct psmouse *psmouse) | 290 | int lifebook_init(struct psmouse *psmouse) |
| 283 | { | 291 | { |
| 284 | struct input_dev *dev1 = psmouse->dev; | 292 | struct input_dev *dev1 = psmouse->dev; |
| 285 | int max_coord = lifebook_use_6byte_proto ? 1024 : 4096; | 293 | int max_coord = lifebook_use_6byte_proto ? 4096 : 1024; |
| 286 | 294 | ||
| 287 | if (lifebook_absolute_mode(psmouse)) | 295 | if (lifebook_absolute_mode(psmouse)) |
| 288 | return -1; | 296 | return -1; |
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index b9f0fb2530e2..073525756532 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c | |||
| @@ -648,9 +648,10 @@ static int psmouse_extensions(struct psmouse *psmouse, | |||
| 648 | 648 | ||
| 649 | /* | 649 | /* |
| 650 | * Reset to defaults in case the device got confused by extended | 650 | * Reset to defaults in case the device got confused by extended |
| 651 | * protocol probes. Note that we do full reset becuase some mice | 651 | * protocol probes. Note that we follow up with full reset because |
| 652 | * put themselves to sleep when see PSMOUSE_RESET_DIS. | 652 | * some mice put themselves to sleep when they see PSMOUSE_RESET_DIS. |
| 653 | */ | 653 | */ |
| 654 | ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS); | ||
| 654 | psmouse_reset(psmouse); | 655 | psmouse_reset(psmouse); |
| 655 | 656 | ||
| 656 | if (max_proto >= PSMOUSE_IMEX && im_explorer_detect(psmouse, set_properties) == 0) | 657 | if (max_proto >= PSMOUSE_IMEX && im_explorer_detect(psmouse, set_properties) == 0) |
diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c index 9173916b8be5..79146d6ed2ab 100644 --- a/drivers/input/mousedev.c +++ b/drivers/input/mousedev.c | |||
| @@ -61,9 +61,11 @@ struct mousedev { | |||
| 61 | int open; | 61 | int open; |
| 62 | int minor; | 62 | int minor; |
| 63 | char name[16]; | 63 | char name[16]; |
| 64 | struct input_handle handle; | ||
| 64 | wait_queue_head_t wait; | 65 | wait_queue_head_t wait; |
| 65 | struct list_head client_list; | 66 | struct list_head client_list; |
| 66 | struct input_handle handle; | 67 | spinlock_t client_lock; /* protects client_list */ |
| 68 | struct mutex mutex; | ||
| 67 | struct device dev; | 69 | struct device dev; |
| 68 | 70 | ||
| 69 | struct list_head mixdev_node; | 71 | struct list_head mixdev_node; |
| @@ -113,108 +115,137 @@ static unsigned char mousedev_imex_seq[] = { 0xf3, 200, 0xf3, 200, 0xf3, 80 }; | |||
| 113 | static struct input_handler mousedev_handler; | 115 | static struct input_handler mousedev_handler; |
| 114 | 116 | ||
| 115 | static struct mousedev *mousedev_table[MOUSEDEV_MINORS]; | 117 | static struct mousedev *mousedev_table[MOUSEDEV_MINORS]; |
| 118 | static DEFINE_MUTEX(mousedev_table_mutex); | ||
| 116 | static struct mousedev *mousedev_mix; | 119 | static struct mousedev *mousedev_mix; |
| 117 | static LIST_HEAD(mousedev_mix_list); | 120 | static LIST_HEAD(mousedev_mix_list); |
| 118 | 121 | ||
| 122 | static void mixdev_open_devices(void); | ||
| 123 | static void mixdev_close_devices(void); | ||
| 124 | |||
| 119 | #define fx(i) (mousedev->old_x[(mousedev->pkt_count - (i)) & 03]) | 125 | #define fx(i) (mousedev->old_x[(mousedev->pkt_count - (i)) & 03]) |
| 120 | #define fy(i) (mousedev->old_y[(mousedev->pkt_count - (i)) & 03]) | 126 | #define fy(i) (mousedev->old_y[(mousedev->pkt_count - (i)) & 03]) |
| 121 | 127 | ||
| 122 | static void mousedev_touchpad_event(struct input_dev *dev, struct mousedev *mousedev, unsigned int code, int value) | 128 | static void mousedev_touchpad_event(struct input_dev *dev, |
| 129 | struct mousedev *mousedev, | ||
| 130 | unsigned int code, int value) | ||
| 123 | { | 131 | { |
| 124 | int size, tmp; | 132 | int size, tmp; |
| 125 | enum { FRACTION_DENOM = 128 }; | 133 | enum { FRACTION_DENOM = 128 }; |
| 126 | 134 | ||
| 127 | switch (code) { | 135 | switch (code) { |
| 128 | case ABS_X: | ||
| 129 | fx(0) = value; | ||
| 130 | if (mousedev->touch && mousedev->pkt_count >= 2) { | ||
| 131 | size = dev->absmax[ABS_X] - dev->absmin[ABS_X]; | ||
| 132 | if (size == 0) | ||
| 133 | size = 256 * 2; | ||
| 134 | tmp = ((value - fx(2)) * (256 * FRACTION_DENOM)) / size; | ||
| 135 | tmp += mousedev->frac_dx; | ||
| 136 | mousedev->packet.dx = tmp / FRACTION_DENOM; | ||
| 137 | mousedev->frac_dx = tmp - mousedev->packet.dx * FRACTION_DENOM; | ||
| 138 | } | ||
| 139 | break; | ||
| 140 | 136 | ||
| 141 | case ABS_Y: | 137 | case ABS_X: |
| 142 | fy(0) = value; | 138 | fx(0) = value; |
| 143 | if (mousedev->touch && mousedev->pkt_count >= 2) { | 139 | if (mousedev->touch && mousedev->pkt_count >= 2) { |
| 144 | /* use X size to keep the same scale */ | 140 | size = dev->absmax[ABS_X] - dev->absmin[ABS_X]; |
| 145 | size = dev->absmax[ABS_X] - dev->absmin[ABS_X]; | 141 | if (size == 0) |
| 146 | if (size == 0) | 142 | size = 256 * 2; |
| 147 | size = 256 * 2; | 143 | tmp = ((value - fx(2)) * 256 * FRACTION_DENOM) / size; |
| 148 | tmp = -((value - fy(2)) * (256 * FRACTION_DENOM)) / size; | 144 | tmp += mousedev->frac_dx; |
| 149 | tmp += mousedev->frac_dy; | 145 | mousedev->packet.dx = tmp / FRACTION_DENOM; |
| 150 | mousedev->packet.dy = tmp / FRACTION_DENOM; | 146 | mousedev->frac_dx = |
| 151 | mousedev->frac_dy = tmp - mousedev->packet.dy * FRACTION_DENOM; | 147 | tmp - mousedev->packet.dx * FRACTION_DENOM; |
| 152 | } | 148 | } |
| 153 | break; | 149 | break; |
| 150 | |||
| 151 | case ABS_Y: | ||
| 152 | fy(0) = value; | ||
| 153 | if (mousedev->touch && mousedev->pkt_count >= 2) { | ||
| 154 | /* use X size to keep the same scale */ | ||
| 155 | size = dev->absmax[ABS_X] - dev->absmin[ABS_X]; | ||
| 156 | if (size == 0) | ||
| 157 | size = 256 * 2; | ||
| 158 | tmp = -((value - fy(2)) * 256 * FRACTION_DENOM) / size; | ||
| 159 | tmp += mousedev->frac_dy; | ||
| 160 | mousedev->packet.dy = tmp / FRACTION_DENOM; | ||
| 161 | mousedev->frac_dy = tmp - | ||
| 162 | mousedev->packet.dy * FRACTION_DENOM; | ||
| 163 | } | ||
| 164 | break; | ||
| 154 | } | 165 | } |
| 155 | } | 166 | } |
| 156 | 167 | ||
| 157 | static void mousedev_abs_event(struct input_dev *dev, struct mousedev *mousedev, unsigned int code, int value) | 168 | static void mousedev_abs_event(struct input_dev *dev, struct mousedev *mousedev, |
| 169 | unsigned int code, int value) | ||
| 158 | { | 170 | { |
| 159 | int size; | 171 | int size; |
| 160 | 172 | ||
| 161 | switch (code) { | 173 | switch (code) { |
| 162 | case ABS_X: | ||
| 163 | size = dev->absmax[ABS_X] - dev->absmin[ABS_X]; | ||
| 164 | if (size == 0) | ||
| 165 | size = xres ? : 1; | ||
| 166 | if (value > dev->absmax[ABS_X]) | ||
| 167 | value = dev->absmax[ABS_X]; | ||
| 168 | if (value < dev->absmin[ABS_X]) | ||
| 169 | value = dev->absmin[ABS_X]; | ||
| 170 | mousedev->packet.x = ((value - dev->absmin[ABS_X]) * xres) / size; | ||
| 171 | mousedev->packet.abs_event = 1; | ||
| 172 | break; | ||
| 173 | 174 | ||
| 174 | case ABS_Y: | 175 | case ABS_X: |
| 175 | size = dev->absmax[ABS_Y] - dev->absmin[ABS_Y]; | 176 | size = dev->absmax[ABS_X] - dev->absmin[ABS_X]; |
| 176 | if (size == 0) | 177 | if (size == 0) |
| 177 | size = yres ? : 1; | 178 | size = xres ? : 1; |
| 178 | if (value > dev->absmax[ABS_Y]) | 179 | if (value > dev->absmax[ABS_X]) |
| 179 | value = dev->absmax[ABS_Y]; | 180 | value = dev->absmax[ABS_X]; |
| 180 | if (value < dev->absmin[ABS_Y]) | 181 | if (value < dev->absmin[ABS_X]) |
| 181 | value = dev->absmin[ABS_Y]; | 182 | value = dev->absmin[ABS_X]; |
| 182 | mousedev->packet.y = yres - ((value - dev->absmin[ABS_Y]) * yres) / size; | 183 | mousedev->packet.x = |
| 183 | mousedev->packet.abs_event = 1; | 184 | ((value - dev->absmin[ABS_X]) * xres) / size; |
| 184 | break; | 185 | mousedev->packet.abs_event = 1; |
| 186 | break; | ||
| 187 | |||
| 188 | case ABS_Y: | ||
| 189 | size = dev->absmax[ABS_Y] - dev->absmin[ABS_Y]; | ||
| 190 | if (size == 0) | ||
| 191 | size = yres ? : 1; | ||
| 192 | if (value > dev->absmax[ABS_Y]) | ||
| 193 | value = dev->absmax[ABS_Y]; | ||
| 194 | if (value < dev->absmin[ABS_Y]) | ||
| 195 | value = dev->absmin[ABS_Y]; | ||
| 196 | mousedev->packet.y = yres - | ||
| 197 | ((value - dev->absmin[ABS_Y]) * yres) / size; | ||
| 198 | mousedev->packet.abs_event = 1; | ||
| 199 | break; | ||
| 185 | } | 200 | } |
| 186 | } | 201 | } |
| 187 | 202 | ||
| 188 | static void mousedev_rel_event(struct mousedev *mousedev, unsigned int code, int value) | 203 | static void mousedev_rel_event(struct mousedev *mousedev, |
| 204 | unsigned int code, int value) | ||
| 189 | { | 205 | { |
| 190 | switch (code) { | 206 | switch (code) { |
| 191 | case REL_X: mousedev->packet.dx += value; break; | 207 | case REL_X: |
| 192 | case REL_Y: mousedev->packet.dy -= value; break; | 208 | mousedev->packet.dx += value; |
| 193 | case REL_WHEEL: mousedev->packet.dz -= value; break; | 209 | break; |
| 210 | |||
| 211 | case REL_Y: | ||
| 212 | mousedev->packet.dy -= value; | ||
| 213 | break; | ||
| 214 | |||
| 215 | case REL_WHEEL: | ||
| 216 | mousedev->packet.dz -= value; | ||
| 217 | break; | ||
| 194 | } | 218 | } |
| 195 | } | 219 | } |
| 196 | 220 | ||
| 197 | static void mousedev_key_event(struct mousedev *mousedev, unsigned int code, int value) | 221 | static void mousedev_key_event(struct mousedev *mousedev, |
| 222 | unsigned int code, int value) | ||
| 198 | { | 223 | { |
| 199 | int index; | 224 | int index; |
| 200 | 225 | ||
| 201 | switch (code) { | 226 | switch (code) { |
| 202 | case BTN_TOUCH: | 227 | |
| 203 | case BTN_0: | 228 | case BTN_TOUCH: |
| 204 | case BTN_LEFT: index = 0; break; | 229 | case BTN_0: |
| 205 | case BTN_STYLUS: | 230 | case BTN_LEFT: index = 0; break; |
| 206 | case BTN_1: | 231 | |
| 207 | case BTN_RIGHT: index = 1; break; | 232 | case BTN_STYLUS: |
| 208 | case BTN_2: | 233 | case BTN_1: |
| 209 | case BTN_FORWARD: | 234 | case BTN_RIGHT: index = 1; break; |
| 210 | case BTN_STYLUS2: | 235 | |
| 211 | case BTN_MIDDLE: index = 2; break; | 236 | case BTN_2: |
| 212 | case BTN_3: | 237 | case BTN_FORWARD: |
| 213 | case BTN_BACK: | 238 | case BTN_STYLUS2: |
| 214 | case BTN_SIDE: index = 3; break; | 239 | case BTN_MIDDLE: index = 2; break; |
| 215 | case BTN_4: | 240 | |
| 216 | case BTN_EXTRA: index = 4; break; | 241 | case BTN_3: |
| 217 | default: return; | 242 | case BTN_BACK: |
| 243 | case BTN_SIDE: index = 3; break; | ||
| 244 | |||
| 245 | case BTN_4: | ||
| 246 | case BTN_EXTRA: index = 4; break; | ||
| 247 | |||
| 248 | default: return; | ||
| 218 | } | 249 | } |
| 219 | 250 | ||
| 220 | if (value) { | 251 | if (value) { |
| @@ -226,19 +257,23 @@ static void mousedev_key_event(struct mousedev *mousedev, unsigned int code, int | |||
| 226 | } | 257 | } |
| 227 | } | 258 | } |
| 228 | 259 | ||
| 229 | static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_hw_data *packet) | 260 | static void mousedev_notify_readers(struct mousedev *mousedev, |
| 261 | struct mousedev_hw_data *packet) | ||
| 230 | { | 262 | { |
| 231 | struct mousedev_client *client; | 263 | struct mousedev_client *client; |
| 232 | struct mousedev_motion *p; | 264 | struct mousedev_motion *p; |
| 233 | unsigned long flags; | 265 | unsigned int new_head; |
| 234 | int wake_readers = 0; | 266 | int wake_readers = 0; |
| 235 | 267 | ||
| 236 | list_for_each_entry(client, &mousedev->client_list, node) { | 268 | rcu_read_lock(); |
| 237 | spin_lock_irqsave(&client->packet_lock, flags); | 269 | list_for_each_entry_rcu(client, &mousedev->client_list, node) { |
| 270 | |||
| 271 | /* Just acquire the lock, interrupts already disabled */ | ||
| 272 | spin_lock(&client->packet_lock); | ||
| 238 | 273 | ||
| 239 | p = &client->packets[client->head]; | 274 | p = &client->packets[client->head]; |
| 240 | if (client->ready && p->buttons != mousedev->packet.buttons) { | 275 | if (client->ready && p->buttons != mousedev->packet.buttons) { |
| 241 | unsigned int new_head = (client->head + 1) % PACKET_QUEUE_LEN; | 276 | new_head = (client->head + 1) % PACKET_QUEUE_LEN; |
| 242 | if (new_head != client->tail) { | 277 | if (new_head != client->tail) { |
| 243 | p = &client->packets[client->head = new_head]; | 278 | p = &client->packets[client->head = new_head]; |
| 244 | memset(p, 0, sizeof(struct mousedev_motion)); | 279 | memset(p, 0, sizeof(struct mousedev_motion)); |
| @@ -253,25 +288,29 @@ static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_h | |||
| 253 | } | 288 | } |
| 254 | 289 | ||
| 255 | client->pos_x += packet->dx; | 290 | client->pos_x += packet->dx; |
| 256 | client->pos_x = client->pos_x < 0 ? 0 : (client->pos_x >= xres ? xres : client->pos_x); | 291 | client->pos_x = client->pos_x < 0 ? |
| 292 | 0 : (client->pos_x >= xres ? xres : client->pos_x); | ||
| 257 | client->pos_y += packet->dy; | 293 | client->pos_y += packet->dy; |
| 258 | client->pos_y = client->pos_y < 0 ? 0 : (client->pos_y >= yres ? yres : client->pos_y); | 294 | client->pos_y = client->pos_y < 0 ? |
| 295 | 0 : (client->pos_y >= yres ? yres : client->pos_y); | ||
| 259 | 296 | ||
| 260 | p->dx += packet->dx; | 297 | p->dx += packet->dx; |
| 261 | p->dy += packet->dy; | 298 | p->dy += packet->dy; |
| 262 | p->dz += packet->dz; | 299 | p->dz += packet->dz; |
| 263 | p->buttons = mousedev->packet.buttons; | 300 | p->buttons = mousedev->packet.buttons; |
| 264 | 301 | ||
| 265 | if (p->dx || p->dy || p->dz || p->buttons != client->last_buttons) | 302 | if (p->dx || p->dy || p->dz || |
| 303 | p->buttons != client->last_buttons) | ||
| 266 | client->ready = 1; | 304 | client->ready = 1; |
| 267 | 305 | ||
| 268 | spin_unlock_irqrestore(&client->packet_lock, flags); | 306 | spin_unlock(&client->packet_lock); |
| 269 | 307 | ||
| 270 | if (client->ready) { | 308 | if (client->ready) { |
| 271 | kill_fasync(&client->fasync, SIGIO, POLL_IN); | 309 | kill_fasync(&client->fasync, SIGIO, POLL_IN); |
| 272 | wake_readers = 1; | 310 | wake_readers = 1; |
| 273 | } | 311 | } |
| 274 | } | 312 | } |
| 313 | rcu_read_unlock(); | ||
| 275 | 314 | ||
| 276 | if (wake_readers) | 315 | if (wake_readers) |
| 277 | wake_up_interruptible(&mousedev->wait); | 316 | wake_up_interruptible(&mousedev->wait); |
| @@ -281,7 +320,8 @@ static void mousedev_touchpad_touch(struct mousedev *mousedev, int value) | |||
| 281 | { | 320 | { |
| 282 | if (!value) { | 321 | if (!value) { |
| 283 | if (mousedev->touch && | 322 | if (mousedev->touch && |
| 284 | time_before(jiffies, mousedev->touch + msecs_to_jiffies(tap_time))) { | 323 | time_before(jiffies, |
| 324 | mousedev->touch + msecs_to_jiffies(tap_time))) { | ||
| 285 | /* | 325 | /* |
| 286 | * Toggle left button to emulate tap. | 326 | * Toggle left button to emulate tap. |
| 287 | * We rely on the fact that mousedev_mix always has 0 | 327 | * We rely on the fact that mousedev_mix always has 0 |
| @@ -290,7 +330,8 @@ static void mousedev_touchpad_touch(struct mousedev *mousedev, int value) | |||
| 290 | set_bit(0, &mousedev->packet.buttons); | 330 | set_bit(0, &mousedev->packet.buttons); |
| 291 | set_bit(0, &mousedev_mix->packet.buttons); | 331 | set_bit(0, &mousedev_mix->packet.buttons); |
| 292 | mousedev_notify_readers(mousedev, &mousedev_mix->packet); | 332 | mousedev_notify_readers(mousedev, &mousedev_mix->packet); |
| 293 | mousedev_notify_readers(mousedev_mix, &mousedev_mix->packet); | 333 | mousedev_notify_readers(mousedev_mix, |
| 334 | &mousedev_mix->packet); | ||
| 294 | clear_bit(0, &mousedev->packet.buttons); | 335 | clear_bit(0, &mousedev->packet.buttons); |
| 295 | clear_bit(0, &mousedev_mix->packet.buttons); | 336 | clear_bit(0, &mousedev_mix->packet.buttons); |
| 296 | } | 337 | } |
| @@ -302,54 +343,61 @@ static void mousedev_touchpad_touch(struct mousedev *mousedev, int value) | |||
| 302 | mousedev->touch = jiffies; | 343 | mousedev->touch = jiffies; |
| 303 | } | 344 | } |
| 304 | 345 | ||
| 305 | static void mousedev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) | 346 | static void mousedev_event(struct input_handle *handle, |
| 347 | unsigned int type, unsigned int code, int value) | ||
| 306 | { | 348 | { |
| 307 | struct mousedev *mousedev = handle->private; | 349 | struct mousedev *mousedev = handle->private; |
| 308 | 350 | ||
| 309 | switch (type) { | 351 | switch (type) { |
| 310 | case EV_ABS: | ||
| 311 | /* Ignore joysticks */ | ||
| 312 | if (test_bit(BTN_TRIGGER, handle->dev->keybit)) | ||
| 313 | return; | ||
| 314 | 352 | ||
| 315 | if (test_bit(BTN_TOOL_FINGER, handle->dev->keybit)) | 353 | case EV_ABS: |
| 316 | mousedev_touchpad_event(handle->dev, mousedev, code, value); | 354 | /* Ignore joysticks */ |
| 317 | else | 355 | if (test_bit(BTN_TRIGGER, handle->dev->keybit)) |
| 318 | mousedev_abs_event(handle->dev, mousedev, code, value); | 356 | return; |
| 319 | 357 | ||
| 320 | break; | 358 | if (test_bit(BTN_TOOL_FINGER, handle->dev->keybit)) |
| 359 | mousedev_touchpad_event(handle->dev, | ||
| 360 | mousedev, code, value); | ||
| 361 | else | ||
| 362 | mousedev_abs_event(handle->dev, mousedev, code, value); | ||
| 321 | 363 | ||
| 322 | case EV_REL: | 364 | break; |
| 323 | mousedev_rel_event(mousedev, code, value); | ||
| 324 | break; | ||
| 325 | 365 | ||
| 326 | case EV_KEY: | 366 | case EV_REL: |
| 327 | if (value != 2) { | 367 | mousedev_rel_event(mousedev, code, value); |
| 328 | if (code == BTN_TOUCH && test_bit(BTN_TOOL_FINGER, handle->dev->keybit)) | 368 | break; |
| 329 | mousedev_touchpad_touch(mousedev, value); | ||
| 330 | else | ||
| 331 | mousedev_key_event(mousedev, code, value); | ||
| 332 | } | ||
| 333 | break; | ||
| 334 | 369 | ||
| 335 | case EV_SYN: | 370 | case EV_KEY: |
| 336 | if (code == SYN_REPORT) { | 371 | if (value != 2) { |
| 337 | if (mousedev->touch) { | 372 | if (code == BTN_TOUCH && |
| 338 | mousedev->pkt_count++; | 373 | test_bit(BTN_TOOL_FINGER, handle->dev->keybit)) |
| 339 | /* Input system eats duplicate events, but we need all of them | 374 | mousedev_touchpad_touch(mousedev, value); |
| 340 | * to do correct averaging so apply present one forward | 375 | else |
| 341 | */ | 376 | mousedev_key_event(mousedev, code, value); |
| 342 | fx(0) = fx(1); | 377 | } |
| 343 | fy(0) = fy(1); | 378 | break; |
| 344 | } | 379 | |
| 345 | 380 | case EV_SYN: | |
| 346 | mousedev_notify_readers(mousedev, &mousedev->packet); | 381 | if (code == SYN_REPORT) { |
| 347 | mousedev_notify_readers(mousedev_mix, &mousedev->packet); | 382 | if (mousedev->touch) { |
| 348 | 383 | mousedev->pkt_count++; | |
| 349 | mousedev->packet.dx = mousedev->packet.dy = mousedev->packet.dz = 0; | 384 | /* |
| 350 | mousedev->packet.abs_event = 0; | 385 | * Input system eats duplicate events, |
| 386 | * but we need all of them to do correct | ||
| 387 | * averaging so apply present one forward | ||
| 388 | */ | ||
| 389 | fx(0) = fx(1); | ||
| 390 | fy(0) = fy(1); | ||
| 351 | } | 391 | } |
| 352 | break; | 392 | |
| 393 | mousedev_notify_readers(mousedev, &mousedev->packet); | ||
| 394 | mousedev_notify_readers(mousedev_mix, &mousedev->packet); | ||
| 395 | |||
| 396 | mousedev->packet.dx = mousedev->packet.dy = | ||
| 397 | mousedev->packet.dz = 0; | ||
| 398 | mousedev->packet.abs_event = 0; | ||
| 399 | } | ||
| 400 | break; | ||
| 353 | } | 401 | } |
| 354 | } | 402 | } |
| 355 | 403 | ||
| @@ -367,41 +415,48 @@ static void mousedev_free(struct device *dev) | |||
| 367 | { | 415 | { |
| 368 | struct mousedev *mousedev = container_of(dev, struct mousedev, dev); | 416 | struct mousedev *mousedev = container_of(dev, struct mousedev, dev); |
| 369 | 417 | ||
| 370 | mousedev_table[mousedev->minor] = NULL; | ||
| 371 | kfree(mousedev); | 418 | kfree(mousedev); |
| 372 | } | 419 | } |
| 373 | 420 | ||
| 374 | static int mixdev_add_device(struct mousedev *mousedev) | 421 | static int mousedev_open_device(struct mousedev *mousedev) |
| 375 | { | 422 | { |
| 376 | int error; | 423 | int retval; |
| 377 | 424 | ||
| 378 | if (mousedev_mix->open) { | 425 | retval = mutex_lock_interruptible(&mousedev->mutex); |
| 379 | error = input_open_device(&mousedev->handle); | 426 | if (retval) |
| 380 | if (error) | 427 | return retval; |
| 381 | return error; | ||
| 382 | 428 | ||
| 383 | mousedev->open++; | 429 | if (mousedev->minor == MOUSEDEV_MIX) |
| 384 | mousedev->mixdev_open = 1; | 430 | mixdev_open_devices(); |
| 431 | else if (!mousedev->exist) | ||
| 432 | retval = -ENODEV; | ||
| 433 | else if (!mousedev->open++) { | ||
| 434 | retval = input_open_device(&mousedev->handle); | ||
| 435 | if (retval) | ||
| 436 | mousedev->open--; | ||
| 385 | } | 437 | } |
| 386 | 438 | ||
| 387 | get_device(&mousedev->dev); | 439 | mutex_unlock(&mousedev->mutex); |
| 388 | list_add_tail(&mousedev->mixdev_node, &mousedev_mix_list); | 440 | return retval; |
| 389 | |||
| 390 | return 0; | ||
| 391 | } | 441 | } |
| 392 | 442 | ||
| 393 | static void mixdev_remove_device(struct mousedev *mousedev) | 443 | static void mousedev_close_device(struct mousedev *mousedev) |
| 394 | { | 444 | { |
| 395 | if (mousedev->mixdev_open) { | 445 | mutex_lock(&mousedev->mutex); |
| 396 | mousedev->mixdev_open = 0; | ||
| 397 | if (!--mousedev->open && mousedev->exist) | ||
| 398 | input_close_device(&mousedev->handle); | ||
| 399 | } | ||
| 400 | 446 | ||
| 401 | list_del_init(&mousedev->mixdev_node); | 447 | if (mousedev->minor == MOUSEDEV_MIX) |
| 402 | put_device(&mousedev->dev); | 448 | mixdev_close_devices(); |
| 449 | else if (mousedev->exist && !--mousedev->open) | ||
| 450 | input_close_device(&mousedev->handle); | ||
| 451 | |||
| 452 | mutex_unlock(&mousedev->mutex); | ||
| 403 | } | 453 | } |
| 404 | 454 | ||
| 455 | /* | ||
| 456 | * Open all available devices so they can all be multiplexed in one. | ||
| 457 | * stream. Note that this function is called with mousedev_mix->mutex | ||
| 458 | * held. | ||
| 459 | */ | ||
| 405 | static void mixdev_open_devices(void) | 460 | static void mixdev_open_devices(void) |
| 406 | { | 461 | { |
| 407 | struct mousedev *mousedev; | 462 | struct mousedev *mousedev; |
| @@ -411,16 +466,19 @@ static void mixdev_open_devices(void) | |||
| 411 | 466 | ||
| 412 | list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) { | 467 | list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) { |
| 413 | if (!mousedev->mixdev_open) { | 468 | if (!mousedev->mixdev_open) { |
| 414 | if (!mousedev->open && mousedev->exist) | 469 | if (mousedev_open_device(mousedev)) |
| 415 | if (input_open_device(&mousedev->handle)) | 470 | continue; |
| 416 | continue; | ||
| 417 | 471 | ||
| 418 | mousedev->open++; | ||
| 419 | mousedev->mixdev_open = 1; | 472 | mousedev->mixdev_open = 1; |
| 420 | } | 473 | } |
| 421 | } | 474 | } |
| 422 | } | 475 | } |
| 423 | 476 | ||
| 477 | /* | ||
| 478 | * Close all devices that were opened as part of multiplexed | ||
| 479 | * device. Note that this function is called with mousedev_mix->mutex | ||
| 480 | * held. | ||
| 481 | */ | ||
| 424 | static void mixdev_close_devices(void) | 482 | static void mixdev_close_devices(void) |
| 425 | { | 483 | { |
| 426 | struct mousedev *mousedev; | 484 | struct mousedev *mousedev; |
| @@ -431,33 +489,45 @@ static void mixdev_close_devices(void) | |||
| 431 | list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) { | 489 | list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) { |
| 432 | if (mousedev->mixdev_open) { | 490 | if (mousedev->mixdev_open) { |
| 433 | mousedev->mixdev_open = 0; | 491 | mousedev->mixdev_open = 0; |
| 434 | if (!--mousedev->open && mousedev->exist) | 492 | mousedev_close_device(mousedev); |
| 435 | input_close_device(&mousedev->handle); | ||
| 436 | } | 493 | } |
| 437 | } | 494 | } |
| 438 | } | 495 | } |
| 439 | 496 | ||
| 497 | |||
| 498 | static void mousedev_attach_client(struct mousedev *mousedev, | ||
| 499 | struct mousedev_client *client) | ||
| 500 | { | ||
| 501 | spin_lock(&mousedev->client_lock); | ||
| 502 | list_add_tail_rcu(&client->node, &mousedev->client_list); | ||
| 503 | spin_unlock(&mousedev->client_lock); | ||
| 504 | synchronize_rcu(); | ||
| 505 | } | ||
| 506 | |||
| 507 | static void mousedev_detach_client(struct mousedev *mousedev, | ||
| 508 | struct mousedev_client *client) | ||
| 509 | { | ||
| 510 | spin_lock(&mousedev->client_lock); | ||
| 511 | list_del_rcu(&client->node); | ||
| 512 | spin_unlock(&mousedev->client_lock); | ||
| 513 | synchronize_rcu(); | ||
| 514 | } | ||
| 515 | |||
| 440 | static int mousedev_release(struct inode *inode, struct file *file) | 516 | static int mousedev_release(struct inode *inode, struct file *file) |
| 441 | { | 517 | { |
| 442 | struct mousedev_client *client = file->private_data; | 518 | struct mousedev_client *client = file->private_data; |
| 443 | struct mousedev *mousedev = client->mousedev; | 519 | struct mousedev *mousedev = client->mousedev; |
| 444 | 520 | ||
| 445 | mousedev_fasync(-1, file, 0); | 521 | mousedev_fasync(-1, file, 0); |
| 446 | 522 | mousedev_detach_client(mousedev, client); | |
| 447 | list_del(&client->node); | ||
| 448 | kfree(client); | 523 | kfree(client); |
| 449 | 524 | ||
| 450 | if (mousedev->minor == MOUSEDEV_MIX) | 525 | mousedev_close_device(mousedev); |
| 451 | mixdev_close_devices(); | ||
| 452 | else if (!--mousedev->open && mousedev->exist) | ||
| 453 | input_close_device(&mousedev->handle); | ||
| 454 | |||
| 455 | put_device(&mousedev->dev); | 526 | put_device(&mousedev->dev); |
| 456 | 527 | ||
| 457 | return 0; | 528 | return 0; |
| 458 | } | 529 | } |
| 459 | 530 | ||
| 460 | |||
| 461 | static int mousedev_open(struct inode *inode, struct file *file) | 531 | static int mousedev_open(struct inode *inode, struct file *file) |
| 462 | { | 532 | { |
| 463 | struct mousedev_client *client; | 533 | struct mousedev_client *client; |
| @@ -475,12 +545,17 @@ static int mousedev_open(struct inode *inode, struct file *file) | |||
| 475 | if (i >= MOUSEDEV_MINORS) | 545 | if (i >= MOUSEDEV_MINORS) |
| 476 | return -ENODEV; | 546 | return -ENODEV; |
| 477 | 547 | ||
| 548 | error = mutex_lock_interruptible(&mousedev_table_mutex); | ||
| 549 | if (error) | ||
| 550 | return error; | ||
| 478 | mousedev = mousedev_table[i]; | 551 | mousedev = mousedev_table[i]; |
| 552 | if (mousedev) | ||
| 553 | get_device(&mousedev->dev); | ||
| 554 | mutex_unlock(&mousedev_table_mutex); | ||
| 555 | |||
| 479 | if (!mousedev) | 556 | if (!mousedev) |
| 480 | return -ENODEV; | 557 | return -ENODEV; |
| 481 | 558 | ||
| 482 | get_device(&mousedev->dev); | ||
| 483 | |||
| 484 | client = kzalloc(sizeof(struct mousedev_client), GFP_KERNEL); | 559 | client = kzalloc(sizeof(struct mousedev_client), GFP_KERNEL); |
| 485 | if (!client) { | 560 | if (!client) { |
| 486 | error = -ENOMEM; | 561 | error = -ENOMEM; |
| @@ -491,21 +566,17 @@ static int mousedev_open(struct inode *inode, struct file *file) | |||
| 491 | client->pos_x = xres / 2; | 566 | client->pos_x = xres / 2; |
| 492 | client->pos_y = yres / 2; | 567 | client->pos_y = yres / 2; |
| 493 | client->mousedev = mousedev; | 568 | client->mousedev = mousedev; |
| 494 | list_add_tail(&client->node, &mousedev->client_list); | 569 | mousedev_attach_client(mousedev, client); |
| 495 | 570 | ||
| 496 | if (mousedev->minor == MOUSEDEV_MIX) | 571 | error = mousedev_open_device(mousedev); |
| 497 | mixdev_open_devices(); | 572 | if (error) |
| 498 | else if (!mousedev->open++ && mousedev->exist) { | 573 | goto err_free_client; |
| 499 | error = input_open_device(&mousedev->handle); | ||
| 500 | if (error) | ||
| 501 | goto err_free_client; | ||
| 502 | } | ||
| 503 | 574 | ||
| 504 | file->private_data = client; | 575 | file->private_data = client; |
| 505 | return 0; | 576 | return 0; |
| 506 | 577 | ||
| 507 | err_free_client: | 578 | err_free_client: |
| 508 | list_del(&client->node); | 579 | mousedev_detach_client(mousedev, client); |
| 509 | kfree(client); | 580 | kfree(client); |
| 510 | err_put_mousedev: | 581 | err_put_mousedev: |
| 511 | put_device(&mousedev->dev); | 582 | put_device(&mousedev->dev); |
| @@ -517,41 +588,41 @@ static inline int mousedev_limit_delta(int delta, int limit) | |||
| 517 | return delta > limit ? limit : (delta < -limit ? -limit : delta); | 588 | return delta > limit ? limit : (delta < -limit ? -limit : delta); |
| 518 | } | 589 | } |
| 519 | 590 | ||
| 520 | static void mousedev_packet(struct mousedev_client *client, signed char *ps2_data) | 591 | static void mousedev_packet(struct mousedev_client *client, |
| 592 | signed char *ps2_data) | ||
| 521 | { | 593 | { |
| 522 | struct mousedev_motion *p; | 594 | struct mousedev_motion *p = &client->packets[client->tail]; |
| 523 | unsigned long flags; | ||
| 524 | |||
| 525 | spin_lock_irqsave(&client->packet_lock, flags); | ||
| 526 | p = &client->packets[client->tail]; | ||
| 527 | 595 | ||
| 528 | ps2_data[0] = 0x08 | ((p->dx < 0) << 4) | ((p->dy < 0) << 5) | (p->buttons & 0x07); | 596 | ps2_data[0] = 0x08 | |
| 597 | ((p->dx < 0) << 4) | ((p->dy < 0) << 5) | (p->buttons & 0x07); | ||
| 529 | ps2_data[1] = mousedev_limit_delta(p->dx, 127); | 598 | ps2_data[1] = mousedev_limit_delta(p->dx, 127); |
| 530 | ps2_data[2] = mousedev_limit_delta(p->dy, 127); | 599 | ps2_data[2] = mousedev_limit_delta(p->dy, 127); |
| 531 | p->dx -= ps2_data[1]; | 600 | p->dx -= ps2_data[1]; |
| 532 | p->dy -= ps2_data[2]; | 601 | p->dy -= ps2_data[2]; |
| 533 | 602 | ||
| 534 | switch (client->mode) { | 603 | switch (client->mode) { |
| 535 | case MOUSEDEV_EMUL_EXPS: | 604 | case MOUSEDEV_EMUL_EXPS: |
| 536 | ps2_data[3] = mousedev_limit_delta(p->dz, 7); | 605 | ps2_data[3] = mousedev_limit_delta(p->dz, 7); |
| 537 | p->dz -= ps2_data[3]; | 606 | p->dz -= ps2_data[3]; |
| 538 | ps2_data[3] = (ps2_data[3] & 0x0f) | ((p->buttons & 0x18) << 1); | 607 | ps2_data[3] = (ps2_data[3] & 0x0f) | ((p->buttons & 0x18) << 1); |
| 539 | client->bufsiz = 4; | 608 | client->bufsiz = 4; |
| 540 | break; | 609 | break; |
| 541 | 610 | ||
| 542 | case MOUSEDEV_EMUL_IMPS: | 611 | case MOUSEDEV_EMUL_IMPS: |
| 543 | ps2_data[0] |= ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1); | 612 | ps2_data[0] |= |
| 544 | ps2_data[3] = mousedev_limit_delta(p->dz, 127); | 613 | ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1); |
| 545 | p->dz -= ps2_data[3]; | 614 | ps2_data[3] = mousedev_limit_delta(p->dz, 127); |
| 546 | client->bufsiz = 4; | 615 | p->dz -= ps2_data[3]; |
| 547 | break; | 616 | client->bufsiz = 4; |
| 548 | 617 | break; | |
| 549 | case MOUSEDEV_EMUL_PS2: | 618 | |
| 550 | default: | 619 | case MOUSEDEV_EMUL_PS2: |
| 551 | ps2_data[0] |= ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1); | 620 | default: |
| 552 | p->dz = 0; | 621 | ps2_data[0] |= |
| 553 | client->bufsiz = 3; | 622 | ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1); |
| 554 | break; | 623 | p->dz = 0; |
| 624 | client->bufsiz = 3; | ||
| 625 | break; | ||
| 555 | } | 626 | } |
| 556 | 627 | ||
| 557 | if (!p->dx && !p->dy && !p->dz) { | 628 | if (!p->dx && !p->dy && !p->dz) { |
| @@ -561,12 +632,56 @@ static void mousedev_packet(struct mousedev_client *client, signed char *ps2_dat | |||
| 561 | } else | 632 | } else |
| 562 | client->tail = (client->tail + 1) % PACKET_QUEUE_LEN; | 633 | client->tail = (client->tail + 1) % PACKET_QUEUE_LEN; |
| 563 | } | 634 | } |
| 564 | |||
| 565 | spin_unlock_irqrestore(&client->packet_lock, flags); | ||
| 566 | } | 635 | } |
| 567 | 636 | ||
| 637 | static void mousedev_generate_response(struct mousedev_client *client, | ||
| 638 | int command) | ||
| 639 | { | ||
| 640 | client->ps2[0] = 0xfa; /* ACK */ | ||
| 641 | |||
| 642 | switch (command) { | ||
| 568 | 643 | ||
| 569 | static ssize_t mousedev_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) | 644 | case 0xeb: /* Poll */ |
| 645 | mousedev_packet(client, &client->ps2[1]); | ||
| 646 | client->bufsiz++; /* account for leading ACK */ | ||
| 647 | break; | ||
| 648 | |||
| 649 | case 0xf2: /* Get ID */ | ||
| 650 | switch (client->mode) { | ||
| 651 | case MOUSEDEV_EMUL_PS2: | ||
| 652 | client->ps2[1] = 0; | ||
| 653 | break; | ||
| 654 | case MOUSEDEV_EMUL_IMPS: | ||
| 655 | client->ps2[1] = 3; | ||
| 656 | break; | ||
| 657 | case MOUSEDEV_EMUL_EXPS: | ||
| 658 | client->ps2[1] = 4; | ||
| 659 | break; | ||
| 660 | } | ||
| 661 | client->bufsiz = 2; | ||
| 662 | break; | ||
| 663 | |||
| 664 | case 0xe9: /* Get info */ | ||
| 665 | client->ps2[1] = 0x60; client->ps2[2] = 3; client->ps2[3] = 200; | ||
| 666 | client->bufsiz = 4; | ||
| 667 | break; | ||
| 668 | |||
| 669 | case 0xff: /* Reset */ | ||
| 670 | client->impsseq = client->imexseq = 0; | ||
| 671 | client->mode = MOUSEDEV_EMUL_PS2; | ||
| 672 | client->ps2[1] = 0xaa; client->ps2[2] = 0x00; | ||
| 673 | client->bufsiz = 3; | ||
| 674 | break; | ||
| 675 | |||
| 676 | default: | ||
| 677 | client->bufsiz = 1; | ||
| 678 | break; | ||
| 679 | } | ||
| 680 | client->buffer = client->bufsiz; | ||
| 681 | } | ||
| 682 | |||
| 683 | static ssize_t mousedev_write(struct file *file, const char __user *buffer, | ||
| 684 | size_t count, loff_t *ppos) | ||
| 570 | { | 685 | { |
| 571 | struct mousedev_client *client = file->private_data; | 686 | struct mousedev_client *client = file->private_data; |
| 572 | unsigned char c; | 687 | unsigned char c; |
| @@ -577,6 +692,8 @@ static ssize_t mousedev_write(struct file *file, const char __user *buffer, size | |||
| 577 | if (get_user(c, buffer + i)) | 692 | if (get_user(c, buffer + i)) |
| 578 | return -EFAULT; | 693 | return -EFAULT; |
| 579 | 694 | ||
| 695 | spin_lock_irq(&client->packet_lock); | ||
| 696 | |||
| 580 | if (c == mousedev_imex_seq[client->imexseq]) { | 697 | if (c == mousedev_imex_seq[client->imexseq]) { |
| 581 | if (++client->imexseq == MOUSEDEV_SEQ_LEN) { | 698 | if (++client->imexseq == MOUSEDEV_SEQ_LEN) { |
| 582 | client->imexseq = 0; | 699 | client->imexseq = 0; |
| @@ -593,68 +710,39 @@ static ssize_t mousedev_write(struct file *file, const char __user *buffer, size | |||
| 593 | } else | 710 | } else |
| 594 | client->impsseq = 0; | 711 | client->impsseq = 0; |
| 595 | 712 | ||
| 596 | client->ps2[0] = 0xfa; | 713 | mousedev_generate_response(client, c); |
| 597 | |||
| 598 | switch (c) { | ||
| 599 | |||
| 600 | case 0xeb: /* Poll */ | ||
| 601 | mousedev_packet(client, &client->ps2[1]); | ||
| 602 | client->bufsiz++; /* account for leading ACK */ | ||
| 603 | break; | ||
| 604 | |||
| 605 | case 0xf2: /* Get ID */ | ||
| 606 | switch (client->mode) { | ||
| 607 | case MOUSEDEV_EMUL_PS2: client->ps2[1] = 0; break; | ||
| 608 | case MOUSEDEV_EMUL_IMPS: client->ps2[1] = 3; break; | ||
| 609 | case MOUSEDEV_EMUL_EXPS: client->ps2[1] = 4; break; | ||
| 610 | } | ||
| 611 | client->bufsiz = 2; | ||
| 612 | break; | ||
| 613 | |||
| 614 | case 0xe9: /* Get info */ | ||
| 615 | client->ps2[1] = 0x60; client->ps2[2] = 3; client->ps2[3] = 200; | ||
| 616 | client->bufsiz = 4; | ||
| 617 | break; | ||
| 618 | |||
| 619 | case 0xff: /* Reset */ | ||
| 620 | client->impsseq = client->imexseq = 0; | ||
| 621 | client->mode = MOUSEDEV_EMUL_PS2; | ||
| 622 | client->ps2[1] = 0xaa; client->ps2[2] = 0x00; | ||
| 623 | client->bufsiz = 3; | ||
| 624 | break; | ||
| 625 | |||
| 626 | default: | ||
| 627 | client->bufsiz = 1; | ||
| 628 | break; | ||
| 629 | } | ||
| 630 | 714 | ||
| 631 | client->buffer = client->bufsiz; | 715 | spin_unlock_irq(&client->packet_lock); |
| 632 | } | 716 | } |
| 633 | 717 | ||
| 634 | kill_fasync(&client->fasync, SIGIO, POLL_IN); | 718 | kill_fasync(&client->fasync, SIGIO, POLL_IN); |
| 635 | |||
| 636 | wake_up_interruptible(&client->mousedev->wait); | 719 | wake_up_interruptible(&client->mousedev->wait); |
| 637 | 720 | ||
| 638 | return count; | 721 | return count; |
| 639 | } | 722 | } |
| 640 | 723 | ||
| 641 | static ssize_t mousedev_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) | 724 | static ssize_t mousedev_read(struct file *file, char __user *buffer, |
| 725 | size_t count, loff_t *ppos) | ||
| 642 | { | 726 | { |
| 643 | struct mousedev_client *client = file->private_data; | 727 | struct mousedev_client *client = file->private_data; |
| 728 | struct mousedev *mousedev = client->mousedev; | ||
| 729 | signed char data[sizeof(client->ps2)]; | ||
| 644 | int retval = 0; | 730 | int retval = 0; |
| 645 | 731 | ||
| 646 | if (!client->ready && !client->buffer && (file->f_flags & O_NONBLOCK)) | 732 | if (!client->ready && !client->buffer && mousedev->exist && |
| 733 | (file->f_flags & O_NONBLOCK)) | ||
| 647 | return -EAGAIN; | 734 | return -EAGAIN; |
| 648 | 735 | ||
| 649 | retval = wait_event_interruptible(client->mousedev->wait, | 736 | retval = wait_event_interruptible(mousedev->wait, |
| 650 | !client->mousedev->exist || client->ready || client->buffer); | 737 | !mousedev->exist || client->ready || client->buffer); |
| 651 | |||
| 652 | if (retval) | 738 | if (retval) |
| 653 | return retval; | 739 | return retval; |
| 654 | 740 | ||
| 655 | if (!client->mousedev->exist) | 741 | if (!mousedev->exist) |
| 656 | return -ENODEV; | 742 | return -ENODEV; |
| 657 | 743 | ||
| 744 | spin_lock_irq(&client->packet_lock); | ||
| 745 | |||
| 658 | if (!client->buffer && client->ready) { | 746 | if (!client->buffer && client->ready) { |
| 659 | mousedev_packet(client, client->ps2); | 747 | mousedev_packet(client, client->ps2); |
| 660 | client->buffer = client->bufsiz; | 748 | client->buffer = client->bufsiz; |
| @@ -663,9 +751,12 @@ static ssize_t mousedev_read(struct file *file, char __user *buffer, size_t coun | |||
| 663 | if (count > client->buffer) | 751 | if (count > client->buffer) |
| 664 | count = client->buffer; | 752 | count = client->buffer; |
| 665 | 753 | ||
| 754 | memcpy(data, client->ps2 + client->bufsiz - client->buffer, count); | ||
| 666 | client->buffer -= count; | 755 | client->buffer -= count; |
| 667 | 756 | ||
| 668 | if (copy_to_user(buffer, client->ps2 + client->bufsiz - client->buffer - count, count)) | 757 | spin_unlock_irq(&client->packet_lock); |
| 758 | |||
| 759 | if (copy_to_user(buffer, data, count)) | ||
| 669 | return -EFAULT; | 760 | return -EFAULT; |
| 670 | 761 | ||
| 671 | return count; | 762 | return count; |
| @@ -692,6 +783,60 @@ static const struct file_operations mousedev_fops = { | |||
| 692 | .fasync = mousedev_fasync, | 783 | .fasync = mousedev_fasync, |
| 693 | }; | 784 | }; |
| 694 | 785 | ||
| 786 | static int mousedev_install_chrdev(struct mousedev *mousedev) | ||
| 787 | { | ||
| 788 | mousedev_table[mousedev->minor] = mousedev; | ||
| 789 | return 0; | ||
| 790 | } | ||
| 791 | |||
| 792 | static void mousedev_remove_chrdev(struct mousedev *mousedev) | ||
| 793 | { | ||
| 794 | mutex_lock(&mousedev_table_mutex); | ||
| 795 | mousedev_table[mousedev->minor] = NULL; | ||
| 796 | mutex_unlock(&mousedev_table_mutex); | ||
| 797 | } | ||
| 798 | |||
| 799 | /* | ||
| 800 | * Mark device non-existent. This disables writes, ioctls and | ||
| 801 | * prevents new users from opening the device. Already posted | ||
| 802 | * blocking reads will stay, however new ones will fail. | ||
| 803 | */ | ||
| 804 | static void mousedev_mark_dead(struct mousedev *mousedev) | ||
| 805 | { | ||
| 806 | mutex_lock(&mousedev->mutex); | ||
| 807 | mousedev->exist = 0; | ||
| 808 | mutex_unlock(&mousedev->mutex); | ||
| 809 | } | ||
| 810 | |||
| 811 | /* | ||
| 812 | * Wake up users waiting for IO so they can disconnect from | ||
| 813 | * dead device. | ||
| 814 | */ | ||
| 815 | static void mousedev_hangup(struct mousedev *mousedev) | ||
| 816 | { | ||
| 817 | struct mousedev_client *client; | ||
| 818 | |||
| 819 | spin_lock(&mousedev->client_lock); | ||
| 820 | list_for_each_entry(client, &mousedev->client_list, node) | ||
| 821 | kill_fasync(&client->fasync, SIGIO, POLL_HUP); | ||
| 822 | spin_unlock(&mousedev->client_lock); | ||
| 823 | |||
| 824 | wake_up_interruptible(&mousedev->wait); | ||
| 825 | } | ||
| 826 | |||
| 827 | static void mousedev_cleanup(struct mousedev *mousedev) | ||
| 828 | { | ||
| 829 | struct input_handle *handle = &mousedev->handle; | ||
| 830 | |||
| 831 | mousedev_mark_dead(mousedev); | ||
| 832 | mousedev_hangup(mousedev); | ||
| 833 | mousedev_remove_chrdev(mousedev); | ||
| 834 | |||
| 835 | /* mousedev is marked dead so no one else accesses mousedev->open */ | ||
| 836 | if (mousedev->open) | ||
| 837 | input_close_device(handle); | ||
| 838 | } | ||
| 839 | |||
| 695 | static struct mousedev *mousedev_create(struct input_dev *dev, | 840 | static struct mousedev *mousedev_create(struct input_dev *dev, |
| 696 | struct input_handler *handler, | 841 | struct input_handler *handler, |
| 697 | int minor) | 842 | int minor) |
| @@ -707,6 +852,10 @@ static struct mousedev *mousedev_create(struct input_dev *dev, | |||
| 707 | 852 | ||
| 708 | INIT_LIST_HEAD(&mousedev->client_list); | 853 | INIT_LIST_HEAD(&mousedev->client_list); |
| 709 | INIT_LIST_HEAD(&mousedev->mixdev_node); | 854 | INIT_LIST_HEAD(&mousedev->mixdev_node); |
| 855 | spin_lock_init(&mousedev->client_lock); | ||
| 856 | mutex_init(&mousedev->mutex); | ||
| 857 | lockdep_set_subclass(&mousedev->mutex, | ||
| 858 | minor == MOUSEDEV_MIX ? MOUSEDEV_MIX : 0); | ||
| 710 | init_waitqueue_head(&mousedev->wait); | 859 | init_waitqueue_head(&mousedev->wait); |
| 711 | 860 | ||
| 712 | if (minor == MOUSEDEV_MIX) | 861 | if (minor == MOUSEDEV_MIX) |
| @@ -731,14 +880,27 @@ static struct mousedev *mousedev_create(struct input_dev *dev, | |||
| 731 | mousedev->dev.release = mousedev_free; | 880 | mousedev->dev.release = mousedev_free; |
| 732 | device_initialize(&mousedev->dev); | 881 | device_initialize(&mousedev->dev); |
| 733 | 882 | ||
| 734 | mousedev_table[minor] = mousedev; | 883 | if (minor != MOUSEDEV_MIX) { |
| 884 | error = input_register_handle(&mousedev->handle); | ||
| 885 | if (error) | ||
| 886 | goto err_free_mousedev; | ||
| 887 | } | ||
| 888 | |||
| 889 | error = mousedev_install_chrdev(mousedev); | ||
| 890 | if (error) | ||
| 891 | goto err_unregister_handle; | ||
| 735 | 892 | ||
| 736 | error = device_add(&mousedev->dev); | 893 | error = device_add(&mousedev->dev); |
| 737 | if (error) | 894 | if (error) |
| 738 | goto err_free_mousedev; | 895 | goto err_cleanup_mousedev; |
| 739 | 896 | ||
| 740 | return mousedev; | 897 | return mousedev; |
| 741 | 898 | ||
| 899 | err_cleanup_mousedev: | ||
| 900 | mousedev_cleanup(mousedev); | ||
| 901 | err_unregister_handle: | ||
| 902 | if (minor != MOUSEDEV_MIX) | ||
| 903 | input_unregister_handle(&mousedev->handle); | ||
| 742 | err_free_mousedev: | 904 | err_free_mousedev: |
| 743 | put_device(&mousedev->dev); | 905 | put_device(&mousedev->dev); |
| 744 | err_out: | 906 | err_out: |
| @@ -747,29 +909,64 @@ static struct mousedev *mousedev_create(struct input_dev *dev, | |||
| 747 | 909 | ||
| 748 | static void mousedev_destroy(struct mousedev *mousedev) | 910 | static void mousedev_destroy(struct mousedev *mousedev) |
| 749 | { | 911 | { |
| 750 | struct mousedev_client *client; | ||
| 751 | |||
| 752 | device_del(&mousedev->dev); | 912 | device_del(&mousedev->dev); |
| 753 | mousedev->exist = 0; | 913 | mousedev_cleanup(mousedev); |
| 914 | if (mousedev->minor != MOUSEDEV_MIX) | ||
| 915 | input_unregister_handle(&mousedev->handle); | ||
| 916 | put_device(&mousedev->dev); | ||
| 917 | } | ||
| 754 | 918 | ||
| 755 | if (mousedev->open) { | 919 | static int mixdev_add_device(struct mousedev *mousedev) |
| 756 | input_close_device(&mousedev->handle); | 920 | { |
| 757 | list_for_each_entry(client, &mousedev->client_list, node) | 921 | int retval; |
| 758 | kill_fasync(&client->fasync, SIGIO, POLL_HUP); | 922 | |
| 759 | wake_up_interruptible(&mousedev->wait); | 923 | retval = mutex_lock_interruptible(&mousedev_mix->mutex); |
| 924 | if (retval) | ||
| 925 | return retval; | ||
| 926 | |||
| 927 | if (mousedev_mix->open) { | ||
| 928 | retval = mousedev_open_device(mousedev); | ||
| 929 | if (retval) | ||
| 930 | goto out; | ||
| 931 | |||
| 932 | mousedev->mixdev_open = 1; | ||
| 760 | } | 933 | } |
| 761 | 934 | ||
| 935 | get_device(&mousedev->dev); | ||
| 936 | list_add_tail(&mousedev->mixdev_node, &mousedev_mix_list); | ||
| 937 | |||
| 938 | out: | ||
| 939 | mutex_unlock(&mousedev_mix->mutex); | ||
| 940 | return retval; | ||
| 941 | } | ||
| 942 | |||
| 943 | static void mixdev_remove_device(struct mousedev *mousedev) | ||
| 944 | { | ||
| 945 | mutex_lock(&mousedev_mix->mutex); | ||
| 946 | |||
| 947 | if (mousedev->mixdev_open) { | ||
| 948 | mousedev->mixdev_open = 0; | ||
| 949 | mousedev_close_device(mousedev); | ||
| 950 | } | ||
| 951 | |||
| 952 | list_del_init(&mousedev->mixdev_node); | ||
| 953 | mutex_unlock(&mousedev_mix->mutex); | ||
| 954 | |||
| 762 | put_device(&mousedev->dev); | 955 | put_device(&mousedev->dev); |
| 763 | } | 956 | } |
| 764 | 957 | ||
| 765 | static int mousedev_connect(struct input_handler *handler, struct input_dev *dev, | 958 | static int mousedev_connect(struct input_handler *handler, |
| 959 | struct input_dev *dev, | ||
| 766 | const struct input_device_id *id) | 960 | const struct input_device_id *id) |
| 767 | { | 961 | { |
| 768 | struct mousedev *mousedev; | 962 | struct mousedev *mousedev; |
| 769 | int minor; | 963 | int minor; |
| 770 | int error; | 964 | int error; |
| 771 | 965 | ||
| 772 | for (minor = 0; minor < MOUSEDEV_MINORS && mousedev_table[minor]; minor++); | 966 | for (minor = 0; minor < MOUSEDEV_MINORS; minor++) |
| 967 | if (!mousedev_table[minor]) | ||
| 968 | break; | ||
| 969 | |||
| 773 | if (minor == MOUSEDEV_MINORS) { | 970 | if (minor == MOUSEDEV_MINORS) { |
| 774 | printk(KERN_ERR "mousedev: no more free mousedev devices\n"); | 971 | printk(KERN_ERR "mousedev: no more free mousedev devices\n"); |
| 775 | return -ENFILE; | 972 | return -ENFILE; |
| @@ -779,21 +976,13 @@ static int mousedev_connect(struct input_handler *handler, struct input_dev *dev | |||
| 779 | if (IS_ERR(mousedev)) | 976 | if (IS_ERR(mousedev)) |
| 780 | return PTR_ERR(mousedev); | 977 | return PTR_ERR(mousedev); |
| 781 | 978 | ||
| 782 | error = input_register_handle(&mousedev->handle); | ||
| 783 | if (error) | ||
| 784 | goto err_delete_mousedev; | ||
| 785 | |||
| 786 | error = mixdev_add_device(mousedev); | 979 | error = mixdev_add_device(mousedev); |
| 787 | if (error) | 980 | if (error) { |
| 788 | goto err_unregister_handle; | 981 | mousedev_destroy(mousedev); |
| 982 | return error; | ||
| 983 | } | ||
| 789 | 984 | ||
| 790 | return 0; | 985 | return 0; |
| 791 | |||
| 792 | err_unregister_handle: | ||
| 793 | input_unregister_handle(&mousedev->handle); | ||
| 794 | err_delete_mousedev: | ||
| 795 | device_unregister(&mousedev->dev); | ||
| 796 | return error; | ||
| 797 | } | 986 | } |
| 798 | 987 | ||
| 799 | static void mousedev_disconnect(struct input_handle *handle) | 988 | static void mousedev_disconnect(struct input_handle *handle) |
| @@ -801,33 +990,42 @@ static void mousedev_disconnect(struct input_handle *handle) | |||
| 801 | struct mousedev *mousedev = handle->private; | 990 | struct mousedev *mousedev = handle->private; |
| 802 | 991 | ||
| 803 | mixdev_remove_device(mousedev); | 992 | mixdev_remove_device(mousedev); |
| 804 | input_unregister_handle(handle); | ||
| 805 | mousedev_destroy(mousedev); | 993 | mousedev_destroy(mousedev); |
| 806 | } | 994 | } |
| 807 | 995 | ||
| 808 | static const struct input_device_id mousedev_ids[] = { | 996 | static const struct input_device_id mousedev_ids[] = { |
| 809 | { | 997 | { |
| 810 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_RELBIT, | 998 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | |
| 999 | INPUT_DEVICE_ID_MATCH_KEYBIT | | ||
| 1000 | INPUT_DEVICE_ID_MATCH_RELBIT, | ||
| 811 | .evbit = { BIT(EV_KEY) | BIT(EV_REL) }, | 1001 | .evbit = { BIT(EV_KEY) | BIT(EV_REL) }, |
| 812 | .keybit = { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) }, | 1002 | .keybit = { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) }, |
| 813 | .relbit = { BIT(REL_X) | BIT(REL_Y) }, | 1003 | .relbit = { BIT(REL_X) | BIT(REL_Y) }, |
| 814 | }, /* A mouse like device, at least one button, two relative axes */ | 1004 | }, /* A mouse like device, at least one button, |
| 1005 | two relative axes */ | ||
| 815 | { | 1006 | { |
| 816 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_RELBIT, | 1007 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | |
| 1008 | INPUT_DEVICE_ID_MATCH_RELBIT, | ||
| 817 | .evbit = { BIT(EV_KEY) | BIT(EV_REL) }, | 1009 | .evbit = { BIT(EV_KEY) | BIT(EV_REL) }, |
| 818 | .relbit = { BIT(REL_WHEEL) }, | 1010 | .relbit = { BIT(REL_WHEEL) }, |
| 819 | }, /* A separate scrollwheel */ | 1011 | }, /* A separate scrollwheel */ |
| 820 | { | 1012 | { |
| 821 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_ABSBIT, | 1013 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | |
| 1014 | INPUT_DEVICE_ID_MATCH_KEYBIT | | ||
| 1015 | INPUT_DEVICE_ID_MATCH_ABSBIT, | ||
| 822 | .evbit = { BIT(EV_KEY) | BIT(EV_ABS) }, | 1016 | .evbit = { BIT(EV_KEY) | BIT(EV_ABS) }, |
| 823 | .keybit = { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) }, | 1017 | .keybit = { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) }, |
| 824 | .absbit = { BIT(ABS_X) | BIT(ABS_Y) }, | 1018 | .absbit = { BIT(ABS_X) | BIT(ABS_Y) }, |
| 825 | }, /* A tablet like device, at least touch detection, two absolute axes */ | 1019 | }, /* A tablet like device, at least touch detection, |
| 1020 | two absolute axes */ | ||
| 826 | { | 1021 | { |
| 827 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_ABSBIT, | 1022 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | |
| 1023 | INPUT_DEVICE_ID_MATCH_KEYBIT | | ||
| 1024 | INPUT_DEVICE_ID_MATCH_ABSBIT, | ||
| 828 | .evbit = { BIT(EV_KEY) | BIT(EV_ABS) }, | 1025 | .evbit = { BIT(EV_KEY) | BIT(EV_ABS) }, |
| 829 | .keybit = { [LONG(BTN_TOOL_FINGER)] = BIT(BTN_TOOL_FINGER) }, | 1026 | .keybit = { [LONG(BTN_TOOL_FINGER)] = BIT(BTN_TOOL_FINGER) }, |
| 830 | .absbit = { BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) | BIT(ABS_TOOL_WIDTH) }, | 1027 | .absbit = { BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) | |
| 1028 | BIT(ABS_TOOL_WIDTH) }, | ||
| 831 | }, /* A touchpad */ | 1029 | }, /* A touchpad */ |
| 832 | 1030 | ||
| 833 | { }, /* Terminating entry */ | 1031 | { }, /* Terminating entry */ |
diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index c2eea2767e10..11dafc0ee994 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c | |||
| @@ -385,6 +385,8 @@ static int i8042_enable_kbd_port(void) | |||
| 385 | i8042_ctr |= I8042_CTR_KBDINT; | 385 | i8042_ctr |= I8042_CTR_KBDINT; |
| 386 | 386 | ||
| 387 | if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { | 387 | if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { |
| 388 | i8042_ctr &= ~I8042_CTR_KBDINT; | ||
| 389 | i8042_ctr |= I8042_CTR_KBDDIS; | ||
| 388 | printk(KERN_ERR "i8042.c: Failed to enable KBD port.\n"); | 390 | printk(KERN_ERR "i8042.c: Failed to enable KBD port.\n"); |
| 389 | return -EIO; | 391 | return -EIO; |
| 390 | } | 392 | } |
| @@ -402,6 +404,8 @@ static int i8042_enable_aux_port(void) | |||
| 402 | i8042_ctr |= I8042_CTR_AUXINT; | 404 | i8042_ctr |= I8042_CTR_AUXINT; |
| 403 | 405 | ||
| 404 | if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { | 406 | if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) { |
| 407 | i8042_ctr &= ~I8042_CTR_AUXINT; | ||
| 408 | i8042_ctr |= I8042_CTR_AUXDIS; | ||
| 405 | printk(KERN_ERR "i8042.c: Failed to enable AUX port.\n"); | 409 | printk(KERN_ERR "i8042.c: Failed to enable AUX port.\n"); |
| 406 | return -EIO; | 410 | return -EIO; |
| 407 | } | 411 | } |
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index f929fcdbae2e..e3e0baa1a158 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig | |||
| @@ -126,6 +126,16 @@ config TOUCHSCREEN_HP600 | |||
| 126 | To compile this driver as a module, choose M here: the | 126 | To compile this driver as a module, choose M here: the |
| 127 | module will be called hp680_ts_input. | 127 | module will be called hp680_ts_input. |
| 128 | 128 | ||
| 129 | config TOUCHSCREEN_HP7XX | ||
| 130 | tristate "HP Jornada 710/720/728 touchscreen" | ||
| 131 | depends on SA1100_JORNADA720_SSP | ||
| 132 | help | ||
| 133 | Say Y here if you have a HP Jornada 710/720/728 and want | ||
| 134 | to support the built-in touchscreen. | ||
| 135 | |||
| 136 | To compile this driver as a module, choose M here: the | ||
| 137 | module will be called jornada720_ts. | ||
| 138 | |||
| 129 | config TOUCHSCREEN_PENMOUNT | 139 | config TOUCHSCREEN_PENMOUNT |
| 130 | tristate "Penmount serial touchscreen" | 140 | tristate "Penmount serial touchscreen" |
| 131 | select SERIO | 141 | select SERIO |
| @@ -191,6 +201,7 @@ config TOUCHSCREEN_USB_COMPOSITE | |||
| 191 | - Gunze AHL61 | 201 | - Gunze AHL61 |
| 192 | - DMC TSC-10/25 | 202 | - DMC TSC-10/25 |
| 193 | - IRTOUCHSYSTEMS/UNITOP | 203 | - IRTOUCHSYSTEMS/UNITOP |
| 204 | - IdealTEK URTC1000 | ||
| 194 | 205 | ||
| 195 | Have a look at <http://linux.chapter7.ch/touchkit/> for | 206 | Have a look at <http://linux.chapter7.ch/touchkit/> for |
| 196 | a usage description and the required user-space stuff. | 207 | a usage description and the required user-space stuff. |
| @@ -238,4 +249,14 @@ config TOUCHSCREEN_USB_IRTOUCH | |||
| 238 | bool "IRTOUCHSYSTEMS/UNITOP device support" if EMBEDDED | 249 | bool "IRTOUCHSYSTEMS/UNITOP device support" if EMBEDDED |
| 239 | depends on TOUCHSCREEN_USB_COMPOSITE | 250 | depends on TOUCHSCREEN_USB_COMPOSITE |
| 240 | 251 | ||
| 252 | config TOUCHSCREEN_USB_IDEALTEK | ||
| 253 | default y | ||
| 254 | bool "IdealTEK URTC1000 device support" if EMBEDDED | ||
| 255 | depends on TOUCHSCREEN_USB_COMPOSITE | ||
| 256 | |||
| 257 | config TOUCHSCREEN_USB_GENERAL_TOUCH | ||
| 258 | default y | ||
| 259 | bool "GeneralTouch Touchscreen device support" if EMBEDDED | ||
| 260 | depends on TOUCHSCREEN_USB_COMPOSITE | ||
| 261 | |||
| 241 | endif | 262 | endif |
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 5de8933c4993..35d4097df35a 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile | |||
| @@ -13,6 +13,7 @@ obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o | |||
| 13 | obj-$(CONFIG_TOUCHSCREEN_MTOUCH) += mtouch.o | 13 | obj-$(CONFIG_TOUCHSCREEN_MTOUCH) += mtouch.o |
| 14 | obj-$(CONFIG_TOUCHSCREEN_MK712) += mk712.o | 14 | obj-$(CONFIG_TOUCHSCREEN_MK712) += mk712.o |
| 15 | obj-$(CONFIG_TOUCHSCREEN_HP600) += hp680_ts_input.o | 15 | obj-$(CONFIG_TOUCHSCREEN_HP600) += hp680_ts_input.o |
| 16 | obj-$(CONFIG_TOUCHSCREEN_HP7XX) += jornada720_ts.o | ||
| 16 | obj-$(CONFIG_TOUCHSCREEN_USB_COMPOSITE) += usbtouchscreen.o | 17 | obj-$(CONFIG_TOUCHSCREEN_USB_COMPOSITE) += usbtouchscreen.o |
| 17 | obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o | 18 | obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o |
| 18 | obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o | 19 | obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o |
diff --git a/drivers/input/touchscreen/jornada720_ts.c b/drivers/input/touchscreen/jornada720_ts.c new file mode 100644 index 000000000000..42a1c9a1940e --- /dev/null +++ b/drivers/input/touchscreen/jornada720_ts.c | |||
| @@ -0,0 +1,182 @@ | |||
| 1 | /* | ||
| 2 | * drivers/input/touchscreen/jornada720_ts.c | ||
| 3 | * | ||
| 4 | * Copyright (C) 2007 Kristoffer Ericson <Kristoffer.Ericson@gmail.com> | ||
| 5 | * | ||
| 6 | * Copyright (C) 2006 Filip Zyzniewski <filip.zyzniewski@tefnet.pl> | ||
| 7 | * based on HP Jornada 56x touchscreen driver by Alex Lange <chicken@handhelds.org> | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or modify | ||
| 10 | * it under the terms of the GNU General Public License version 2 as | ||
| 11 | * published by the Free Software Foundation. | ||
| 12 | * | ||
| 13 | * HP Jornada 710/720/729 Touchscreen Driver | ||
| 14 | */ | ||
| 15 | |||
| 16 | #include <linux/platform_device.h> | ||
| 17 | #include <linux/init.h> | ||
| 18 | #include <linux/input.h> | ||
| 19 | #include <linux/interrupt.h> | ||
| 20 | #include <linux/module.h> | ||
| 21 | |||
| 22 | #include <asm/hardware.h> | ||
| 23 | #include <asm/arch/jornada720.h> | ||
| 24 | |||
| 25 | MODULE_AUTHOR("Kristoffer Ericson <kristoffer.ericson@gmail.com>"); | ||
| 26 | MODULE_DESCRIPTION("HP Jornada 710/720/728 touchscreen driver"); | ||
| 27 | MODULE_LICENSE("GPLv2"); | ||
| 28 | |||
| 29 | struct jornada_ts { | ||
| 30 | struct input_dev *dev; | ||
| 31 | int x_data[4]; /* X sample values */ | ||
| 32 | int y_data[4]; /* Y sample values */ | ||
| 33 | }; | ||
| 34 | |||
| 35 | static void jornada720_ts_collect_data(struct jornada_ts *jornada_ts) | ||
| 36 | { | ||
| 37 | |||
| 38 | /* 3 low word X samples */ | ||
| 39 | jornada_ts->x_data[0] = jornada_ssp_byte(TXDUMMY); | ||
| 40 | jornada_ts->x_data[1] = jornada_ssp_byte(TXDUMMY); | ||
| 41 | jornada_ts->x_data[2] = jornada_ssp_byte(TXDUMMY); | ||
| 42 | |||
| 43 | /* 3 low word Y samples */ | ||
| 44 | jornada_ts->y_data[0] = jornada_ssp_byte(TXDUMMY); | ||
| 45 | jornada_ts->y_data[1] = jornada_ssp_byte(TXDUMMY); | ||
| 46 | jornada_ts->y_data[2] = jornada_ssp_byte(TXDUMMY); | ||
| 47 | |||
| 48 | /* combined x samples bits */ | ||
| 49 | jornada_ts->x_data[3] = jornada_ssp_byte(TXDUMMY); | ||
| 50 | |||
| 51 | /* combined y samples bits */ | ||
| 52 | jornada_ts->y_data[3] = jornada_ssp_byte(TXDUMMY); | ||
| 53 | } | ||
| 54 | |||
| 55 | static int jornada720_ts_average(int coords[4]) | ||
| 56 | { | ||
| 57 | int coord, high_bits = coords[3]; | ||
| 58 | |||
| 59 | coord = coords[0] | ((high_bits & 0x03) << 8); | ||
| 60 | coord += coords[1] | ((high_bits & 0x0c) << 6); | ||
| 61 | coord += coords[2] | ((high_bits & 0x30) << 4); | ||
| 62 | |||
| 63 | return coord / 3; | ||
| 64 | } | ||
| 65 | |||
| 66 | static irqreturn_t jornada720_ts_interrupt(int irq, void *dev_id) | ||
| 67 | { | ||
| 68 | struct platform_device *pdev = dev_id; | ||
| 69 | struct jornada_ts *jornada_ts = platform_get_drvdata(pdev); | ||
| 70 | struct input_dev *input = jornada_ts->dev; | ||
| 71 | int x, y; | ||
| 72 | |||
| 73 | /* If GPIO_GPIO9 is set to high then report pen up */ | ||
| 74 | if (GPLR & GPIO_GPIO(9)) { | ||
| 75 | input_report_key(input, BTN_TOUCH, 0); | ||
| 76 | input_sync(input); | ||
| 77 | } else { | ||
| 78 | jornada_ssp_start(); | ||
| 79 | |||
| 80 | /* proper reply to request is always TXDUMMY */ | ||
| 81 | if (jornada_ssp_inout(GETTOUCHSAMPLES) == TXDUMMY) { | ||
| 82 | jornada720_ts_collect_data(jornada_ts); | ||
| 83 | |||
| 84 | x = jornada720_ts_average(jornada_ts->x_data); | ||
| 85 | y = jornada720_ts_average(jornada_ts->y_data); | ||
| 86 | |||
| 87 | input_report_key(input, BTN_TOUCH, 1); | ||
| 88 | input_report_abs(input, ABS_X, x); | ||
| 89 | input_report_abs(input, ABS_Y, y); | ||
| 90 | input_sync(input); | ||
| 91 | } | ||
| 92 | |||
| 93 | jornada_ssp_end(); | ||
| 94 | } | ||
| 95 | |||
| 96 | return IRQ_HANDLED; | ||
| 97 | } | ||
| 98 | |||
| 99 | static int __devinit jornada720_ts_probe(struct platform_device *pdev) | ||
| 100 | { | ||
| 101 | struct jornada_ts *jornada_ts; | ||
| 102 | struct input_dev *input_dev; | ||
| 103 | int error; | ||
| 104 | |||
| 105 | jornada_ts = kzalloc(sizeof(struct jornada_ts), GFP_KERNEL); | ||
| 106 | input_dev = input_allocate_device(); | ||
| 107 | |||
| 108 | if (!jornada_ts || !input_dev) { | ||
| 109 | error = -ENOMEM; | ||
| 110 | goto fail1; | ||
| 111 | } | ||
| 112 | |||
| 113 | platform_set_drvdata(pdev, jornada_ts); | ||
| 114 | |||
| 115 | jornada_ts->dev = input_dev; | ||
| 116 | |||
| 117 | input_dev->name = "HP Jornada 7xx Touchscreen"; | ||
| 118 | input_dev->phys = "jornadats/input0"; | ||
| 119 | input_dev->id.bustype = BUS_HOST; | ||
| 120 | input_dev->dev.parent = &pdev->dev; | ||
| 121 | |||
| 122 | input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); | ||
| 123 | input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); | ||
| 124 | input_set_abs_params(input_dev, ABS_X, 270, 3900, 0, 0); | ||
| 125 | input_set_abs_params(input_dev, ABS_Y, 180, 3700, 0, 0); | ||
| 126 | |||
| 127 | error = request_irq(IRQ_GPIO9, | ||
| 128 | jornada720_ts_interrupt, | ||
| 129 | IRQF_DISABLED | IRQF_TRIGGER_RISING, | ||
| 130 | "HP7XX Touchscreen driver", pdev); | ||
| 131 | if (error) { | ||
| 132 | printk(KERN_INFO "HP7XX TS : Unable to acquire irq!\n"); | ||
| 133 | goto fail1; | ||
| 134 | } | ||
| 135 | |||
| 136 | error = input_register_device(jornada_ts->dev); | ||
| 137 | if (error) | ||
| 138 | goto fail2; | ||
| 139 | |||
| 140 | return 0; | ||
| 141 | |||
| 142 | fail2: | ||
| 143 | free_irq(IRQ_GPIO9, pdev); | ||
| 144 | fail1: | ||
| 145 | platform_set_drvdata(pdev, NULL); | ||
| 146 | input_free_device(input_dev); | ||
| 147 | kfree(jornada_ts); | ||
| 148 | return error; | ||
| 149 | } | ||
| 150 | |||
| 151 | static int __devexit jornada720_ts_remove(struct platform_device *pdev) | ||
| 152 | { | ||
| 153 | struct jornada_ts *jornada_ts = platform_get_drvdata(pdev); | ||
| 154 | |||
| 155 | free_irq(IRQ_GPIO9, pdev); | ||
| 156 | platform_set_drvdata(pdev, NULL); | ||
| 157 | input_unregister_device(jornada_ts->dev); | ||
| 158 | kfree(jornada_ts); | ||
| 159 | |||
| 160 | return 0; | ||
| 161 | } | ||
| 162 | |||
| 163 | static struct platform_driver jornada720_ts_driver = { | ||
| 164 | .probe = jornada720_ts_probe, | ||
| 165 | .remove = __devexit_p(jornada720_ts_remove), | ||
| 166 | .driver = { | ||
| 167 | .name = "jornada_ts", | ||
| 168 | }, | ||
| 169 | }; | ||
| 170 | |||
| 171 | static int __init jornada720_ts_init(void) | ||
| 172 | { | ||
| 173 | return platform_driver_register(&jornada720_ts_driver); | ||
| 174 | } | ||
| 175 | |||
| 176 | static void __exit jornada720_ts_exit(void) | ||
| 177 | { | ||
| 178 | platform_driver_unregister(&jornada720_ts_driver); | ||
| 179 | } | ||
| 180 | |||
| 181 | module_init(jornada720_ts_init); | ||
| 182 | module_exit(jornada720_ts_exit); | ||
diff --git a/drivers/input/touchscreen/ucb1400_ts.c b/drivers/input/touchscreen/ucb1400_ts.c index 36f944019158..86aed64ec0fb 100644 --- a/drivers/input/touchscreen/ucb1400_ts.c +++ b/drivers/input/touchscreen/ucb1400_ts.c | |||
| @@ -130,8 +130,7 @@ static unsigned int ucb1400_adc_read(struct ucb1400 *ucb, u16 adc_channel) | |||
| 130 | if (val & UCB_ADC_DAT_VALID) | 130 | if (val & UCB_ADC_DAT_VALID) |
| 131 | break; | 131 | break; |
| 132 | /* yield to other processes */ | 132 | /* yield to other processes */ |
| 133 | set_current_state(TASK_INTERRUPTIBLE); | 133 | schedule_timeout_uninterruptible(1); |
| 134 | schedule_timeout(1); | ||
| 135 | } | 134 | } |
| 136 | 135 | ||
| 137 | return UCB_ADC_DAT_VALUE(val); | 136 | return UCB_ADC_DAT_VALUE(val); |
diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c index 741f6c6f1e50..9fb3d5c30999 100644 --- a/drivers/input/touchscreen/usbtouchscreen.c +++ b/drivers/input/touchscreen/usbtouchscreen.c | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | * - Gunze AHL61 | 10 | * - Gunze AHL61 |
| 11 | * - DMC TSC-10/25 | 11 | * - DMC TSC-10/25 |
| 12 | * - IRTOUCHSYSTEMS/UNITOP | 12 | * - IRTOUCHSYSTEMS/UNITOP |
| 13 | * - IdealTEK URTC1000 | ||
| 13 | * | 14 | * |
| 14 | * Copyright (C) 2004-2006 by Daniel Ritz <daniel.ritz@gmx.ch> | 15 | * Copyright (C) 2004-2006 by Daniel Ritz <daniel.ritz@gmx.ch> |
| 15 | * Copyright (C) by Todd E. Johnson (mtouchusb.c) | 16 | * Copyright (C) by Todd E. Johnson (mtouchusb.c) |
| @@ -92,7 +93,7 @@ struct usbtouch_usb { | |||
| 92 | }; | 93 | }; |
| 93 | 94 | ||
| 94 | 95 | ||
| 95 | #if defined(CONFIG_TOUCHSCREEN_USB_EGALAX) || defined(CONFIG_TOUCHSCREEN_USB_ETURBO) | 96 | #if defined(CONFIG_TOUCHSCREEN_USB_EGALAX) || defined(CONFIG_TOUCHSCREEN_USB_ETURBO) || defined(CONFIG_TOUCHSCREEN_USB_IDEALTEK) |
| 96 | #define MULTI_PACKET | 97 | #define MULTI_PACKET |
| 97 | #endif | 98 | #endif |
| 98 | 99 | ||
| @@ -112,6 +113,8 @@ enum { | |||
| 112 | DEVTYPE_GUNZE, | 113 | DEVTYPE_GUNZE, |
| 113 | DEVTYPE_DMC_TSC10, | 114 | DEVTYPE_DMC_TSC10, |
| 114 | DEVTYPE_IRTOUCH, | 115 | DEVTYPE_IRTOUCH, |
| 116 | DEVTYPE_IDEALTEK, | ||
| 117 | DEVTYPE_GENERAL_TOUCH, | ||
| 115 | }; | 118 | }; |
| 116 | 119 | ||
| 117 | static struct usb_device_id usbtouch_devices[] = { | 120 | static struct usb_device_id usbtouch_devices[] = { |
| @@ -157,6 +160,14 @@ static struct usb_device_id usbtouch_devices[] = { | |||
| 157 | {USB_DEVICE(0x6615, 0x0001), .driver_info = DEVTYPE_IRTOUCH}, | 160 | {USB_DEVICE(0x6615, 0x0001), .driver_info = DEVTYPE_IRTOUCH}, |
| 158 | #endif | 161 | #endif |
| 159 | 162 | ||
| 163 | #ifdef CONFIG_TOUCHSCREEN_USB_IDEALTEK | ||
| 164 | {USB_DEVICE(0x1391, 0x1000), .driver_info = DEVTYPE_IDEALTEK}, | ||
| 165 | #endif | ||
| 166 | |||
| 167 | #ifdef CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH | ||
| 168 | {USB_DEVICE(0x0dfc, 0x0001), .driver_info = DEVTYPE_GENERAL_TOUCH}, | ||
| 169 | #endif | ||
| 170 | |||
| 160 | {} | 171 | {} |
| 161 | }; | 172 | }; |
| 162 | 173 | ||
| @@ -396,7 +407,8 @@ static int dmc_tsc10_init(struct usbtouch_usb *usbtouch) | |||
| 396 | TSC10_RATE_150, 0, buf, 2, USB_CTRL_SET_TIMEOUT); | 407 | TSC10_RATE_150, 0, buf, 2, USB_CTRL_SET_TIMEOUT); |
| 397 | if (ret < 0) | 408 | if (ret < 0) |
| 398 | return ret; | 409 | return ret; |
| 399 | if (buf[0] != 0x06 || buf[1] != 0x00) | 410 | if ((buf[0] != 0x06 || buf[1] != 0x00) && |
| 411 | (buf[0] != 0x15 || buf[1] != 0x01)) | ||
| 400 | return -ENODEV; | 412 | return -ENODEV; |
| 401 | 413 | ||
| 402 | /* start sending data */ | 414 | /* start sending data */ |
| @@ -438,6 +450,57 @@ static int irtouch_read_data(struct usbtouch_usb *dev, unsigned char *pkt) | |||
| 438 | 450 | ||
| 439 | 451 | ||
| 440 | /***************************************************************************** | 452 | /***************************************************************************** |
| 453 | * IdealTEK URTC1000 Part | ||
| 454 | */ | ||
| 455 | #ifdef CONFIG_TOUCHSCREEN_USB_IDEALTEK | ||
| 456 | static int idealtek_get_pkt_len(unsigned char *buf, int len) | ||
| 457 | { | ||
| 458 | if (buf[0] & 0x80) | ||
| 459 | return 5; | ||
| 460 | if (buf[0] == 0x01) | ||
| 461 | return len; | ||
| 462 | return 0; | ||
| 463 | } | ||
| 464 | |||
| 465 | static int idealtek_read_data(struct usbtouch_usb *dev, unsigned char *pkt) | ||
| 466 | { | ||
| 467 | switch (pkt[0] & 0x98) { | ||
| 468 | case 0x88: | ||
| 469 | /* touch data in IdealTEK mode */ | ||
| 470 | dev->x = (pkt[1] << 5) | (pkt[2] >> 2); | ||
| 471 | dev->y = (pkt[3] << 5) | (pkt[4] >> 2); | ||
| 472 | dev->touch = (pkt[0] & 0x40) ? 1 : 0; | ||
| 473 | return 1; | ||
| 474 | |||
| 475 | case 0x98: | ||
| 476 | /* touch data in MT emulation mode */ | ||
| 477 | dev->x = (pkt[2] << 5) | (pkt[1] >> 2); | ||
| 478 | dev->y = (pkt[4] << 5) | (pkt[3] >> 2); | ||
| 479 | dev->touch = (pkt[0] & 0x40) ? 1 : 0; | ||
| 480 | return 1; | ||
| 481 | |||
| 482 | default: | ||
| 483 | return 0; | ||
| 484 | } | ||
| 485 | } | ||
| 486 | #endif | ||
| 487 | |||
| 488 | /***************************************************************************** | ||
| 489 | * General Touch Part | ||
| 490 | */ | ||
| 491 | #ifdef CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH | ||
| 492 | static int general_touch_read_data(struct usbtouch_usb *dev, unsigned char *pkt) | ||
| 493 | { | ||
| 494 | dev->x = ((pkt[2] & 0x0F) << 8) | pkt[1] ; | ||
| 495 | dev->y = ((pkt[4] & 0x0F) << 8) | pkt[3] ; | ||
| 496 | dev->press = pkt[5] & 0xff; | ||
| 497 | dev->touch = pkt[0] & 0x01; | ||
| 498 | |||
| 499 | return 1; | ||
| 500 | } | ||
| 501 | #endif | ||
| 502 | |||
| 503 | /***************************************************************************** | ||
| 441 | * the different device descriptors | 504 | * the different device descriptors |
| 442 | */ | 505 | */ |
| 443 | static struct usbtouch_device_info usbtouch_dev_info[] = { | 506 | static struct usbtouch_device_info usbtouch_dev_info[] = { |
| @@ -537,6 +600,32 @@ static struct usbtouch_device_info usbtouch_dev_info[] = { | |||
| 537 | .read_data = irtouch_read_data, | 600 | .read_data = irtouch_read_data, |
| 538 | }, | 601 | }, |
| 539 | #endif | 602 | #endif |
| 603 | |||
| 604 | #ifdef CONFIG_TOUCHSCREEN_USB_IDEALTEK | ||
| 605 | [DEVTYPE_IDEALTEK] = { | ||
| 606 | .min_xc = 0x0, | ||
| 607 | .max_xc = 0x0fff, | ||
| 608 | .min_yc = 0x0, | ||
| 609 | .max_yc = 0x0fff, | ||
| 610 | .rept_size = 8, | ||
| 611 | .flags = USBTOUCH_FLG_BUFFER, | ||
| 612 | .process_pkt = usbtouch_process_multi, | ||
| 613 | .get_pkt_len = idealtek_get_pkt_len, | ||
| 614 | .read_data = idealtek_read_data, | ||
| 615 | }, | ||
| 616 | #endif | ||
| 617 | |||
| 618 | #ifdef CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH | ||
| 619 | [DEVTYPE_GENERAL_TOUCH] = { | ||
| 620 | .min_xc = 0x0, | ||
| 621 | .max_xc = 0x0500, | ||
| 622 | .min_yc = 0x0, | ||
| 623 | .max_yc = 0x0500, | ||
| 624 | .rept_size = 7, | ||
| 625 | .read_data = general_touch_read_data, | ||
| 626 | } | ||
| 627 | #endif | ||
| 628 | |||
| 540 | }; | 629 | }; |
| 541 | 630 | ||
| 542 | 631 | ||
diff --git a/drivers/input/tsdev.c b/drivers/input/tsdev.c deleted file mode 100644 index d2f882e98e5e..000000000000 --- a/drivers/input/tsdev.c +++ /dev/null | |||
| @@ -1,533 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * $Id: tsdev.c,v 1.15 2002/04/10 16:50:19 jsimmons Exp $ | ||
| 3 | * | ||
| 4 | * Copyright (c) 2001 "Crazy" james Simmons | ||
| 5 | * | ||
| 6 | * Compaq touchscreen protocol driver. The protocol emulated by this driver | ||
| 7 | * is obsolete; for new programs use the tslib library which can read directly | ||
| 8 | * from evdev and perform dejittering, variance filtering and calibration - | ||
| 9 | * all in user space, not at kernel level. The meaning of this driver is | ||
| 10 | * to allow usage of newer input drivers with old applications that use the | ||
| 11 | * old /dev/h3600_ts and /dev/h3600_tsraw devices. | ||
| 12 | * | ||
| 13 | * 09-Apr-2004: Andrew Zabolotny <zap@homelink.ru> | ||
| 14 | * Fixed to actually work, not just output random numbers. | ||
| 15 | * Added support for both h3600_ts and h3600_tsraw protocol | ||
| 16 | * emulation. | ||
| 17 | */ | ||
| 18 | |||
| 19 | /* | ||
| 20 | * This program is free software; you can redistribute it and/or modify | ||
| 21 | * it under the terms of the GNU General Public License as published by | ||
| 22 | * the Free Software Foundation; either version 2 of the License, or | ||
| 23 | * (at your option) any later version. | ||
| 24 | * | ||
| 25 | * This program is distributed in the hope that it will be useful, | ||
| 26 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 27 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 28 | * GNU General Public License for more details. | ||
| 29 | * | ||
| 30 | * You should have received a copy of the GNU General Public License | ||
| 31 | * along with this program; if not, write to the Free Software | ||
| 32 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 33 | * | ||
| 34 | * Should you need to contact me, the author, you can do so either by | ||
| 35 | * e-mail - mail your message to <jsimmons@infradead.org>. | ||
| 36 | */ | ||
| 37 | |||
| 38 | #define TSDEV_MINOR_BASE 128 | ||
| 39 | #define TSDEV_MINORS 32 | ||
| 40 | /* First 16 devices are h3600_ts compatible; second 16 are h3600_tsraw */ | ||
| 41 | #define TSDEV_MINOR_MASK 15 | ||
| 42 | #define TSDEV_BUFFER_SIZE 64 | ||
| 43 | |||
| 44 | #include <linux/slab.h> | ||
| 45 | #include <linux/poll.h> | ||
| 46 | #include <linux/module.h> | ||
| 47 | #include <linux/moduleparam.h> | ||
| 48 | #include <linux/init.h> | ||
| 49 | #include <linux/input.h> | ||
| 50 | #include <linux/major.h> | ||
| 51 | #include <linux/random.h> | ||
| 52 | #include <linux/time.h> | ||
| 53 | #include <linux/device.h> | ||
| 54 | |||
| 55 | #ifndef CONFIG_INPUT_TSDEV_SCREEN_X | ||
| 56 | #define CONFIG_INPUT_TSDEV_SCREEN_X 240 | ||
| 57 | #endif | ||
| 58 | #ifndef CONFIG_INPUT_TSDEV_SCREEN_Y | ||
| 59 | #define CONFIG_INPUT_TSDEV_SCREEN_Y 320 | ||
| 60 | #endif | ||
| 61 | |||
| 62 | /* This driver emulates both protocols of the old h3600_ts and h3600_tsraw | ||
| 63 | * devices. The first one must output X/Y data in 'cooked' format, e.g. | ||
| 64 | * filtered, dejittered and calibrated. Second device just outputs raw | ||
| 65 | * data received from the hardware. | ||
| 66 | * | ||
| 67 | * This driver doesn't support filtering and dejittering; it supports only | ||
| 68 | * calibration. Filtering and dejittering must be done in the low-level | ||
| 69 | * driver, if needed, because it may gain additional benefits from knowing | ||
| 70 | * the low-level details, the nature of noise and so on. | ||
| 71 | * | ||
| 72 | * The driver precomputes a calibration matrix given the initial xres and | ||
| 73 | * yres values (quite innacurate for most touchscreens) that will result | ||
| 74 | * in a more or less expected range of output values. The driver supports | ||
| 75 | * the TS_SET_CAL ioctl, which will replace the calibration matrix with a | ||
| 76 | * new one, supposedly generated from the values taken from the raw device. | ||
| 77 | */ | ||
| 78 | |||
| 79 | MODULE_AUTHOR("James Simmons <jsimmons@transvirtual.com>"); | ||
| 80 | MODULE_DESCRIPTION("Input driver to touchscreen converter"); | ||
| 81 | MODULE_LICENSE("GPL"); | ||
| 82 | |||
| 83 | static int xres = CONFIG_INPUT_TSDEV_SCREEN_X; | ||
| 84 | module_param(xres, uint, 0); | ||
| 85 | MODULE_PARM_DESC(xres, "Horizontal screen resolution (can be negative for X-mirror)"); | ||
| 86 | |||
| 87 | static int yres = CONFIG_INPUT_TSDEV_SCREEN_Y; | ||
| 88 | module_param(yres, uint, 0); | ||
| 89 | MODULE_PARM_DESC(yres, "Vertical screen resolution (can be negative for Y-mirror)"); | ||
| 90 | |||
| 91 | /* From Compaq's Touch Screen Specification version 0.2 (draft) */ | ||
| 92 | struct ts_event { | ||
| 93 | short pressure; | ||
| 94 | short x; | ||
| 95 | short y; | ||
| 96 | short millisecs; | ||
| 97 | }; | ||
| 98 | |||
| 99 | struct ts_calibration { | ||
| 100 | int xscale; | ||
| 101 | int xtrans; | ||
| 102 | int yscale; | ||
| 103 | int ytrans; | ||
| 104 | int xyswap; | ||
| 105 | }; | ||
| 106 | |||
| 107 | struct tsdev { | ||
| 108 | int exist; | ||
| 109 | int open; | ||
| 110 | int minor; | ||
| 111 | char name[8]; | ||
| 112 | struct input_handle handle; | ||
| 113 | wait_queue_head_t wait; | ||
| 114 | struct list_head client_list; | ||
| 115 | struct device dev; | ||
| 116 | |||
| 117 | int x, y, pressure; | ||
| 118 | struct ts_calibration cal; | ||
| 119 | }; | ||
| 120 | |||
| 121 | struct tsdev_client { | ||
| 122 | struct fasync_struct *fasync; | ||
| 123 | struct list_head node; | ||
| 124 | struct tsdev *tsdev; | ||
| 125 | int head, tail; | ||
| 126 | struct ts_event event[TSDEV_BUFFER_SIZE]; | ||
| 127 | int raw; | ||
| 128 | }; | ||
| 129 | |||
| 130 | /* The following ioctl codes are defined ONLY for backward compatibility. | ||
| 131 | * Don't use tsdev for new developement; use the tslib library instead. | ||
| 132 | * Touchscreen calibration is a fully userspace task. | ||
| 133 | */ | ||
| 134 | /* Use 'f' as magic number */ | ||
| 135 | #define IOC_H3600_TS_MAGIC 'f' | ||
| 136 | #define TS_GET_CAL _IOR(IOC_H3600_TS_MAGIC, 10, struct ts_calibration) | ||
| 137 | #define TS_SET_CAL _IOW(IOC_H3600_TS_MAGIC, 11, struct ts_calibration) | ||
| 138 | |||
| 139 | static struct tsdev *tsdev_table[TSDEV_MINORS/2]; | ||
| 140 | |||
| 141 | static int tsdev_fasync(int fd, struct file *file, int on) | ||
| 142 | { | ||
| 143 | struct tsdev_client *client = file->private_data; | ||
| 144 | int retval; | ||
| 145 | |||
| 146 | retval = fasync_helper(fd, file, on, &client->fasync); | ||
| 147 | return retval < 0 ? retval : 0; | ||
| 148 | } | ||
| 149 | |||
| 150 | static int tsdev_open(struct inode *inode, struct file *file) | ||
| 151 | { | ||
| 152 | int i = iminor(inode) - TSDEV_MINOR_BASE; | ||
| 153 | struct tsdev_client *client; | ||
| 154 | struct tsdev *tsdev; | ||
| 155 | int error; | ||
| 156 | |||
| 157 | printk(KERN_WARNING "tsdev (compaq touchscreen emulation) is scheduled " | ||
| 158 | "for removal.\nSee Documentation/feature-removal-schedule.txt " | ||
| 159 | "for details.\n"); | ||
| 160 | |||
| 161 | if (i >= TSDEV_MINORS) | ||
| 162 | return -ENODEV; | ||
| 163 | |||
| 164 | tsdev = tsdev_table[i & TSDEV_MINOR_MASK]; | ||
| 165 | if (!tsdev || !tsdev->exist) | ||
| 166 | return -ENODEV; | ||
| 167 | |||
| 168 | get_device(&tsdev->dev); | ||
| 169 | |||
| 170 | client = kzalloc(sizeof(struct tsdev_client), GFP_KERNEL); | ||
| 171 | if (!client) { | ||
| 172 | error = -ENOMEM; | ||
| 173 | goto err_put_tsdev; | ||
| 174 | } | ||
| 175 | |||
| 176 | client->tsdev = tsdev; | ||
| 177 | client->raw = (i >= TSDEV_MINORS / 2) ? 1 : 0; | ||
| 178 | list_add_tail(&client->node, &tsdev->client_list); | ||
| 179 | |||
| 180 | if (!tsdev->open++ && tsdev->exist) { | ||
| 181 | error = input_open_device(&tsdev->handle); | ||
| 182 | if (error) | ||
| 183 | goto err_free_client; | ||
| 184 | } | ||
| 185 | |||
| 186 | file->private_data = client; | ||
| 187 | return 0; | ||
| 188 | |||
| 189 | err_free_client: | ||
| 190 | list_del(&client->node); | ||
| 191 | kfree(client); | ||
| 192 | err_put_tsdev: | ||
| 193 | put_device(&tsdev->dev); | ||
| 194 | return error; | ||
| 195 | } | ||
| 196 | |||
| 197 | static void tsdev_free(struct device *dev) | ||
| 198 | { | ||
| 199 | struct tsdev *tsdev = container_of(dev, struct tsdev, dev); | ||
| 200 | |||
| 201 | tsdev_table[tsdev->minor] = NULL; | ||
| 202 | kfree(tsdev); | ||
| 203 | } | ||
| 204 | |||
| 205 | static int tsdev_release(struct inode *inode, struct file *file) | ||
| 206 | { | ||
| 207 | struct tsdev_client *client = file->private_data; | ||
| 208 | struct tsdev *tsdev = client->tsdev; | ||
| 209 | |||
| 210 | tsdev_fasync(-1, file, 0); | ||
| 211 | |||
| 212 | list_del(&client->node); | ||
| 213 | kfree(client); | ||
| 214 | |||
| 215 | if (!--tsdev->open && tsdev->exist) | ||
| 216 | input_close_device(&tsdev->handle); | ||
| 217 | |||
| 218 | put_device(&tsdev->dev); | ||
| 219 | |||
| 220 | return 0; | ||
| 221 | } | ||
| 222 | |||
| 223 | static ssize_t tsdev_read(struct file *file, char __user *buffer, size_t count, | ||
| 224 | loff_t *ppos) | ||
| 225 | { | ||
| 226 | struct tsdev_client *client = file->private_data; | ||
| 227 | struct tsdev *tsdev = client->tsdev; | ||
| 228 | int retval = 0; | ||
| 229 | |||
| 230 | if (client->head == client->tail && tsdev->exist && (file->f_flags & O_NONBLOCK)) | ||
| 231 | return -EAGAIN; | ||
| 232 | |||
| 233 | retval = wait_event_interruptible(tsdev->wait, | ||
| 234 | client->head != client->tail || !tsdev->exist); | ||
| 235 | if (retval) | ||
| 236 | return retval; | ||
| 237 | |||
| 238 | if (!tsdev->exist) | ||
| 239 | return -ENODEV; | ||
| 240 | |||
| 241 | while (client->head != client->tail && | ||
| 242 | retval + sizeof (struct ts_event) <= count) { | ||
| 243 | if (copy_to_user (buffer + retval, client->event + client->tail, | ||
| 244 | sizeof (struct ts_event))) | ||
| 245 | return -EFAULT; | ||
| 246 | client->tail = (client->tail + 1) & (TSDEV_BUFFER_SIZE - 1); | ||
| 247 | retval += sizeof (struct ts_event); | ||
| 248 | } | ||
| 249 | |||
| 250 | return retval; | ||
| 251 | } | ||
| 252 | |||
| 253 | /* No kernel lock - fine */ | ||
| 254 | static unsigned int tsdev_poll(struct file *file, poll_table *wait) | ||
| 255 | { | ||
| 256 | struct tsdev_client *client = file->private_data; | ||
| 257 | struct tsdev *tsdev = client->tsdev; | ||
| 258 | |||
| 259 | poll_wait(file, &tsdev->wait, wait); | ||
| 260 | return ((client->head == client->tail) ? 0 : (POLLIN | POLLRDNORM)) | | ||
| 261 | (tsdev->exist ? 0 : (POLLHUP | POLLERR)); | ||
| 262 | } | ||
| 263 | |||
| 264 | static int tsdev_ioctl(struct inode *inode, struct file *file, | ||
| 265 | unsigned int cmd, unsigned long arg) | ||
| 266 | { | ||
| 267 | struct tsdev_client *client = file->private_data; | ||
| 268 | struct tsdev *tsdev = client->tsdev; | ||
| 269 | int retval = 0; | ||
| 270 | |||
| 271 | switch (cmd) { | ||
| 272 | case TS_GET_CAL: | ||
| 273 | if (copy_to_user((void __user *)arg, &tsdev->cal, | ||
| 274 | sizeof (struct ts_calibration))) | ||
| 275 | retval = -EFAULT; | ||
| 276 | break; | ||
| 277 | |||
| 278 | case TS_SET_CAL: | ||
| 279 | if (copy_from_user(&tsdev->cal, (void __user *)arg, | ||
| 280 | sizeof (struct ts_calibration))) | ||
| 281 | retval = -EFAULT; | ||
| 282 | break; | ||
| 283 | |||
| 284 | default: | ||
| 285 | retval = -EINVAL; | ||
| 286 | break; | ||
| 287 | } | ||
| 288 | |||
| 289 | return retval; | ||
| 290 | } | ||
| 291 | |||
| 292 | static const struct file_operations tsdev_fops = { | ||
| 293 | .owner = THIS_MODULE, | ||
| 294 | .open = tsdev_open, | ||
| 295 | .release = tsdev_release, | ||
| 296 | .read = tsdev_read, | ||
| 297 | .poll = tsdev_poll, | ||
| 298 | .fasync = tsdev_fasync, | ||
| 299 | .ioctl = tsdev_ioctl, | ||
| 300 | }; | ||
| 301 | |||
| 302 | static void tsdev_event(struct input_handle *handle, unsigned int type, | ||
| 303 | unsigned int code, int value) | ||
| 304 | { | ||
| 305 | struct tsdev *tsdev = handle->private; | ||
| 306 | struct tsdev_client *client; | ||
| 307 | struct timeval time; | ||
| 308 | |||
| 309 | switch (type) { | ||
| 310 | case EV_ABS: | ||
| 311 | switch (code) { | ||
| 312 | case ABS_X: | ||
| 313 | tsdev->x = value; | ||
| 314 | break; | ||
| 315 | |||
| 316 | case ABS_Y: | ||
| 317 | tsdev->y = value; | ||
| 318 | break; | ||
| 319 | |||
| 320 | case ABS_PRESSURE: | ||
| 321 | if (value > handle->dev->absmax[ABS_PRESSURE]) | ||
| 322 | value = handle->dev->absmax[ABS_PRESSURE]; | ||
| 323 | value -= handle->dev->absmin[ABS_PRESSURE]; | ||
| 324 | if (value < 0) | ||
| 325 | value = 0; | ||
| 326 | tsdev->pressure = value; | ||
| 327 | break; | ||
| 328 | } | ||
| 329 | break; | ||
| 330 | |||
| 331 | case EV_REL: | ||
| 332 | switch (code) { | ||
| 333 | case REL_X: | ||
| 334 | tsdev->x += value; | ||
| 335 | if (tsdev->x < 0) | ||
| 336 | tsdev->x = 0; | ||
| 337 | else if (tsdev->x > xres) | ||
| 338 | tsdev->x = xres; | ||
| 339 | break; | ||
| 340 | |||
| 341 | case REL_Y: | ||
| 342 | tsdev->y += value; | ||
| 343 | if (tsdev->y < 0) | ||
| 344 | tsdev->y = 0; | ||
| 345 | else if (tsdev->y > yres) | ||
| 346 | tsdev->y = yres; | ||
| 347 | break; | ||
| 348 | } | ||
| 349 | break; | ||
| 350 | |||
| 351 | case EV_KEY: | ||
| 352 | if (code == BTN_TOUCH || code == BTN_MOUSE) { | ||
| 353 | switch (value) { | ||
| 354 | case 0: | ||
| 355 | tsdev->pressure = 0; | ||
| 356 | break; | ||
| 357 | |||
| 358 | case 1: | ||
| 359 | if (!tsdev->pressure) | ||
| 360 | tsdev->pressure = 1; | ||
| 361 | break; | ||
| 362 | } | ||
| 363 | } | ||
| 364 | break; | ||
| 365 | } | ||
| 366 | |||
| 367 | if (type != EV_SYN || code != SYN_REPORT) | ||
| 368 | return; | ||
| 369 | |||
| 370 | list_for_each_entry(client, &tsdev->client_list, node) { | ||
| 371 | int x, y, tmp; | ||
| 372 | |||
| 373 | do_gettimeofday(&time); | ||
| 374 | client->event[client->head].millisecs = time.tv_usec / 1000; | ||
| 375 | client->event[client->head].pressure = tsdev->pressure; | ||
| 376 | |||
| 377 | x = tsdev->x; | ||
| 378 | y = tsdev->y; | ||
| 379 | |||
| 380 | /* Calibration */ | ||
| 381 | if (!client->raw) { | ||
| 382 | x = ((x * tsdev->cal.xscale) >> 8) + tsdev->cal.xtrans; | ||
| 383 | y = ((y * tsdev->cal.yscale) >> 8) + tsdev->cal.ytrans; | ||
| 384 | if (tsdev->cal.xyswap) { | ||
| 385 | tmp = x; x = y; y = tmp; | ||
| 386 | } | ||
| 387 | } | ||
| 388 | |||
| 389 | client->event[client->head].x = x; | ||
| 390 | client->event[client->head].y = y; | ||
| 391 | client->head = (client->head + 1) & (TSDEV_BUFFER_SIZE - 1); | ||
| 392 | kill_fasync(&client->fasync, SIGIO, POLL_IN); | ||
| 393 | } | ||
| 394 | wake_up_interruptible(&tsdev->wait); | ||
| 395 | } | ||
| 396 | |||
| 397 | static int tsdev_connect(struct input_handler *handler, struct input_dev *dev, | ||
| 398 | const struct input_device_id *id) | ||
| 399 | { | ||
| 400 | struct tsdev *tsdev; | ||
| 401 | int minor, delta; | ||
| 402 | int error; | ||
| 403 | |||
| 404 | for (minor = 0; minor < TSDEV_MINORS / 2 && tsdev_table[minor]; minor++); | ||
| 405 | if (minor >= TSDEV_MINORS / 2) { | ||
| 406 | printk(KERN_ERR | ||
| 407 | "tsdev: You have way too many touchscreens\n"); | ||
| 408 | return -ENFILE; | ||
| 409 | } | ||
| 410 | |||
| 411 | tsdev = kzalloc(sizeof(struct tsdev), GFP_KERNEL); | ||
| 412 | if (!tsdev) | ||
| 413 | return -ENOMEM; | ||
| 414 | |||
| 415 | INIT_LIST_HEAD(&tsdev->client_list); | ||
| 416 | init_waitqueue_head(&tsdev->wait); | ||
| 417 | |||
| 418 | tsdev->exist = 1; | ||
| 419 | tsdev->minor = minor; | ||
| 420 | tsdev->handle.dev = dev; | ||
| 421 | tsdev->handle.name = tsdev->name; | ||
| 422 | tsdev->handle.handler = handler; | ||
| 423 | tsdev->handle.private = tsdev; | ||
| 424 | snprintf(tsdev->name, sizeof(tsdev->name), "ts%d", minor); | ||
| 425 | |||
| 426 | /* Precompute the rough calibration matrix */ | ||
| 427 | delta = dev->absmax [ABS_X] - dev->absmin [ABS_X] + 1; | ||
| 428 | if (delta == 0) | ||
| 429 | delta = 1; | ||
| 430 | tsdev->cal.xscale = (xres << 8) / delta; | ||
| 431 | tsdev->cal.xtrans = - ((dev->absmin [ABS_X] * tsdev->cal.xscale) >> 8); | ||
| 432 | |||
| 433 | delta = dev->absmax [ABS_Y] - dev->absmin [ABS_Y] + 1; | ||
| 434 | if (delta == 0) | ||
| 435 | delta = 1; | ||
| 436 | tsdev->cal.yscale = (yres << 8) / delta; | ||
| 437 | tsdev->cal.ytrans = - ((dev->absmin [ABS_Y] * tsdev->cal.yscale) >> 8); | ||
| 438 | |||
| 439 | snprintf(tsdev->dev.bus_id, sizeof(tsdev->dev.bus_id), | ||
| 440 | "ts%d", minor); | ||
| 441 | tsdev->dev.class = &input_class; | ||
| 442 | tsdev->dev.parent = &dev->dev; | ||
| 443 | tsdev->dev.devt = MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor); | ||
| 444 | tsdev->dev.release = tsdev_free; | ||
| 445 | device_initialize(&tsdev->dev); | ||
| 446 | |||
| 447 | tsdev_table[minor] = tsdev; | ||
| 448 | |||
| 449 | error = device_add(&tsdev->dev); | ||
| 450 | if (error) | ||
| 451 | goto err_free_tsdev; | ||
| 452 | |||
| 453 | error = input_register_handle(&tsdev->handle); | ||
| 454 | if (error) | ||
| 455 | goto err_delete_tsdev; | ||
| 456 | |||
| 457 | return 0; | ||
| 458 | |||
| 459 | err_delete_tsdev: | ||
| 460 | device_del(&tsdev->dev); | ||
| 461 | err_free_tsdev: | ||
| 462 | put_device(&tsdev->dev); | ||
| 463 | return error; | ||
| 464 | } | ||
| 465 | |||
| 466 | static void tsdev_disconnect(struct input_handle *handle) | ||
| 467 | { | ||
| 468 | struct tsdev *tsdev = handle->private; | ||
| 469 | struct tsdev_client *client; | ||
| 470 | |||
| 471 | input_unregister_handle(handle); | ||
| 472 | device_del(&tsdev->dev); | ||
| 473 | |||
| 474 | tsdev->exist = 0; | ||
| 475 | |||
| 476 | if (tsdev->open) { | ||
| 477 | input_close_device(handle); | ||
| 478 | list_for_each_entry(client, &tsdev->client_list, node) | ||
| 479 | kill_fasync(&client->fasync, SIGIO, POLL_HUP); | ||
| 480 | wake_up_interruptible(&tsdev->wait); | ||
| 481 | } | ||
| 482 | |||
| 483 | put_device(&tsdev->dev); | ||
| 484 | } | ||
| 485 | |||
| 486 | static const struct input_device_id tsdev_ids[] = { | ||
| 487 | { | ||
| 488 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_RELBIT, | ||
| 489 | .evbit = { BIT(EV_KEY) | BIT(EV_REL) }, | ||
| 490 | .keybit = { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) }, | ||
| 491 | .relbit = { BIT(REL_X) | BIT(REL_Y) }, | ||
| 492 | }, /* A mouse like device, at least one button, two relative axes */ | ||
| 493 | |||
| 494 | { | ||
| 495 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_ABSBIT, | ||
| 496 | .evbit = { BIT(EV_KEY) | BIT(EV_ABS) }, | ||
| 497 | .keybit = { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) }, | ||
| 498 | .absbit = { BIT(ABS_X) | BIT(ABS_Y) }, | ||
| 499 | }, /* A tablet like device, at least touch detection, two absolute axes */ | ||
| 500 | |||
| 501 | { | ||
| 502 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT, | ||
| 503 | .evbit = { BIT(EV_ABS) }, | ||
| 504 | .absbit = { BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) }, | ||
| 505 | }, /* A tablet like device with several gradations of pressure */ | ||
| 506 | |||
| 507 | {} /* Terminating entry */ | ||
| 508 | }; | ||
| 509 | |||
| 510 | MODULE_DEVICE_TABLE(input, tsdev_ids); | ||
| 511 | |||
| 512 | static struct input_handler tsdev_handler = { | ||
| 513 | .event = tsdev_event, | ||
| 514 | .connect = tsdev_connect, | ||
| 515 | .disconnect = tsdev_disconnect, | ||
| 516 | .fops = &tsdev_fops, | ||
| 517 | .minor = TSDEV_MINOR_BASE, | ||
| 518 | .name = "tsdev", | ||
| 519 | .id_table = tsdev_ids, | ||
| 520 | }; | ||
| 521 | |||
| 522 | static int __init tsdev_init(void) | ||
| 523 | { | ||
| 524 | return input_register_handler(&tsdev_handler); | ||
| 525 | } | ||
| 526 | |||
| 527 | static void __exit tsdev_exit(void) | ||
| 528 | { | ||
| 529 | input_unregister_handler(&tsdev_handler); | ||
| 530 | } | ||
| 531 | |||
| 532 | module_init(tsdev_init); | ||
| 533 | module_exit(tsdev_exit); | ||
diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig index 56cd8998fe4b..77f50b63a970 100644 --- a/drivers/macintosh/Kconfig +++ b/drivers/macintosh/Kconfig | |||
| @@ -172,6 +172,7 @@ config INPUT_ADBHID | |||
| 172 | 172 | ||
| 173 | config MAC_EMUMOUSEBTN | 173 | config MAC_EMUMOUSEBTN |
| 174 | bool "Support for mouse button 2+3 emulation" | 174 | bool "Support for mouse button 2+3 emulation" |
| 175 | select INPUT | ||
| 175 | help | 176 | help |
| 176 | This provides generic support for emulating the 2nd and 3rd mouse | 177 | This provides generic support for emulating the 2nd and 3rd mouse |
| 177 | button with keypresses. If you say Y here, the emulation is still | 178 | button with keypresses. If you say Y here, the emulation is still |
diff --git a/drivers/macintosh/adbhid.c b/drivers/macintosh/adbhid.c index 48d17bf6c927..8cce016b3d09 100644 --- a/drivers/macintosh/adbhid.c +++ b/drivers/macintosh/adbhid.c | |||
| @@ -52,6 +52,11 @@ | |||
| 52 | 52 | ||
| 53 | MODULE_AUTHOR("Franz Sirl <Franz.Sirl-kernel@lauterbach.com>"); | 53 | MODULE_AUTHOR("Franz Sirl <Franz.Sirl-kernel@lauterbach.com>"); |
| 54 | 54 | ||
| 55 | static int restore_capslock_events; | ||
| 56 | module_param(restore_capslock_events, int, 0644); | ||
| 57 | MODULE_PARM_DESC(restore_capslock_events, | ||
| 58 | "Produce keypress events for capslock on both keyup and keydown."); | ||
| 59 | |||
| 55 | #define KEYB_KEYREG 0 /* register # for key up/down data */ | 60 | #define KEYB_KEYREG 0 /* register # for key up/down data */ |
| 56 | #define KEYB_LEDREG 2 /* register # for leds on ADB keyboard */ | 61 | #define KEYB_LEDREG 2 /* register # for leds on ADB keyboard */ |
| 57 | #define MOUSE_DATAREG 0 /* reg# for movement/button codes from mouse */ | 62 | #define MOUSE_DATAREG 0 /* reg# for movement/button codes from mouse */ |
| @@ -217,6 +222,8 @@ struct adbhid { | |||
| 217 | #define FLAG_FN_KEY_PRESSED 0x00000001 | 222 | #define FLAG_FN_KEY_PRESSED 0x00000001 |
| 218 | #define FLAG_POWER_FROM_FN 0x00000002 | 223 | #define FLAG_POWER_FROM_FN 0x00000002 |
| 219 | #define FLAG_EMU_FWDEL_DOWN 0x00000004 | 224 | #define FLAG_EMU_FWDEL_DOWN 0x00000004 |
| 225 | #define FLAG_CAPSLOCK_TRANSLATE 0x00000008 | ||
| 226 | #define FLAG_CAPSLOCK_DOWN 0x00000010 | ||
| 220 | 227 | ||
| 221 | static struct adbhid *adbhid[16]; | 228 | static struct adbhid *adbhid[16]; |
| 222 | 229 | ||
| @@ -272,19 +279,50 @@ adbhid_keyboard_input(unsigned char *data, int nb, int apoll) | |||
| 272 | } | 279 | } |
| 273 | 280 | ||
| 274 | static void | 281 | static void |
| 275 | adbhid_input_keycode(int id, int keycode, int repeat) | 282 | adbhid_input_keycode(int id, int scancode, int repeat) |
| 276 | { | 283 | { |
| 277 | struct adbhid *ahid = adbhid[id]; | 284 | struct adbhid *ahid = adbhid[id]; |
| 278 | int up_flag, key; | 285 | int keycode, up_flag; |
| 279 | 286 | ||
| 280 | up_flag = (keycode & 0x80); | 287 | keycode = scancode & 0x7f; |
| 281 | keycode &= 0x7f; | 288 | up_flag = scancode & 0x80; |
| 289 | |||
| 290 | if (restore_capslock_events) { | ||
| 291 | if (keycode == ADB_KEY_CAPSLOCK && !up_flag) { | ||
| 292 | /* Key pressed, turning on the CapsLock LED. | ||
| 293 | * The next 0xff will be interpreted as a release. */ | ||
| 294 | ahid->flags |= FLAG_CAPSLOCK_TRANSLATE | ||
| 295 | | FLAG_CAPSLOCK_DOWN; | ||
| 296 | } else if (scancode == 0xff) { | ||
| 297 | /* Scancode 0xff usually signifies that the capslock | ||
| 298 | * key was either pressed or released. */ | ||
| 299 | if (ahid->flags & FLAG_CAPSLOCK_TRANSLATE) { | ||
| 300 | keycode = ADB_KEY_CAPSLOCK; | ||
| 301 | if (ahid->flags & FLAG_CAPSLOCK_DOWN) { | ||
| 302 | /* Key released */ | ||
| 303 | up_flag = 1; | ||
| 304 | ahid->flags &= ~FLAG_CAPSLOCK_DOWN; | ||
| 305 | } else { | ||
| 306 | /* Key pressed */ | ||
| 307 | up_flag = 0; | ||
| 308 | ahid->flags &= ~FLAG_CAPSLOCK_TRANSLATE; | ||
| 309 | } | ||
| 310 | } else { | ||
| 311 | printk(KERN_INFO "Spurious caps lock event " | ||
| 312 | "(scancode 0xff)."); | ||
| 313 | } | ||
| 314 | } | ||
| 315 | } | ||
| 282 | 316 | ||
| 283 | switch (keycode) { | 317 | switch (keycode) { |
| 284 | case ADB_KEY_CAPSLOCK: /* Generate down/up events for CapsLock everytime. */ | 318 | case ADB_KEY_CAPSLOCK: |
| 285 | input_report_key(ahid->input, KEY_CAPSLOCK, 1); | 319 | if (!restore_capslock_events) { |
| 286 | input_report_key(ahid->input, KEY_CAPSLOCK, 0); | 320 | /* Generate down/up events for CapsLock everytime. */ |
| 287 | input_sync(ahid->input); | 321 | input_report_key(ahid->input, KEY_CAPSLOCK, 1); |
| 322 | input_sync(ahid->input); | ||
| 323 | input_report_key(ahid->input, KEY_CAPSLOCK, 0); | ||
| 324 | input_sync(ahid->input); | ||
| 325 | } | ||
| 288 | return; | 326 | return; |
| 289 | #ifdef CONFIG_PPC_PMAC | 327 | #ifdef CONFIG_PPC_PMAC |
| 290 | case ADB_KEY_POWER_OLD: /* Power key on PBook 3400 needs remapping */ | 328 | case ADB_KEY_POWER_OLD: /* Power key on PBook 3400 needs remapping */ |
| @@ -296,7 +334,7 @@ adbhid_input_keycode(int id, int keycode, int repeat) | |||
| 296 | keycode = ADB_KEY_POWER; | 334 | keycode = ADB_KEY_POWER; |
| 297 | } | 335 | } |
| 298 | break; | 336 | break; |
| 299 | case ADB_KEY_POWER: | 337 | case ADB_KEY_POWER: |
| 300 | /* Fn + Command will produce a bogus "power" keycode */ | 338 | /* Fn + Command will produce a bogus "power" keycode */ |
| 301 | if (ahid->flags & FLAG_FN_KEY_PRESSED) { | 339 | if (ahid->flags & FLAG_FN_KEY_PRESSED) { |
| 302 | keycode = ADB_KEY_CMD; | 340 | keycode = ADB_KEY_CMD; |
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 216948dd71a5..81e068fa7ac5 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c | |||
| @@ -945,15 +945,15 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
| 945 | KEY_UNKNOWN, /* 0x0C: FN+BACKSPACE */ | 945 | KEY_UNKNOWN, /* 0x0C: FN+BACKSPACE */ |
| 946 | KEY_UNKNOWN, /* 0x0D: FN+INSERT */ | 946 | KEY_UNKNOWN, /* 0x0D: FN+INSERT */ |
| 947 | KEY_UNKNOWN, /* 0x0E: FN+DELETE */ | 947 | KEY_UNKNOWN, /* 0x0E: FN+DELETE */ |
| 948 | KEY_RESERVED, /* 0x0F: FN+HOME (brightness up) */ | 948 | KEY_BRIGHTNESSUP, /* 0x0F: FN+HOME (brightness up) */ |
| 949 | /* Scan codes 0x10 to 0x1F: Extended ACPI HKEY hot keys */ | 949 | /* Scan codes 0x10 to 0x1F: Extended ACPI HKEY hot keys */ |
| 950 | KEY_RESERVED, /* 0x10: FN+END (brightness down) */ | 950 | KEY_BRIGHTNESSDOWN, /* 0x10: FN+END (brightness down) */ |
| 951 | KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */ | 951 | KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */ |
| 952 | KEY_UNKNOWN, /* 0x12: FN+PGDOWN */ | 952 | KEY_UNKNOWN, /* 0x12: FN+PGDOWN */ |
| 953 | KEY_ZOOM, /* 0x13: FN+SPACE (zoom) */ | 953 | KEY_ZOOM, /* 0x13: FN+SPACE (zoom) */ |
| 954 | KEY_RESERVED, /* 0x14: VOLUME UP */ | 954 | KEY_VOLUMEUP, /* 0x14: VOLUME UP */ |
| 955 | KEY_RESERVED, /* 0x15: VOLUME DOWN */ | 955 | KEY_VOLUMEDOWN, /* 0x15: VOLUME DOWN */ |
| 956 | KEY_RESERVED, /* 0x16: MUTE */ | 956 | KEY_MUTE, /* 0x16: MUTE */ |
| 957 | KEY_VENDOR, /* 0x17: Thinkpad/AccessIBM/Lenovo */ | 957 | KEY_VENDOR, /* 0x17: Thinkpad/AccessIBM/Lenovo */ |
| 958 | /* (assignments unknown, please report if found) */ | 958 | /* (assignments unknown, please report if found) */ |
| 959 | KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, | 959 | KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, |
| @@ -974,9 +974,9 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
| 974 | KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */ | 974 | KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */ |
| 975 | KEY_UNKNOWN, /* 0x12: FN+PGDOWN */ | 975 | KEY_UNKNOWN, /* 0x12: FN+PGDOWN */ |
| 976 | KEY_ZOOM, /* 0x13: FN+SPACE (zoom) */ | 976 | KEY_ZOOM, /* 0x13: FN+SPACE (zoom) */ |
| 977 | KEY_RESERVED, /* 0x14: VOLUME UP */ | 977 | KEY_VOLUMEUP, /* 0x14: VOLUME UP */ |
| 978 | KEY_RESERVED, /* 0x15: VOLUME DOWN */ | 978 | KEY_VOLUMEDOWN, /* 0x15: VOLUME DOWN */ |
| 979 | KEY_RESERVED, /* 0x16: MUTE */ | 979 | KEY_MUTE, /* 0x16: MUTE */ |
| 980 | KEY_VENDOR, /* 0x17: Thinkpad/AccessIBM/Lenovo */ | 980 | KEY_VENDOR, /* 0x17: Thinkpad/AccessIBM/Lenovo */ |
| 981 | /* (assignments unknown, please report if found) */ | 981 | /* (assignments unknown, please report if found) */ |
| 982 | KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, | 982 | KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, |
diff --git a/drivers/mtd/maps/pxa2xx-flash.c b/drivers/mtd/maps/pxa2xx-flash.c index cb933ac475d5..82113295c266 100644 --- a/drivers/mtd/maps/pxa2xx-flash.c +++ b/drivers/mtd/maps/pxa2xx-flash.c | |||
| @@ -14,20 +14,20 @@ | |||
| 14 | #include <linux/kernel.h> | 14 | #include <linux/kernel.h> |
| 15 | #include <linux/init.h> | 15 | #include <linux/init.h> |
| 16 | #include <linux/platform_device.h> | 16 | #include <linux/platform_device.h> |
| 17 | #include <linux/dma-mapping.h> | ||
| 18 | #include <linux/mtd/mtd.h> | 17 | #include <linux/mtd/mtd.h> |
| 19 | #include <linux/mtd/map.h> | 18 | #include <linux/mtd/map.h> |
| 20 | #include <linux/mtd/partitions.h> | 19 | #include <linux/mtd/partitions.h> |
| 21 | 20 | ||
| 22 | #include <asm/io.h> | 21 | #include <asm/io.h> |
| 23 | #include <asm/hardware.h> | 22 | #include <asm/hardware.h> |
| 23 | #include <asm/cacheflush.h> | ||
| 24 | 24 | ||
| 25 | #include <asm/mach/flash.h> | 25 | #include <asm/mach/flash.h> |
| 26 | 26 | ||
| 27 | static void pxa2xx_map_inval_cache(struct map_info *map, unsigned long from, | 27 | static void pxa2xx_map_inval_cache(struct map_info *map, unsigned long from, |
| 28 | ssize_t len) | 28 | ssize_t len) |
| 29 | { | 29 | { |
| 30 | consistent_sync((char *)map->cached + from, len, DMA_FROM_DEVICE); | 30 | flush_ioremap_region(map->phys, map->cached, from, len); |
| 31 | } | 31 | } |
| 32 | 32 | ||
| 33 | struct pxa2xx_flash_info { | 33 | struct pxa2xx_flash_info { |
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 9c635a237a9d..8f99a0626616 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig | |||
| @@ -1780,6 +1780,15 @@ config SC92031 | |||
| 1780 | To compile this driver as a module, choose M here: the module | 1780 | To compile this driver as a module, choose M here: the module |
| 1781 | will be called sc92031. This is recommended. | 1781 | will be called sc92031. This is recommended. |
| 1782 | 1782 | ||
| 1783 | config CPMAC | ||
| 1784 | tristate "TI AR7 CPMAC Ethernet support (EXPERIMENTAL)" | ||
| 1785 | depends on NET_ETHERNET && EXPERIMENTAL && AR7 | ||
| 1786 | select PHYLIB | ||
| 1787 | select FIXED_PHY | ||
| 1788 | select FIXED_MII_100_FDX | ||
| 1789 | help | ||
| 1790 | TI AR7 CPMAC Ethernet support | ||
| 1791 | |||
| 1783 | config NET_POCKET | 1792 | config NET_POCKET |
| 1784 | bool "Pocket and portable adapters" | 1793 | bool "Pocket and portable adapters" |
| 1785 | depends on PARPORT | 1794 | depends on PARPORT |
diff --git a/drivers/net/Makefile b/drivers/net/Makefile index d2e0f35da42e..22f78cbd126b 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile | |||
| @@ -159,6 +159,7 @@ obj-$(CONFIG_8139CP) += 8139cp.o | |||
| 159 | obj-$(CONFIG_8139TOO) += 8139too.o | 159 | obj-$(CONFIG_8139TOO) += 8139too.o |
| 160 | obj-$(CONFIG_ZNET) += znet.o | 160 | obj-$(CONFIG_ZNET) += znet.o |
| 161 | obj-$(CONFIG_LAN_SAA9730) += saa9730.o | 161 | obj-$(CONFIG_LAN_SAA9730) += saa9730.o |
| 162 | obj-$(CONFIG_CPMAC) += cpmac.o | ||
| 162 | obj-$(CONFIG_DEPCA) += depca.o | 163 | obj-$(CONFIG_DEPCA) += depca.o |
| 163 | obj-$(CONFIG_EWRK3) += ewrk3.o | 164 | obj-$(CONFIG_EWRK3) += ewrk3.o |
| 164 | obj-$(CONFIG_ATP) += atp.o | 165 | obj-$(CONFIG_ATP) += atp.o |
diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c index b46c5d8a77bd..185f98e3964c 100644 --- a/drivers/net/au1000_eth.c +++ b/drivers/net/au1000_eth.c | |||
| @@ -54,13 +54,16 @@ | |||
| 54 | #include <linux/delay.h> | 54 | #include <linux/delay.h> |
| 55 | #include <linux/crc32.h> | 55 | #include <linux/crc32.h> |
| 56 | #include <linux/phy.h> | 56 | #include <linux/phy.h> |
| 57 | |||
| 58 | #include <asm/cpu.h> | ||
| 57 | #include <asm/mipsregs.h> | 59 | #include <asm/mipsregs.h> |
| 58 | #include <asm/irq.h> | 60 | #include <asm/irq.h> |
| 59 | #include <asm/io.h> | 61 | #include <asm/io.h> |
| 60 | #include <asm/processor.h> | 62 | #include <asm/processor.h> |
| 61 | 63 | ||
| 62 | #include <asm/mach-au1x00/au1000.h> | 64 | #include <au1000.h> |
| 63 | #include <asm/cpu.h> | 65 | #include <prom.h> |
| 66 | |||
| 64 | #include "au1000_eth.h" | 67 | #include "au1000_eth.h" |
| 65 | 68 | ||
| 66 | #ifdef AU1000_ETH_DEBUG | 69 | #ifdef AU1000_ETH_DEBUG |
| @@ -96,11 +99,6 @@ static void mdio_write(struct net_device *, int, int, u16); | |||
| 96 | static void au1000_adjust_link(struct net_device *); | 99 | static void au1000_adjust_link(struct net_device *); |
| 97 | static void enable_mac(struct net_device *, int); | 100 | static void enable_mac(struct net_device *, int); |
| 98 | 101 | ||
| 99 | // externs | ||
| 100 | extern int get_ethernet_addr(char *ethernet_addr); | ||
| 101 | extern void str2eaddr(unsigned char *ea, unsigned char *str); | ||
| 102 | extern char * prom_getcmdline(void); | ||
| 103 | |||
| 104 | /* | 102 | /* |
| 105 | * Theory of operation | 103 | * Theory of operation |
| 106 | * | 104 | * |
| @@ -619,7 +617,6 @@ static struct net_device * au1000_probe(int port_num) | |||
| 619 | struct au1000_private *aup = NULL; | 617 | struct au1000_private *aup = NULL; |
| 620 | struct net_device *dev = NULL; | 618 | struct net_device *dev = NULL; |
| 621 | db_dest_t *pDB, *pDBfree; | 619 | db_dest_t *pDB, *pDBfree; |
| 622 | char *pmac, *argptr; | ||
| 623 | char ethaddr[6]; | 620 | char ethaddr[6]; |
| 624 | int irq, i, err; | 621 | int irq, i, err; |
| 625 | u32 base, macen; | 622 | u32 base, macen; |
| @@ -677,21 +674,12 @@ static struct net_device * au1000_probe(int port_num) | |||
| 677 | au_macs[port_num] = aup; | 674 | au_macs[port_num] = aup; |
| 678 | 675 | ||
| 679 | if (port_num == 0) { | 676 | if (port_num == 0) { |
| 680 | /* Check the environment variables first */ | 677 | if (prom_get_ethernet_addr(ethaddr) == 0) |
| 681 | if (get_ethernet_addr(ethaddr) == 0) | ||
| 682 | memcpy(au1000_mac_addr, ethaddr, sizeof(au1000_mac_addr)); | 678 | memcpy(au1000_mac_addr, ethaddr, sizeof(au1000_mac_addr)); |
| 683 | else { | 679 | else { |
| 684 | /* Check command line */ | 680 | printk(KERN_INFO "%s: No MAC address found\n", |
| 685 | argptr = prom_getcmdline(); | 681 | dev->name); |
| 686 | if ((pmac = strstr(argptr, "ethaddr=")) == NULL) | ||
| 687 | printk(KERN_INFO "%s: No MAC address found\n", | ||
| 688 | dev->name); | ||
| 689 | /* Use the hard coded MAC addresses */ | 682 | /* Use the hard coded MAC addresses */ |
| 690 | else { | ||
| 691 | str2eaddr(ethaddr, pmac + strlen("ethaddr=")); | ||
| 692 | memcpy(au1000_mac_addr, ethaddr, | ||
| 693 | sizeof(au1000_mac_addr)); | ||
| 694 | } | ||
| 695 | } | 683 | } |
| 696 | 684 | ||
| 697 | setup_hw_rings(aup, MAC0_RX_DMA_ADDR, MAC0_TX_DMA_ADDR); | 685 | setup_hw_rings(aup, MAC0_RX_DMA_ADDR, MAC0_TX_DMA_ADDR); |
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 64bfec32e2a6..db80f243dd37 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c | |||
| @@ -98,6 +98,7 @@ static char *xmit_hash_policy = NULL; | |||
| 98 | static int arp_interval = BOND_LINK_ARP_INTERV; | 98 | static int arp_interval = BOND_LINK_ARP_INTERV; |
| 99 | static char *arp_ip_target[BOND_MAX_ARP_TARGETS] = { NULL, }; | 99 | static char *arp_ip_target[BOND_MAX_ARP_TARGETS] = { NULL, }; |
| 100 | static char *arp_validate = NULL; | 100 | static char *arp_validate = NULL; |
| 101 | static int fail_over_mac = 0; | ||
| 101 | struct bond_params bonding_defaults; | 102 | struct bond_params bonding_defaults; |
| 102 | 103 | ||
| 103 | module_param(max_bonds, int, 0); | 104 | module_param(max_bonds, int, 0); |
| @@ -131,6 +132,8 @@ module_param_array(arp_ip_target, charp, NULL, 0); | |||
| 131 | MODULE_PARM_DESC(arp_ip_target, "arp targets in n.n.n.n form"); | 132 | MODULE_PARM_DESC(arp_ip_target, "arp targets in n.n.n.n form"); |
| 132 | module_param(arp_validate, charp, 0); | 133 | module_param(arp_validate, charp, 0); |
| 133 | MODULE_PARM_DESC(arp_validate, "validate src/dst of ARP probes: none (default), active, backup or all"); | 134 | MODULE_PARM_DESC(arp_validate, "validate src/dst of ARP probes: none (default), active, backup or all"); |
| 135 | module_param(fail_over_mac, int, 0); | ||
| 136 | MODULE_PARM_DESC(fail_over_mac, "For active-backup, do not set all slaves to the same MAC. 0 of off (default), 1 for on."); | ||
| 134 | 137 | ||
| 135 | /*----------------------------- Global variables ----------------------------*/ | 138 | /*----------------------------- Global variables ----------------------------*/ |
| 136 | 139 | ||
| @@ -1096,7 +1099,21 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active) | |||
| 1096 | if (new_active) { | 1099 | if (new_active) { |
| 1097 | bond_set_slave_active_flags(new_active); | 1100 | bond_set_slave_active_flags(new_active); |
| 1098 | } | 1101 | } |
| 1099 | bond_send_gratuitous_arp(bond); | 1102 | |
| 1103 | /* when bonding does not set the slave MAC address, the bond MAC | ||
| 1104 | * address is the one of the active slave. | ||
| 1105 | */ | ||
| 1106 | if (new_active && bond->params.fail_over_mac) | ||
| 1107 | memcpy(bond->dev->dev_addr, new_active->dev->dev_addr, | ||
| 1108 | new_active->dev->addr_len); | ||
| 1109 | if (bond->curr_active_slave && | ||
| 1110 | test_bit(__LINK_STATE_LINKWATCH_PENDING, | ||
| 1111 | &bond->curr_active_slave->dev->state)) { | ||
| 1112 | dprintk("delaying gratuitous arp on %s\n", | ||
| 1113 | bond->curr_active_slave->dev->name); | ||
| 1114 | bond->send_grat_arp = 1; | ||
| 1115 | } else | ||
| 1116 | bond_send_gratuitous_arp(bond); | ||
| 1100 | } | 1117 | } |
| 1101 | } | 1118 | } |
| 1102 | 1119 | ||
| @@ -1217,7 +1234,8 @@ static int bond_compute_features(struct bonding *bond) | |||
| 1217 | struct slave *slave; | 1234 | struct slave *slave; |
| 1218 | struct net_device *bond_dev = bond->dev; | 1235 | struct net_device *bond_dev = bond->dev; |
| 1219 | unsigned long features = bond_dev->features; | 1236 | unsigned long features = bond_dev->features; |
| 1220 | unsigned short max_hard_header_len = ETH_HLEN; | 1237 | unsigned short max_hard_header_len = max((u16)ETH_HLEN, |
| 1238 | bond_dev->hard_header_len); | ||
| 1221 | int i; | 1239 | int i; |
| 1222 | 1240 | ||
| 1223 | features &= ~(NETIF_F_ALL_CSUM | BOND_VLAN_FEATURES); | 1241 | features &= ~(NETIF_F_ALL_CSUM | BOND_VLAN_FEATURES); |
| @@ -1238,6 +1256,23 @@ static int bond_compute_features(struct bonding *bond) | |||
| 1238 | return 0; | 1256 | return 0; |
| 1239 | } | 1257 | } |
| 1240 | 1258 | ||
| 1259 | |||
| 1260 | static void bond_setup_by_slave(struct net_device *bond_dev, | ||
| 1261 | struct net_device *slave_dev) | ||
| 1262 | { | ||
| 1263 | struct bonding *bond = bond_dev->priv; | ||
| 1264 | |||
| 1265 | bond_dev->neigh_setup = slave_dev->neigh_setup; | ||
| 1266 | |||
| 1267 | bond_dev->type = slave_dev->type; | ||
| 1268 | bond_dev->hard_header_len = slave_dev->hard_header_len; | ||
| 1269 | bond_dev->addr_len = slave_dev->addr_len; | ||
| 1270 | |||
| 1271 | memcpy(bond_dev->broadcast, slave_dev->broadcast, | ||
| 1272 | slave_dev->addr_len); | ||
| 1273 | bond->setup_by_slave = 1; | ||
| 1274 | } | ||
| 1275 | |||
| 1241 | /* enslave device <slave> to bond device <master> */ | 1276 | /* enslave device <slave> to bond device <master> */ |
| 1242 | int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) | 1277 | int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) |
| 1243 | { | 1278 | { |
| @@ -1258,8 +1293,9 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) | |||
| 1258 | 1293 | ||
| 1259 | /* bond must be initialized by bond_open() before enslaving */ | 1294 | /* bond must be initialized by bond_open() before enslaving */ |
| 1260 | if (!(bond_dev->flags & IFF_UP)) { | 1295 | if (!(bond_dev->flags & IFF_UP)) { |
| 1261 | dprintk("Error, master_dev is not up\n"); | 1296 | printk(KERN_WARNING DRV_NAME |
| 1262 | return -EPERM; | 1297 | " %s: master_dev is not up in bond_enslave\n", |
| 1298 | bond_dev->name); | ||
| 1263 | } | 1299 | } |
| 1264 | 1300 | ||
| 1265 | /* already enslaved */ | 1301 | /* already enslaved */ |
| @@ -1312,14 +1348,42 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) | |||
| 1312 | goto err_undo_flags; | 1348 | goto err_undo_flags; |
| 1313 | } | 1349 | } |
| 1314 | 1350 | ||
| 1351 | /* set bonding device ether type by slave - bonding netdevices are | ||
| 1352 | * created with ether_setup, so when the slave type is not ARPHRD_ETHER | ||
| 1353 | * there is a need to override some of the type dependent attribs/funcs. | ||
| 1354 | * | ||
| 1355 | * bond ether type mutual exclusion - don't allow slaves of dissimilar | ||
| 1356 | * ether type (eg ARPHRD_ETHER and ARPHRD_INFINIBAND) share the same bond | ||
| 1357 | */ | ||
| 1358 | if (bond->slave_cnt == 0) { | ||
| 1359 | if (slave_dev->type != ARPHRD_ETHER) | ||
| 1360 | bond_setup_by_slave(bond_dev, slave_dev); | ||
| 1361 | } else if (bond_dev->type != slave_dev->type) { | ||
| 1362 | printk(KERN_ERR DRV_NAME ": %s ether type (%d) is different " | ||
| 1363 | "from other slaves (%d), can not enslave it.\n", | ||
| 1364 | slave_dev->name, | ||
| 1365 | slave_dev->type, bond_dev->type); | ||
| 1366 | res = -EINVAL; | ||
| 1367 | goto err_undo_flags; | ||
| 1368 | } | ||
| 1369 | |||
| 1315 | if (slave_dev->set_mac_address == NULL) { | 1370 | if (slave_dev->set_mac_address == NULL) { |
| 1316 | printk(KERN_ERR DRV_NAME | 1371 | if (bond->slave_cnt == 0) { |
| 1317 | ": %s: Error: The slave device you specified does " | 1372 | printk(KERN_WARNING DRV_NAME |
| 1318 | "not support setting the MAC address. " | 1373 | ": %s: Warning: The first slave device " |
| 1319 | "Your kernel likely does not support slave " | 1374 | "specified does not support setting the MAC " |
| 1320 | "devices.\n", bond_dev->name); | 1375 | "address. Enabling the fail_over_mac option.", |
| 1321 | res = -EOPNOTSUPP; | 1376 | bond_dev->name); |
| 1322 | goto err_undo_flags; | 1377 | bond->params.fail_over_mac = 1; |
| 1378 | } else if (!bond->params.fail_over_mac) { | ||
| 1379 | printk(KERN_ERR DRV_NAME | ||
| 1380 | ": %s: Error: The slave device specified " | ||
| 1381 | "does not support setting the MAC address, " | ||
| 1382 | "but fail_over_mac is not enabled.\n" | ||
| 1383 | , bond_dev->name); | ||
| 1384 | res = -EOPNOTSUPP; | ||
| 1385 | goto err_undo_flags; | ||
| 1386 | } | ||
| 1323 | } | 1387 | } |
| 1324 | 1388 | ||
| 1325 | new_slave = kzalloc(sizeof(struct slave), GFP_KERNEL); | 1389 | new_slave = kzalloc(sizeof(struct slave), GFP_KERNEL); |
| @@ -1340,16 +1404,18 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) | |||
| 1340 | */ | 1404 | */ |
| 1341 | memcpy(new_slave->perm_hwaddr, slave_dev->dev_addr, ETH_ALEN); | 1405 | memcpy(new_slave->perm_hwaddr, slave_dev->dev_addr, ETH_ALEN); |
| 1342 | 1406 | ||
| 1343 | /* | 1407 | if (!bond->params.fail_over_mac) { |
| 1344 | * Set slave to master's mac address. The application already | 1408 | /* |
| 1345 | * set the master's mac address to that of the first slave | 1409 | * Set slave to master's mac address. The application already |
| 1346 | */ | 1410 | * set the master's mac address to that of the first slave |
| 1347 | memcpy(addr.sa_data, bond_dev->dev_addr, bond_dev->addr_len); | 1411 | */ |
| 1348 | addr.sa_family = slave_dev->type; | 1412 | memcpy(addr.sa_data, bond_dev->dev_addr, bond_dev->addr_len); |
| 1349 | res = dev_set_mac_address(slave_dev, &addr); | 1413 | addr.sa_family = slave_dev->type; |
| 1350 | if (res) { | 1414 | res = dev_set_mac_address(slave_dev, &addr); |
| 1351 | dprintk("Error %d calling set_mac_address\n", res); | 1415 | if (res) { |
| 1352 | goto err_free; | 1416 | dprintk("Error %d calling set_mac_address\n", res); |
| 1417 | goto err_free; | ||
| 1418 | } | ||
| 1353 | } | 1419 | } |
| 1354 | 1420 | ||
| 1355 | res = netdev_set_master(slave_dev, bond_dev); | 1421 | res = netdev_set_master(slave_dev, bond_dev); |
| @@ -1574,9 +1640,11 @@ err_close: | |||
| 1574 | dev_close(slave_dev); | 1640 | dev_close(slave_dev); |
| 1575 | 1641 | ||
| 1576 | err_restore_mac: | 1642 | err_restore_mac: |
| 1577 | memcpy(addr.sa_data, new_slave->perm_hwaddr, ETH_ALEN); | 1643 | if (!bond->params.fail_over_mac) { |
| 1578 | addr.sa_family = slave_dev->type; | 1644 | memcpy(addr.sa_data, new_slave->perm_hwaddr, ETH_ALEN); |
| 1579 | dev_set_mac_address(slave_dev, &addr); | 1645 | addr.sa_family = slave_dev->type; |
| 1646 | dev_set_mac_address(slave_dev, &addr); | ||
| 1647 | } | ||
| 1580 | 1648 | ||
| 1581 | err_free: | 1649 | err_free: |
| 1582 | kfree(new_slave); | 1650 | kfree(new_slave); |
| @@ -1749,10 +1817,12 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) | |||
| 1749 | /* close slave before restoring its mac address */ | 1817 | /* close slave before restoring its mac address */ |
| 1750 | dev_close(slave_dev); | 1818 | dev_close(slave_dev); |
| 1751 | 1819 | ||
| 1752 | /* restore original ("permanent") mac address */ | 1820 | if (!bond->params.fail_over_mac) { |
| 1753 | memcpy(addr.sa_data, slave->perm_hwaddr, ETH_ALEN); | 1821 | /* restore original ("permanent") mac address */ |
| 1754 | addr.sa_family = slave_dev->type; | 1822 | memcpy(addr.sa_data, slave->perm_hwaddr, ETH_ALEN); |
| 1755 | dev_set_mac_address(slave_dev, &addr); | 1823 | addr.sa_family = slave_dev->type; |
| 1824 | dev_set_mac_address(slave_dev, &addr); | ||
| 1825 | } | ||
| 1756 | 1826 | ||
| 1757 | slave_dev->priv_flags &= ~(IFF_MASTER_8023AD | IFF_MASTER_ALB | | 1827 | slave_dev->priv_flags &= ~(IFF_MASTER_8023AD | IFF_MASTER_ALB | |
| 1758 | IFF_SLAVE_INACTIVE | IFF_BONDING | | 1828 | IFF_SLAVE_INACTIVE | IFF_BONDING | |
| @@ -1764,6 +1834,35 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) | |||
| 1764 | } | 1834 | } |
| 1765 | 1835 | ||
| 1766 | /* | 1836 | /* |
| 1837 | * Destroy a bonding device. | ||
| 1838 | * Must be under rtnl_lock when this function is called. | ||
| 1839 | */ | ||
| 1840 | void bond_destroy(struct bonding *bond) | ||
| 1841 | { | ||
| 1842 | bond_deinit(bond->dev); | ||
| 1843 | bond_destroy_sysfs_entry(bond); | ||
| 1844 | unregister_netdevice(bond->dev); | ||
| 1845 | } | ||
| 1846 | |||
| 1847 | /* | ||
| 1848 | * First release a slave and than destroy the bond if no more slaves iare left. | ||
| 1849 | * Must be under rtnl_lock when this function is called. | ||
| 1850 | */ | ||
| 1851 | int bond_release_and_destroy(struct net_device *bond_dev, struct net_device *slave_dev) | ||
| 1852 | { | ||
| 1853 | struct bonding *bond = bond_dev->priv; | ||
| 1854 | int ret; | ||
| 1855 | |||
| 1856 | ret = bond_release(bond_dev, slave_dev); | ||
| 1857 | if ((ret == 0) && (bond->slave_cnt == 0)) { | ||
| 1858 | printk(KERN_INFO DRV_NAME ": %s: destroying bond %s.\n", | ||
| 1859 | bond_dev->name, bond_dev->name); | ||
| 1860 | bond_destroy(bond); | ||
| 1861 | } | ||
| 1862 | return ret; | ||
| 1863 | } | ||
| 1864 | |||
| 1865 | /* | ||
| 1767 | * This function releases all slaves. | 1866 | * This function releases all slaves. |
| 1768 | */ | 1867 | */ |
| 1769 | static int bond_release_all(struct net_device *bond_dev) | 1868 | static int bond_release_all(struct net_device *bond_dev) |
| @@ -1839,10 +1938,12 @@ static int bond_release_all(struct net_device *bond_dev) | |||
| 1839 | /* close slave before restoring its mac address */ | 1938 | /* close slave before restoring its mac address */ |
| 1840 | dev_close(slave_dev); | 1939 | dev_close(slave_dev); |
| 1841 | 1940 | ||
| 1842 | /* restore original ("permanent") mac address*/ | 1941 | if (!bond->params.fail_over_mac) { |
| 1843 | memcpy(addr.sa_data, slave->perm_hwaddr, ETH_ALEN); | 1942 | /* restore original ("permanent") mac address*/ |
| 1844 | addr.sa_family = slave_dev->type; | 1943 | memcpy(addr.sa_data, slave->perm_hwaddr, ETH_ALEN); |
| 1845 | dev_set_mac_address(slave_dev, &addr); | 1944 | addr.sa_family = slave_dev->type; |
| 1945 | dev_set_mac_address(slave_dev, &addr); | ||
| 1946 | } | ||
| 1846 | 1947 | ||
| 1847 | slave_dev->priv_flags &= ~(IFF_MASTER_8023AD | IFF_MASTER_ALB | | 1948 | slave_dev->priv_flags &= ~(IFF_MASTER_8023AD | IFF_MASTER_ALB | |
| 1848 | IFF_SLAVE_INACTIVE); | 1949 | IFF_SLAVE_INACTIVE); |
| @@ -2013,6 +2114,17 @@ void bond_mii_monitor(struct net_device *bond_dev) | |||
| 2013 | * program could monitor the link itself if needed. | 2114 | * program could monitor the link itself if needed. |
| 2014 | */ | 2115 | */ |
| 2015 | 2116 | ||
| 2117 | if (bond->send_grat_arp) { | ||
| 2118 | if (bond->curr_active_slave && test_bit(__LINK_STATE_LINKWATCH_PENDING, | ||
| 2119 | &bond->curr_active_slave->dev->state)) | ||
| 2120 | dprintk("Needs to send gratuitous arp but not yet\n"); | ||
| 2121 | else { | ||
| 2122 | dprintk("sending delayed gratuitous arp on on %s\n", | ||
| 2123 | bond->curr_active_slave->dev->name); | ||
| 2124 | bond_send_gratuitous_arp(bond); | ||
| 2125 | bond->send_grat_arp = 0; | ||
| 2126 | } | ||
| 2127 | } | ||
| 2016 | read_lock(&bond->curr_slave_lock); | 2128 | read_lock(&bond->curr_slave_lock); |
| 2017 | oldcurrent = bond->curr_active_slave; | 2129 | oldcurrent = bond->curr_active_slave; |
| 2018 | read_unlock(&bond->curr_slave_lock); | 2130 | read_unlock(&bond->curr_slave_lock); |
| @@ -2414,7 +2526,7 @@ static void bond_send_gratuitous_arp(struct bonding *bond) | |||
| 2414 | 2526 | ||
| 2415 | if (bond->master_ip) { | 2527 | if (bond->master_ip) { |
| 2416 | bond_arp_send(slave->dev, ARPOP_REPLY, bond->master_ip, | 2528 | bond_arp_send(slave->dev, ARPOP_REPLY, bond->master_ip, |
| 2417 | bond->master_ip, 0); | 2529 | bond->master_ip, 0); |
| 2418 | } | 2530 | } |
| 2419 | 2531 | ||
| 2420 | list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { | 2532 | list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { |
| @@ -2951,9 +3063,15 @@ static void bond_info_show_master(struct seq_file *seq) | |||
| 2951 | curr = bond->curr_active_slave; | 3063 | curr = bond->curr_active_slave; |
| 2952 | read_unlock(&bond->curr_slave_lock); | 3064 | read_unlock(&bond->curr_slave_lock); |
| 2953 | 3065 | ||
| 2954 | seq_printf(seq, "Bonding Mode: %s\n", | 3066 | seq_printf(seq, "Bonding Mode: %s", |
| 2955 | bond_mode_name(bond->params.mode)); | 3067 | bond_mode_name(bond->params.mode)); |
| 2956 | 3068 | ||
| 3069 | if (bond->params.mode == BOND_MODE_ACTIVEBACKUP && | ||
| 3070 | bond->params.fail_over_mac) | ||
| 3071 | seq_printf(seq, " (fail_over_mac)"); | ||
| 3072 | |||
| 3073 | seq_printf(seq, "\n"); | ||
| 3074 | |||
| 2957 | if (bond->params.mode == BOND_MODE_XOR || | 3075 | if (bond->params.mode == BOND_MODE_XOR || |
| 2958 | bond->params.mode == BOND_MODE_8023AD) { | 3076 | bond->params.mode == BOND_MODE_8023AD) { |
| 2959 | seq_printf(seq, "Transmit Hash Policy: %s (%d)\n", | 3077 | seq_printf(seq, "Transmit Hash Policy: %s (%d)\n", |
| @@ -3248,6 +3366,11 @@ static int bond_slave_netdev_event(unsigned long event, struct net_device *slave | |||
| 3248 | * ... Or is it this? | 3366 | * ... Or is it this? |
| 3249 | */ | 3367 | */ |
| 3250 | break; | 3368 | break; |
| 3369 | case NETDEV_GOING_DOWN: | ||
| 3370 | dprintk("slave %s is going down\n", slave_dev->name); | ||
| 3371 | if (bond->setup_by_slave) | ||
| 3372 | bond_release_and_destroy(bond_dev, slave_dev); | ||
| 3373 | break; | ||
| 3251 | case NETDEV_CHANGEMTU: | 3374 | case NETDEV_CHANGEMTU: |
| 3252 | /* | 3375 | /* |
| 3253 | * TODO: Should slaves be allowed to | 3376 | * TODO: Should slaves be allowed to |
| @@ -3880,6 +4003,13 @@ static int bond_set_mac_address(struct net_device *bond_dev, void *addr) | |||
| 3880 | 4003 | ||
| 3881 | dprintk("bond=%p, name=%s\n", bond, (bond_dev ? bond_dev->name : "None")); | 4004 | dprintk("bond=%p, name=%s\n", bond, (bond_dev ? bond_dev->name : "None")); |
| 3882 | 4005 | ||
| 4006 | /* | ||
| 4007 | * If fail_over_mac is enabled, do nothing and return success. | ||
| 4008 | * Returning an error causes ifenslave to fail. | ||
| 4009 | */ | ||
| 4010 | if (bond->params.fail_over_mac) | ||
| 4011 | return 0; | ||
| 4012 | |||
| 3883 | if (!is_valid_ether_addr(sa->sa_data)) { | 4013 | if (!is_valid_ether_addr(sa->sa_data)) { |
| 3884 | return -EADDRNOTAVAIL; | 4014 | return -EADDRNOTAVAIL; |
| 3885 | } | 4015 | } |
| @@ -4217,6 +4347,8 @@ static int bond_init(struct net_device *bond_dev, struct bond_params *params) | |||
| 4217 | bond->current_arp_slave = NULL; | 4347 | bond->current_arp_slave = NULL; |
| 4218 | bond->primary_slave = NULL; | 4348 | bond->primary_slave = NULL; |
| 4219 | bond->dev = bond_dev; | 4349 | bond->dev = bond_dev; |
| 4350 | bond->send_grat_arp = 0; | ||
| 4351 | bond->setup_by_slave = 0; | ||
| 4220 | INIT_LIST_HEAD(&bond->vlan_list); | 4352 | INIT_LIST_HEAD(&bond->vlan_list); |
| 4221 | 4353 | ||
| 4222 | /* Initialize the device entry points */ | 4354 | /* Initialize the device entry points */ |
| @@ -4265,7 +4397,6 @@ static int bond_init(struct net_device *bond_dev, struct bond_params *params) | |||
| 4265 | #ifdef CONFIG_PROC_FS | 4397 | #ifdef CONFIG_PROC_FS |
| 4266 | bond_create_proc_entry(bond); | 4398 | bond_create_proc_entry(bond); |
| 4267 | #endif | 4399 | #endif |
| 4268 | |||
| 4269 | list_add_tail(&bond->bond_list, &bond_dev_list); | 4400 | list_add_tail(&bond->bond_list, &bond_dev_list); |
| 4270 | 4401 | ||
| 4271 | return 0; | 4402 | return 0; |
| @@ -4599,6 +4730,11 @@ static int bond_check_params(struct bond_params *params) | |||
| 4599 | primary = NULL; | 4730 | primary = NULL; |
| 4600 | } | 4731 | } |
| 4601 | 4732 | ||
| 4733 | if (fail_over_mac && (bond_mode != BOND_MODE_ACTIVEBACKUP)) | ||
| 4734 | printk(KERN_WARNING DRV_NAME | ||
| 4735 | ": Warning: fail_over_mac only affects " | ||
| 4736 | "active-backup mode.\n"); | ||
| 4737 | |||
| 4602 | /* fill params struct with the proper values */ | 4738 | /* fill params struct with the proper values */ |
| 4603 | params->mode = bond_mode; | 4739 | params->mode = bond_mode; |
| 4604 | params->xmit_policy = xmit_hashtype; | 4740 | params->xmit_policy = xmit_hashtype; |
| @@ -4610,6 +4746,7 @@ static int bond_check_params(struct bond_params *params) | |||
| 4610 | params->use_carrier = use_carrier; | 4746 | params->use_carrier = use_carrier; |
| 4611 | params->lacp_fast = lacp_fast; | 4747 | params->lacp_fast = lacp_fast; |
| 4612 | params->primary[0] = 0; | 4748 | params->primary[0] = 0; |
| 4749 | params->fail_over_mac = fail_over_mac; | ||
| 4613 | 4750 | ||
| 4614 | if (primary) { | 4751 | if (primary) { |
| 4615 | strncpy(params->primary, primary, IFNAMSIZ); | 4752 | strncpy(params->primary, primary, IFNAMSIZ); |
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index 6f49ca7e9b66..80c0c8c415ed 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c | |||
| @@ -164,9 +164,7 @@ static ssize_t bonding_store_bonds(struct class *cls, const char *buffer, size_t | |||
| 164 | printk(KERN_INFO DRV_NAME | 164 | printk(KERN_INFO DRV_NAME |
| 165 | ": %s is being deleted...\n", | 165 | ": %s is being deleted...\n", |
| 166 | bond->dev->name); | 166 | bond->dev->name); |
| 167 | bond_deinit(bond->dev); | 167 | bond_destroy(bond); |
| 168 | bond_destroy_sysfs_entry(bond); | ||
| 169 | unregister_netdevice(bond->dev); | ||
| 170 | rtnl_unlock(); | 168 | rtnl_unlock(); |
| 171 | goto out; | 169 | goto out; |
| 172 | } | 170 | } |
| @@ -260,17 +258,16 @@ static ssize_t bonding_store_slaves(struct device *d, | |||
| 260 | char command[IFNAMSIZ + 1] = { 0, }; | 258 | char command[IFNAMSIZ + 1] = { 0, }; |
| 261 | char *ifname; | 259 | char *ifname; |
| 262 | int i, res, found, ret = count; | 260 | int i, res, found, ret = count; |
| 261 | u32 original_mtu; | ||
| 263 | struct slave *slave; | 262 | struct slave *slave; |
| 264 | struct net_device *dev = NULL; | 263 | struct net_device *dev = NULL; |
| 265 | struct bonding *bond = to_bond(d); | 264 | struct bonding *bond = to_bond(d); |
| 266 | 265 | ||
| 267 | /* Quick sanity check -- is the bond interface up? */ | 266 | /* Quick sanity check -- is the bond interface up? */ |
| 268 | if (!(bond->dev->flags & IFF_UP)) { | 267 | if (!(bond->dev->flags & IFF_UP)) { |
| 269 | printk(KERN_ERR DRV_NAME | 268 | printk(KERN_WARNING DRV_NAME |
| 270 | ": %s: Unable to update slaves because interface is down.\n", | 269 | ": %s: doing slave updates when interface is down.\n", |
| 271 | bond->dev->name); | 270 | bond->dev->name); |
| 272 | ret = -EPERM; | ||
| 273 | goto out; | ||
| 274 | } | 271 | } |
| 275 | 272 | ||
| 276 | /* Note: We can't hold bond->lock here, as bond_create grabs it. */ | 273 | /* Note: We can't hold bond->lock here, as bond_create grabs it. */ |
| @@ -327,6 +324,7 @@ static ssize_t bonding_store_slaves(struct device *d, | |||
| 327 | } | 324 | } |
| 328 | 325 | ||
| 329 | /* Set the slave's MTU to match the bond */ | 326 | /* Set the slave's MTU to match the bond */ |
| 327 | original_mtu = dev->mtu; | ||
| 330 | if (dev->mtu != bond->dev->mtu) { | 328 | if (dev->mtu != bond->dev->mtu) { |
| 331 | if (dev->change_mtu) { | 329 | if (dev->change_mtu) { |
| 332 | res = dev->change_mtu(dev, | 330 | res = dev->change_mtu(dev, |
| @@ -341,6 +339,9 @@ static ssize_t bonding_store_slaves(struct device *d, | |||
| 341 | } | 339 | } |
| 342 | rtnl_lock(); | 340 | rtnl_lock(); |
| 343 | res = bond_enslave(bond->dev, dev); | 341 | res = bond_enslave(bond->dev, dev); |
| 342 | bond_for_each_slave(bond, slave, i) | ||
| 343 | if (strnicmp(slave->dev->name, ifname, IFNAMSIZ) == 0) | ||
| 344 | slave->original_mtu = original_mtu; | ||
| 344 | rtnl_unlock(); | 345 | rtnl_unlock(); |
| 345 | if (res) { | 346 | if (res) { |
| 346 | ret = res; | 347 | ret = res; |
| @@ -353,13 +354,17 @@ static ssize_t bonding_store_slaves(struct device *d, | |||
| 353 | bond_for_each_slave(bond, slave, i) | 354 | bond_for_each_slave(bond, slave, i) |
| 354 | if (strnicmp(slave->dev->name, ifname, IFNAMSIZ) == 0) { | 355 | if (strnicmp(slave->dev->name, ifname, IFNAMSIZ) == 0) { |
| 355 | dev = slave->dev; | 356 | dev = slave->dev; |
| 357 | original_mtu = slave->original_mtu; | ||
| 356 | break; | 358 | break; |
| 357 | } | 359 | } |
| 358 | if (dev) { | 360 | if (dev) { |
| 359 | printk(KERN_INFO DRV_NAME ": %s: Removing slave %s\n", | 361 | printk(KERN_INFO DRV_NAME ": %s: Removing slave %s\n", |
| 360 | bond->dev->name, dev->name); | 362 | bond->dev->name, dev->name); |
| 361 | rtnl_lock(); | 363 | rtnl_lock(); |
| 362 | res = bond_release(bond->dev, dev); | 364 | if (bond->setup_by_slave) |
| 365 | res = bond_release_and_destroy(bond->dev, dev); | ||
| 366 | else | ||
| 367 | res = bond_release(bond->dev, dev); | ||
| 363 | rtnl_unlock(); | 368 | rtnl_unlock(); |
| 364 | if (res) { | 369 | if (res) { |
| 365 | ret = res; | 370 | ret = res; |
| @@ -367,9 +372,9 @@ static ssize_t bonding_store_slaves(struct device *d, | |||
| 367 | } | 372 | } |
| 368 | /* set the slave MTU to the default */ | 373 | /* set the slave MTU to the default */ |
| 369 | if (dev->change_mtu) { | 374 | if (dev->change_mtu) { |
| 370 | dev->change_mtu(dev, 1500); | 375 | dev->change_mtu(dev, original_mtu); |
| 371 | } else { | 376 | } else { |
| 372 | dev->mtu = 1500; | 377 | dev->mtu = original_mtu; |
| 373 | } | 378 | } |
| 374 | } | 379 | } |
| 375 | else { | 380 | else { |
| @@ -563,6 +568,54 @@ static ssize_t bonding_store_arp_validate(struct device *d, | |||
| 563 | static DEVICE_ATTR(arp_validate, S_IRUGO | S_IWUSR, bonding_show_arp_validate, bonding_store_arp_validate); | 568 | static DEVICE_ATTR(arp_validate, S_IRUGO | S_IWUSR, bonding_show_arp_validate, bonding_store_arp_validate); |
| 564 | 569 | ||
| 565 | /* | 570 | /* |
| 571 | * Show and store fail_over_mac. User only allowed to change the | ||
| 572 | * value when there are no slaves. | ||
| 573 | */ | ||
| 574 | static ssize_t bonding_show_fail_over_mac(struct device *d, struct device_attribute *attr, char *buf) | ||
| 575 | { | ||
| 576 | struct bonding *bond = to_bond(d); | ||
| 577 | |||
| 578 | return sprintf(buf, "%d\n", bond->params.fail_over_mac) + 1; | ||
| 579 | } | ||
| 580 | |||
| 581 | static ssize_t bonding_store_fail_over_mac(struct device *d, struct device_attribute *attr, const char *buf, size_t count) | ||
| 582 | { | ||
| 583 | int new_value; | ||
| 584 | int ret = count; | ||
| 585 | struct bonding *bond = to_bond(d); | ||
| 586 | |||
| 587 | if (bond->slave_cnt != 0) { | ||
| 588 | printk(KERN_ERR DRV_NAME | ||
| 589 | ": %s: Can't alter fail_over_mac with slaves in bond.\n", | ||
| 590 | bond->dev->name); | ||
| 591 | ret = -EPERM; | ||
| 592 | goto out; | ||
| 593 | } | ||
| 594 | |||
| 595 | if (sscanf(buf, "%d", &new_value) != 1) { | ||
| 596 | printk(KERN_ERR DRV_NAME | ||
| 597 | ": %s: no fail_over_mac value specified.\n", | ||
| 598 | bond->dev->name); | ||
| 599 | ret = -EINVAL; | ||
| 600 | goto out; | ||
| 601 | } | ||
| 602 | |||
| 603 | if ((new_value == 0) || (new_value == 1)) { | ||
| 604 | bond->params.fail_over_mac = new_value; | ||
| 605 | printk(KERN_INFO DRV_NAME ": %s: Setting fail_over_mac to %d.\n", | ||
| 606 | bond->dev->name, new_value); | ||
| 607 | } else { | ||
| 608 | printk(KERN_INFO DRV_NAME | ||
| 609 | ": %s: Ignoring invalid fail_over_mac value %d.\n", | ||
| 610 | bond->dev->name, new_value); | ||
| 611 | } | ||
| 612 | out: | ||
| 613 | return ret; | ||
| 614 | } | ||
| 615 | |||
| 616 | static DEVICE_ATTR(fail_over_mac, S_IRUGO | S_IWUSR, bonding_show_fail_over_mac, bonding_store_fail_over_mac); | ||
| 617 | |||
| 618 | /* | ||
| 566 | * Show and set the arp timer interval. There are two tricky bits | 619 | * Show and set the arp timer interval. There are two tricky bits |
| 567 | * here. First, if ARP monitoring is activated, then we must disable | 620 | * here. First, if ARP monitoring is activated, then we must disable |
| 568 | * MII monitoring. Second, if the ARP timer isn't running, we must | 621 | * MII monitoring. Second, if the ARP timer isn't running, we must |
| @@ -1383,6 +1436,7 @@ static DEVICE_ATTR(ad_partner_mac, S_IRUGO, bonding_show_ad_partner_mac, NULL); | |||
| 1383 | static struct attribute *per_bond_attrs[] = { | 1436 | static struct attribute *per_bond_attrs[] = { |
| 1384 | &dev_attr_slaves.attr, | 1437 | &dev_attr_slaves.attr, |
| 1385 | &dev_attr_mode.attr, | 1438 | &dev_attr_mode.attr, |
| 1439 | &dev_attr_fail_over_mac.attr, | ||
| 1386 | &dev_attr_arp_validate.attr, | 1440 | &dev_attr_arp_validate.attr, |
| 1387 | &dev_attr_arp_interval.attr, | 1441 | &dev_attr_arp_interval.attr, |
| 1388 | &dev_attr_arp_ip_target.attr, | 1442 | &dev_attr_arp_ip_target.attr, |
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index 2a6af7d23728..a8bbd563265c 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h | |||
| @@ -22,8 +22,8 @@ | |||
| 22 | #include "bond_3ad.h" | 22 | #include "bond_3ad.h" |
| 23 | #include "bond_alb.h" | 23 | #include "bond_alb.h" |
| 24 | 24 | ||
| 25 | #define DRV_VERSION "3.1.3" | 25 | #define DRV_VERSION "3.2.0" |
| 26 | #define DRV_RELDATE "June 13, 2007" | 26 | #define DRV_RELDATE "September 13, 2007" |
| 27 | #define DRV_NAME "bonding" | 27 | #define DRV_NAME "bonding" |
| 28 | #define DRV_DESCRIPTION "Ethernet Channel Bonding Driver" | 28 | #define DRV_DESCRIPTION "Ethernet Channel Bonding Driver" |
| 29 | 29 | ||
| @@ -128,6 +128,7 @@ struct bond_params { | |||
| 128 | int arp_interval; | 128 | int arp_interval; |
| 129 | int arp_validate; | 129 | int arp_validate; |
| 130 | int use_carrier; | 130 | int use_carrier; |
| 131 | int fail_over_mac; | ||
| 131 | int updelay; | 132 | int updelay; |
| 132 | int downdelay; | 133 | int downdelay; |
| 133 | int lacp_fast; | 134 | int lacp_fast; |
| @@ -156,6 +157,7 @@ struct slave { | |||
| 156 | s8 link; /* one of BOND_LINK_XXXX */ | 157 | s8 link; /* one of BOND_LINK_XXXX */ |
| 157 | s8 state; /* one of BOND_STATE_XXXX */ | 158 | s8 state; /* one of BOND_STATE_XXXX */ |
| 158 | u32 original_flags; | 159 | u32 original_flags; |
| 160 | u32 original_mtu; | ||
| 159 | u32 link_failure_count; | 161 | u32 link_failure_count; |
| 160 | u16 speed; | 162 | u16 speed; |
| 161 | u8 duplex; | 163 | u8 duplex; |
| @@ -185,6 +187,8 @@ struct bonding { | |||
| 185 | struct timer_list mii_timer; | 187 | struct timer_list mii_timer; |
| 186 | struct timer_list arp_timer; | 188 | struct timer_list arp_timer; |
| 187 | s8 kill_timers; | 189 | s8 kill_timers; |
| 190 | s8 send_grat_arp; | ||
| 191 | s8 setup_by_slave; | ||
| 188 | struct net_device_stats stats; | 192 | struct net_device_stats stats; |
| 189 | #ifdef CONFIG_PROC_FS | 193 | #ifdef CONFIG_PROC_FS |
| 190 | struct proc_dir_entry *proc_entry; | 194 | struct proc_dir_entry *proc_entry; |
| @@ -292,6 +296,8 @@ static inline void bond_unset_master_alb_flags(struct bonding *bond) | |||
| 292 | struct vlan_entry *bond_next_vlan(struct bonding *bond, struct vlan_entry *curr); | 296 | struct vlan_entry *bond_next_vlan(struct bonding *bond, struct vlan_entry *curr); |
| 293 | int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, struct net_device *slave_dev); | 297 | int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, struct net_device *slave_dev); |
| 294 | int bond_create(char *name, struct bond_params *params, struct bonding **newbond); | 298 | int bond_create(char *name, struct bond_params *params, struct bonding **newbond); |
| 299 | void bond_destroy(struct bonding *bond); | ||
| 300 | int bond_release_and_destroy(struct net_device *bond_dev, struct net_device *slave_dev); | ||
| 295 | void bond_deinit(struct net_device *bond_dev); | 301 | void bond_deinit(struct net_device *bond_dev); |
| 296 | int bond_create_sysfs(void); | 302 | int bond_create_sysfs(void); |
| 297 | void bond_destroy_sysfs(void); | 303 | void bond_destroy_sysfs(void); |
diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c index 563bf5f6fa2a..7df31b5561cc 100644 --- a/drivers/net/cassini.c +++ b/drivers/net/cassini.c | |||
| @@ -4443,7 +4443,7 @@ static struct { | |||
| 4443 | {REG_MAC_COLL_EXCESS}, | 4443 | {REG_MAC_COLL_EXCESS}, |
| 4444 | {REG_MAC_COLL_LATE} | 4444 | {REG_MAC_COLL_LATE} |
| 4445 | }; | 4445 | }; |
| 4446 | #define CAS_REG_LEN (sizeof(ethtool_register_table)/sizeof(int)) | 4446 | #define CAS_REG_LEN ARRAY_SIZE(ethtool_register_table) |
| 4447 | #define CAS_MAX_REGS (sizeof (u32)*CAS_REG_LEN) | 4447 | #define CAS_MAX_REGS (sizeof (u32)*CAS_REG_LEN) |
| 4448 | 4448 | ||
| 4449 | static void cas_read_regs(struct cas *cp, u8 *ptr, int len) | 4449 | static void cas_read_regs(struct cas *cp, u8 *ptr, int len) |
diff --git a/drivers/net/cpmac.c b/drivers/net/cpmac.c new file mode 100644 index 000000000000..ed53aaab4c02 --- /dev/null +++ b/drivers/net/cpmac.c | |||
| @@ -0,0 +1,1174 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2006, 2007 Eugene Konev | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License as published by | ||
| 6 | * the Free Software Foundation; either version 2 of the License, or | ||
| 7 | * (at your option) any later version. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License | ||
| 15 | * along with this program; if not, write to the Free Software | ||
| 16 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 17 | */ | ||
| 18 | |||
| 19 | #include <linux/module.h> | ||
| 20 | #include <linux/init.h> | ||
| 21 | #include <linux/moduleparam.h> | ||
| 22 | |||
| 23 | #include <linux/sched.h> | ||
| 24 | #include <linux/kernel.h> | ||
| 25 | #include <linux/slab.h> | ||
| 26 | #include <linux/errno.h> | ||
| 27 | #include <linux/types.h> | ||
| 28 | #include <linux/delay.h> | ||
| 29 | #include <linux/version.h> | ||
| 30 | |||
| 31 | #include <linux/netdevice.h> | ||
| 32 | #include <linux/etherdevice.h> | ||
| 33 | #include <linux/ethtool.h> | ||
| 34 | #include <linux/skbuff.h> | ||
| 35 | #include <linux/mii.h> | ||
| 36 | #include <linux/phy.h> | ||
| 37 | #include <linux/platform_device.h> | ||
| 38 | #include <linux/dma-mapping.h> | ||
| 39 | #include <asm/gpio.h> | ||
| 40 | |||
| 41 | MODULE_AUTHOR("Eugene Konev <ejka@imfi.kspu.ru>"); | ||
| 42 | MODULE_DESCRIPTION("TI AR7 ethernet driver (CPMAC)"); | ||
| 43 | MODULE_LICENSE("GPL"); | ||
| 44 | |||
| 45 | static int debug_level = 8; | ||
| 46 | static int dumb_switch; | ||
| 47 | |||
| 48 | /* Next 2 are only used in cpmac_probe, so it's pointless to change them */ | ||
| 49 | module_param(debug_level, int, 0444); | ||
| 50 | module_param(dumb_switch, int, 0444); | ||
| 51 | |||
| 52 | MODULE_PARM_DESC(debug_level, "Number of NETIF_MSG bits to enable"); | ||
| 53 | MODULE_PARM_DESC(dumb_switch, "Assume switch is not connected to MDIO bus"); | ||
| 54 | |||
| 55 | #define CPMAC_VERSION "0.5.0" | ||
| 56 | /* stolen from net/ieee80211.h */ | ||
| 57 | #ifndef MAC_FMT | ||
| 58 | #define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x" | ||
| 59 | #define MAC_ARG(x) ((u8*)(x))[0], ((u8*)(x))[1], ((u8*)(x))[2], \ | ||
| 60 | ((u8*)(x))[3], ((u8*)(x))[4], ((u8*)(x))[5] | ||
| 61 | #endif | ||
| 62 | /* frame size + 802.1q tag */ | ||
| 63 | #define CPMAC_SKB_SIZE (ETH_FRAME_LEN + 4) | ||
| 64 | #define CPMAC_QUEUES 8 | ||
| 65 | |||
| 66 | /* Ethernet registers */ | ||
| 67 | #define CPMAC_TX_CONTROL 0x0004 | ||
| 68 | #define CPMAC_TX_TEARDOWN 0x0008 | ||
| 69 | #define CPMAC_RX_CONTROL 0x0014 | ||
| 70 | #define CPMAC_RX_TEARDOWN 0x0018 | ||
| 71 | #define CPMAC_MBP 0x0100 | ||
| 72 | # define MBP_RXPASSCRC 0x40000000 | ||
| 73 | # define MBP_RXQOS 0x20000000 | ||
| 74 | # define MBP_RXNOCHAIN 0x10000000 | ||
| 75 | # define MBP_RXCMF 0x01000000 | ||
| 76 | # define MBP_RXSHORT 0x00800000 | ||
| 77 | # define MBP_RXCEF 0x00400000 | ||
| 78 | # define MBP_RXPROMISC 0x00200000 | ||
| 79 | # define MBP_PROMISCCHAN(channel) (((channel) & 0x7) << 16) | ||
| 80 | # define MBP_RXBCAST 0x00002000 | ||
| 81 | # define MBP_BCASTCHAN(channel) (((channel) & 0x7) << 8) | ||
| 82 | # define MBP_RXMCAST 0x00000020 | ||
| 83 | # define MBP_MCASTCHAN(channel) ((channel) & 0x7) | ||
| 84 | #define CPMAC_UNICAST_ENABLE 0x0104 | ||
| 85 | #define CPMAC_UNICAST_CLEAR 0x0108 | ||
| 86 | #define CPMAC_MAX_LENGTH 0x010c | ||
| 87 | #define CPMAC_BUFFER_OFFSET 0x0110 | ||
| 88 | #define CPMAC_MAC_CONTROL 0x0160 | ||
| 89 | # define MAC_TXPTYPE 0x00000200 | ||
| 90 | # define MAC_TXPACE 0x00000040 | ||
| 91 | # define MAC_MII 0x00000020 | ||
| 92 | # define MAC_TXFLOW 0x00000010 | ||
| 93 | # define MAC_RXFLOW 0x00000008 | ||
| 94 | # define MAC_MTEST 0x00000004 | ||
| 95 | # define MAC_LOOPBACK 0x00000002 | ||
| 96 | # define MAC_FDX 0x00000001 | ||
| 97 | #define CPMAC_MAC_STATUS 0x0164 | ||
| 98 | # define MAC_STATUS_QOS 0x00000004 | ||
| 99 | # define MAC_STATUS_RXFLOW 0x00000002 | ||
| 100 | # define MAC_STATUS_TXFLOW 0x00000001 | ||
| 101 | #define CPMAC_TX_INT_ENABLE 0x0178 | ||
| 102 | #define CPMAC_TX_INT_CLEAR 0x017c | ||
| 103 | #define CPMAC_MAC_INT_VECTOR 0x0180 | ||
| 104 | # define MAC_INT_STATUS 0x00080000 | ||
| 105 | # define MAC_INT_HOST 0x00040000 | ||
| 106 | # define MAC_INT_RX 0x00020000 | ||
| 107 | # define MAC_INT_TX 0x00010000 | ||
| 108 | #define CPMAC_MAC_EOI_VECTOR 0x0184 | ||
| 109 | #define CPMAC_RX_INT_ENABLE 0x0198 | ||
| 110 | #define CPMAC_RX_INT_CLEAR 0x019c | ||
| 111 | #define CPMAC_MAC_INT_ENABLE 0x01a8 | ||
| 112 | #define CPMAC_MAC_INT_CLEAR 0x01ac | ||
| 113 | #define CPMAC_MAC_ADDR_LO(channel) (0x01b0 + (channel) * 4) | ||
| 114 | #define CPMAC_MAC_ADDR_MID 0x01d0 | ||
| 115 | #define CPMAC_MAC_ADDR_HI 0x01d4 | ||
| 116 | #define CPMAC_MAC_HASH_LO 0x01d8 | ||
| 117 | #define CPMAC_MAC_HASH_HI 0x01dc | ||
| 118 | #define CPMAC_TX_PTR(channel) (0x0600 + (channel) * 4) | ||
| 119 | #define CPMAC_RX_PTR(channel) (0x0620 + (channel) * 4) | ||
| 120 | #define CPMAC_TX_ACK(channel) (0x0640 + (channel) * 4) | ||
| 121 | #define CPMAC_RX_ACK(channel) (0x0660 + (channel) * 4) | ||
| 122 | #define CPMAC_REG_END 0x0680 | ||
| 123 | /* | ||
| 124 | * Rx/Tx statistics | ||
| 125 | * TODO: use some of them to fill stats in cpmac_stats() | ||
| 126 | */ | ||
| 127 | #define CPMAC_STATS_RX_GOOD 0x0200 | ||
| 128 | #define CPMAC_STATS_RX_BCAST 0x0204 | ||
| 129 | #define CPMAC_STATS_RX_MCAST 0x0208 | ||
| 130 | #define CPMAC_STATS_RX_PAUSE 0x020c | ||
| 131 | #define CPMAC_STATS_RX_CRC 0x0210 | ||
| 132 | #define CPMAC_STATS_RX_ALIGN 0x0214 | ||
| 133 | #define CPMAC_STATS_RX_OVER 0x0218 | ||
| 134 | #define CPMAC_STATS_RX_JABBER 0x021c | ||
| 135 | #define CPMAC_STATS_RX_UNDER 0x0220 | ||
| 136 | #define CPMAC_STATS_RX_FRAG 0x0224 | ||
| 137 | #define CPMAC_STATS_RX_FILTER 0x0228 | ||
| 138 | #define CPMAC_STATS_RX_QOSFILTER 0x022c | ||
| 139 | #define CPMAC_STATS_RX_OCTETS 0x0230 | ||
| 140 | |||
| 141 | #define CPMAC_STATS_TX_GOOD 0x0234 | ||
| 142 | #define CPMAC_STATS_TX_BCAST 0x0238 | ||
| 143 | #define CPMAC_STATS_TX_MCAST 0x023c | ||
| 144 | #define CPMAC_STATS_TX_PAUSE 0x0240 | ||
| 145 | #define CPMAC_STATS_TX_DEFER 0x0244 | ||
| 146 | #define CPMAC_STATS_TX_COLLISION 0x0248 | ||
| 147 | #define CPMAC_STATS_TX_SINGLECOLL 0x024c | ||
| 148 | #define CPMAC_STATS_TX_MULTICOLL 0x0250 | ||
| 149 | #define CPMAC_STATS_TX_EXCESSCOLL 0x0254 | ||
| 150 | #define CPMAC_STATS_TX_LATECOLL 0x0258 | ||
| 151 | #define CPMAC_STATS_TX_UNDERRUN 0x025c | ||
| 152 | #define CPMAC_STATS_TX_CARRIERSENSE 0x0260 | ||
| 153 | #define CPMAC_STATS_TX_OCTETS 0x0264 | ||
| 154 | |||
| 155 | #define cpmac_read(base, reg) (readl((void __iomem *)(base) + (reg))) | ||
| 156 | #define cpmac_write(base, reg, val) (writel(val, (void __iomem *)(base) + \ | ||
| 157 | (reg))) | ||
| 158 | |||
| 159 | /* MDIO bus */ | ||
| 160 | #define CPMAC_MDIO_VERSION 0x0000 | ||
| 161 | #define CPMAC_MDIO_CONTROL 0x0004 | ||
| 162 | # define MDIOC_IDLE 0x80000000 | ||
| 163 | # define MDIOC_ENABLE 0x40000000 | ||
| 164 | # define MDIOC_PREAMBLE 0x00100000 | ||
| 165 | # define MDIOC_FAULT 0x00080000 | ||
| 166 | # define MDIOC_FAULTDETECT 0x00040000 | ||
| 167 | # define MDIOC_INTTEST 0x00020000 | ||
| 168 | # define MDIOC_CLKDIV(div) ((div) & 0xff) | ||
| 169 | #define CPMAC_MDIO_ALIVE 0x0008 | ||
| 170 | #define CPMAC_MDIO_LINK 0x000c | ||
| 171 | #define CPMAC_MDIO_ACCESS(channel) (0x0080 + (channel) * 8) | ||
| 172 | # define MDIO_BUSY 0x80000000 | ||
| 173 | # define MDIO_WRITE 0x40000000 | ||
| 174 | # define MDIO_REG(reg) (((reg) & 0x1f) << 21) | ||
| 175 | # define MDIO_PHY(phy) (((phy) & 0x1f) << 16) | ||
| 176 | # define MDIO_DATA(data) ((data) & 0xffff) | ||
| 177 | #define CPMAC_MDIO_PHYSEL(channel) (0x0084 + (channel) * 8) | ||
| 178 | # define PHYSEL_LINKSEL 0x00000040 | ||
| 179 | # define PHYSEL_LINKINT 0x00000020 | ||
| 180 | |||
| 181 | struct cpmac_desc { | ||
| 182 | u32 hw_next; | ||
| 183 | u32 hw_data; | ||
| 184 | u16 buflen; | ||
| 185 | u16 bufflags; | ||
| 186 | u16 datalen; | ||
| 187 | u16 dataflags; | ||
| 188 | #define CPMAC_SOP 0x8000 | ||
| 189 | #define CPMAC_EOP 0x4000 | ||
| 190 | #define CPMAC_OWN 0x2000 | ||
| 191 | #define CPMAC_EOQ 0x1000 | ||
| 192 | struct sk_buff *skb; | ||
| 193 | struct cpmac_desc *next; | ||
| 194 | dma_addr_t mapping; | ||
| 195 | dma_addr_t data_mapping; | ||
| 196 | }; | ||
| 197 | |||
| 198 | struct cpmac_priv { | ||
| 199 | spinlock_t lock; | ||
| 200 | spinlock_t rx_lock; | ||
| 201 | struct cpmac_desc *rx_head; | ||
| 202 | int ring_size; | ||
| 203 | struct cpmac_desc *desc_ring; | ||
| 204 | dma_addr_t dma_ring; | ||
| 205 | void __iomem *regs; | ||
| 206 | struct mii_bus *mii_bus; | ||
| 207 | struct phy_device *phy; | ||
| 208 | char phy_name[BUS_ID_SIZE]; | ||
| 209 | int oldlink, oldspeed, oldduplex; | ||
| 210 | u32 msg_enable; | ||
| 211 | struct net_device *dev; | ||
| 212 | struct work_struct reset_work; | ||
| 213 | struct platform_device *pdev; | ||
| 214 | }; | ||
| 215 | |||
| 216 | static irqreturn_t cpmac_irq(int, void *); | ||
| 217 | static void cpmac_hw_start(struct net_device *dev); | ||
| 218 | static void cpmac_hw_stop(struct net_device *dev); | ||
| 219 | static int cpmac_stop(struct net_device *dev); | ||
| 220 | static int cpmac_open(struct net_device *dev); | ||
| 221 | |||
| 222 | static void cpmac_dump_regs(struct net_device *dev) | ||
| 223 | { | ||
| 224 | int i; | ||
| 225 | struct cpmac_priv *priv = netdev_priv(dev); | ||
| 226 | for (i = 0; i < CPMAC_REG_END; i += 4) { | ||
| 227 | if (i % 16 == 0) { | ||
| 228 | if (i) | ||
| 229 | printk("\n"); | ||
| 230 | printk(KERN_DEBUG "%s: reg[%p]:", dev->name, | ||
| 231 | priv->regs + i); | ||
| 232 | } | ||
| 233 | printk(" %08x", cpmac_read(priv->regs, i)); | ||
| 234 | } | ||
| 235 | printk("\n"); | ||
| 236 | } | ||
| 237 | |||
| 238 | static void cpmac_dump_desc(struct net_device *dev, struct cpmac_desc *desc) | ||
| 239 | { | ||
| 240 | int i; | ||
| 241 | printk(KERN_DEBUG "%s: desc[%p]:", dev->name, desc); | ||
| 242 | for (i = 0; i < sizeof(*desc) / 4; i++) | ||
| 243 | printk(" %08x", ((u32 *)desc)[i]); | ||
| 244 | printk("\n"); | ||
| 245 | } | ||
| 246 | |||
| 247 | static void cpmac_dump_skb(struct net_device *dev, struct sk_buff *skb) | ||
| 248 | { | ||
| 249 | int i; | ||
| 250 | printk(KERN_DEBUG "%s: skb 0x%p, len=%d\n", dev->name, skb, skb->len); | ||
| 251 | for (i = 0; i < skb->len; i++) { | ||
| 252 | if (i % 16 == 0) { | ||
| 253 | if (i) | ||
| 254 | printk("\n"); | ||
| 255 | printk(KERN_DEBUG "%s: data[%p]:", dev->name, | ||
| 256 | skb->data + i); | ||
| 257 | } | ||
| 258 | printk(" %02x", ((u8 *)skb->data)[i]); | ||
| 259 | } | ||
| 260 | printk("\n"); | ||
| 261 | } | ||
| 262 | |||
| 263 | static int cpmac_mdio_read(struct mii_bus *bus, int phy_id, int reg) | ||
| 264 | { | ||
| 265 | u32 val; | ||
| 266 | |||
| 267 | while (cpmac_read(bus->priv, CPMAC_MDIO_ACCESS(0)) & MDIO_BUSY) | ||
| 268 | cpu_relax(); | ||
| 269 | cpmac_write(bus->priv, CPMAC_MDIO_ACCESS(0), MDIO_BUSY | MDIO_REG(reg) | | ||
| 270 | MDIO_PHY(phy_id)); | ||
| 271 | while ((val = cpmac_read(bus->priv, CPMAC_MDIO_ACCESS(0))) & MDIO_BUSY) | ||
| 272 | cpu_relax(); | ||
| 273 | return MDIO_DATA(val); | ||
| 274 | } | ||
| 275 | |||
| 276 | static int cpmac_mdio_write(struct mii_bus *bus, int phy_id, | ||
| 277 | int reg, u16 val) | ||
| 278 | { | ||
| 279 | while (cpmac_read(bus->priv, CPMAC_MDIO_ACCESS(0)) & MDIO_BUSY) | ||
| 280 | cpu_relax(); | ||
| 281 | cpmac_write(bus->priv, CPMAC_MDIO_ACCESS(0), MDIO_BUSY | MDIO_WRITE | | ||
| 282 | MDIO_REG(reg) | MDIO_PHY(phy_id) | MDIO_DATA(val)); | ||
| 283 | return 0; | ||
| 284 | } | ||
| 285 | |||
| 286 | static int cpmac_mdio_reset(struct mii_bus *bus) | ||
| 287 | { | ||
| 288 | ar7_device_reset(AR7_RESET_BIT_MDIO); | ||
| 289 | cpmac_write(bus->priv, CPMAC_MDIO_CONTROL, MDIOC_ENABLE | | ||
| 290 | MDIOC_CLKDIV(ar7_cpmac_freq() / 2200000 - 1)); | ||
| 291 | return 0; | ||
| 292 | } | ||
| 293 | |||
| 294 | static int mii_irqs[PHY_MAX_ADDR] = { PHY_POLL, }; | ||
| 295 | |||
| 296 | static struct mii_bus cpmac_mii = { | ||
| 297 | .name = "cpmac-mii", | ||
| 298 | .read = cpmac_mdio_read, | ||
| 299 | .write = cpmac_mdio_write, | ||
| 300 | .reset = cpmac_mdio_reset, | ||
| 301 | .irq = mii_irqs, | ||
| 302 | }; | ||
| 303 | |||
| 304 | static int cpmac_config(struct net_device *dev, struct ifmap *map) | ||
| 305 | { | ||
| 306 | if (dev->flags & IFF_UP) | ||
| 307 | return -EBUSY; | ||
| 308 | |||
| 309 | /* Don't allow changing the I/O address */ | ||
| 310 | if (map->base_addr != dev->base_addr) | ||
| 311 | return -EOPNOTSUPP; | ||
| 312 | |||
| 313 | /* ignore other fields */ | ||
| 314 | return 0; | ||
| 315 | } | ||
| 316 | |||
| 317 | static void cpmac_set_multicast_list(struct net_device *dev) | ||
| 318 | { | ||
| 319 | struct dev_mc_list *iter; | ||
| 320 | int i; | ||
| 321 | u8 tmp; | ||
| 322 | u32 mbp, bit, hash[2] = { 0, }; | ||
| 323 | struct cpmac_priv *priv = netdev_priv(dev); | ||
| 324 | |||
| 325 | mbp = cpmac_read(priv->regs, CPMAC_MBP); | ||
| 326 | if (dev->flags & IFF_PROMISC) { | ||
| 327 | cpmac_write(priv->regs, CPMAC_MBP, (mbp & ~MBP_PROMISCCHAN(0)) | | ||
| 328 | MBP_RXPROMISC); | ||
| 329 | } else { | ||
| 330 | cpmac_write(priv->regs, CPMAC_MBP, mbp & ~MBP_RXPROMISC); | ||
| 331 | if (dev->flags & IFF_ALLMULTI) { | ||
| 332 | /* enable all multicast mode */ | ||
| 333 | cpmac_write(priv->regs, CPMAC_MAC_HASH_LO, 0xffffffff); | ||
| 334 | cpmac_write(priv->regs, CPMAC_MAC_HASH_HI, 0xffffffff); | ||
| 335 | } else { | ||
| 336 | /* | ||
| 337 | * cpmac uses some strange mac address hashing | ||
| 338 | * (not crc32) | ||
| 339 | */ | ||
| 340 | for (i = 0, iter = dev->mc_list; i < dev->mc_count; | ||
| 341 | i++, iter = iter->next) { | ||
| 342 | bit = 0; | ||
| 343 | tmp = iter->dmi_addr[0]; | ||
| 344 | bit ^= (tmp >> 2) ^ (tmp << 4); | ||
| 345 | tmp = iter->dmi_addr[1]; | ||
| 346 | bit ^= (tmp >> 4) ^ (tmp << 2); | ||
| 347 | tmp = iter->dmi_addr[2]; | ||
| 348 | bit ^= (tmp >> 6) ^ tmp; | ||
| 349 | tmp = iter->dmi_addr[3]; | ||
| 350 | bit ^= (tmp >> 2) ^ (tmp << 4); | ||
| 351 | tmp = iter->dmi_addr[4]; | ||
| 352 | bit ^= (tmp >> 4) ^ (tmp << 2); | ||
| 353 | tmp = iter->dmi_addr[5]; | ||
| 354 | bit ^= (tmp >> 6) ^ tmp; | ||
| 355 | bit &= 0x3f; | ||
| 356 | hash[bit / 32] |= 1 << (bit % 32); | ||
| 357 | } | ||
| 358 | |||
| 359 | cpmac_write(priv->regs, CPMAC_MAC_HASH_LO, hash[0]); | ||
| 360 | cpmac_write(priv->regs, CPMAC_MAC_HASH_HI, hash[1]); | ||
| 361 | } | ||
| 362 | } | ||
| 363 | } | ||
| 364 | |||
| 365 | static struct sk_buff *cpmac_rx_one(struct net_device *dev, | ||
| 366 | struct cpmac_priv *priv, | ||
| 367 | struct cpmac_desc *desc) | ||
| 368 | { | ||
| 369 | struct sk_buff *skb, *result = NULL; | ||
| 370 | |||
| 371 | if (unlikely(netif_msg_hw(priv))) | ||
| 372 | cpmac_dump_desc(dev, desc); | ||
| 373 | cpmac_write(priv->regs, CPMAC_RX_ACK(0), (u32)desc->mapping); | ||
| 374 | if (unlikely(!desc->datalen)) { | ||
| 375 | if (netif_msg_rx_err(priv) && net_ratelimit()) | ||
| 376 | printk(KERN_WARNING "%s: rx: spurious interrupt\n", | ||
| 377 | dev->name); | ||
| 378 | return NULL; | ||
| 379 | } | ||
| 380 | |||
| 381 | skb = netdev_alloc_skb(dev, CPMAC_SKB_SIZE); | ||
| 382 | if (likely(skb)) { | ||
| 383 | skb_reserve(skb, 2); | ||
| 384 | skb_put(desc->skb, desc->datalen); | ||
| 385 | desc->skb->protocol = eth_type_trans(desc->skb, dev); | ||
| 386 | desc->skb->ip_summed = CHECKSUM_NONE; | ||
| 387 | dev->stats.rx_packets++; | ||
| 388 | dev->stats.rx_bytes += desc->datalen; | ||
| 389 | result = desc->skb; | ||
| 390 | dma_unmap_single(&dev->dev, desc->data_mapping, CPMAC_SKB_SIZE, | ||
| 391 | DMA_FROM_DEVICE); | ||
| 392 | desc->skb = skb; | ||
| 393 | desc->data_mapping = dma_map_single(&dev->dev, skb->data, | ||
| 394 | CPMAC_SKB_SIZE, | ||
| 395 | DMA_FROM_DEVICE); | ||
| 396 | desc->hw_data = (u32)desc->data_mapping; | ||
| 397 | if (unlikely(netif_msg_pktdata(priv))) { | ||
| 398 | printk(KERN_DEBUG "%s: received packet:\n", dev->name); | ||
| 399 | cpmac_dump_skb(dev, result); | ||
| 400 | } | ||
| 401 | } else { | ||
| 402 | if (netif_msg_rx_err(priv) && net_ratelimit()) | ||
| 403 | printk(KERN_WARNING | ||
| 404 | "%s: low on skbs, dropping packet\n", dev->name); | ||
| 405 | dev->stats.rx_dropped++; | ||
| 406 | } | ||
| 407 | |||
| 408 | desc->buflen = CPMAC_SKB_SIZE; | ||
| 409 | desc->dataflags = CPMAC_OWN; | ||
| 410 | |||
| 411 | return result; | ||
| 412 | } | ||
| 413 | |||
| 414 | static int cpmac_poll(struct net_device *dev, int *budget) | ||
| 415 | { | ||
| 416 | struct sk_buff *skb; | ||
| 417 | struct cpmac_desc *desc; | ||
| 418 | int received = 0, quota = min(dev->quota, *budget); | ||
| 419 | struct cpmac_priv *priv = netdev_priv(dev); | ||
| 420 | |||
| 421 | spin_lock(&priv->rx_lock); | ||
| 422 | if (unlikely(!priv->rx_head)) { | ||
| 423 | if (netif_msg_rx_err(priv) && net_ratelimit()) | ||
| 424 | printk(KERN_WARNING "%s: rx: polling, but no queue\n", | ||
| 425 | dev->name); | ||
| 426 | netif_rx_complete(dev); | ||
| 427 | return 0; | ||
| 428 | } | ||
| 429 | |||
| 430 | desc = priv->rx_head; | ||
| 431 | while ((received < quota) && ((desc->dataflags & CPMAC_OWN) == 0)) { | ||
| 432 | skb = cpmac_rx_one(dev, priv, desc); | ||
| 433 | if (likely(skb)) { | ||
| 434 | netif_receive_skb(skb); | ||
| 435 | received++; | ||
| 436 | } | ||
| 437 | desc = desc->next; | ||
| 438 | } | ||
| 439 | |||
| 440 | priv->rx_head = desc; | ||
| 441 | spin_unlock(&priv->rx_lock); | ||
| 442 | *budget -= received; | ||
| 443 | dev->quota -= received; | ||
| 444 | if (unlikely(netif_msg_rx_status(priv))) | ||
| 445 | printk(KERN_DEBUG "%s: poll processed %d packets\n", dev->name, | ||
| 446 | received); | ||
| 447 | if (desc->dataflags & CPMAC_OWN) { | ||
| 448 | netif_rx_complete(dev); | ||
| 449 | cpmac_write(priv->regs, CPMAC_RX_PTR(0), (u32)desc->mapping); | ||
| 450 | cpmac_write(priv->regs, CPMAC_RX_INT_ENABLE, 1); | ||
| 451 | return 0; | ||
| 452 | } | ||
| 453 | |||
| 454 | return 1; | ||
| 455 | } | ||
| 456 | |||
| 457 | static int cpmac_start_xmit(struct sk_buff *skb, struct net_device *dev) | ||
| 458 | { | ||
| 459 | int queue, len; | ||
| 460 | struct cpmac_desc *desc; | ||
| 461 | struct cpmac_priv *priv = netdev_priv(dev); | ||
| 462 | |||
| 463 | if (unlikely(skb_padto(skb, ETH_ZLEN))) { | ||
| 464 | if (netif_msg_tx_err(priv) && net_ratelimit()) | ||
| 465 | printk(KERN_WARNING | ||
| 466 | "%s: tx: padding failed, dropping\n", dev->name); | ||
| 467 | spin_lock(&priv->lock); | ||
| 468 | dev->stats.tx_dropped++; | ||
| 469 | spin_unlock(&priv->lock); | ||
| 470 | return -ENOMEM; | ||
| 471 | } | ||
| 472 | |||
| 473 | len = max(skb->len, ETH_ZLEN); | ||
| 474 | queue = skb->queue_mapping; | ||
| 475 | #ifdef CONFIG_NETDEVICES_MULTIQUEUE | ||
| 476 | netif_stop_subqueue(dev, queue); | ||
| 477 | #else | ||
| 478 | netif_stop_queue(dev); | ||
| 479 | #endif | ||
| 480 | |||
| 481 | desc = &priv->desc_ring[queue]; | ||
| 482 | if (unlikely(desc->dataflags & CPMAC_OWN)) { | ||
| 483 | if (netif_msg_tx_err(priv) && net_ratelimit()) | ||
| 484 | printk(KERN_WARNING "%s: tx dma ring full, dropping\n", | ||
| 485 | dev->name); | ||
| 486 | spin_lock(&priv->lock); | ||
| 487 | dev->stats.tx_dropped++; | ||
| 488 | spin_unlock(&priv->lock); | ||
| 489 | dev_kfree_skb_any(skb); | ||
| 490 | return -ENOMEM; | ||
| 491 | } | ||
| 492 | |||
| 493 | spin_lock(&priv->lock); | ||
| 494 | dev->trans_start = jiffies; | ||
| 495 | spin_unlock(&priv->lock); | ||
| 496 | desc->dataflags = CPMAC_SOP | CPMAC_EOP | CPMAC_OWN; | ||
| 497 | desc->skb = skb; | ||
| 498 | desc->data_mapping = dma_map_single(&dev->dev, skb->data, len, | ||
| 499 | DMA_TO_DEVICE); | ||
| 500 | desc->hw_data = (u32)desc->data_mapping; | ||
| 501 | desc->datalen = len; | ||
| 502 | desc->buflen = len; | ||
| 503 | if (unlikely(netif_msg_tx_queued(priv))) | ||
| 504 | printk(KERN_DEBUG "%s: sending 0x%p, len=%d\n", dev->name, skb, | ||
| 505 | skb->len); | ||
| 506 | if (unlikely(netif_msg_hw(priv))) | ||
| 507 | cpmac_dump_desc(dev, desc); | ||
| 508 | if (unlikely(netif_msg_pktdata(priv))) | ||
| 509 | cpmac_dump_skb(dev, skb); | ||
| 510 | cpmac_write(priv->regs, CPMAC_TX_PTR(queue), (u32)desc->mapping); | ||
| 511 | |||
| 512 | return 0; | ||
| 513 | } | ||
| 514 | |||
| 515 | static void cpmac_end_xmit(struct net_device *dev, int queue) | ||
| 516 | { | ||
| 517 | struct cpmac_desc *desc; | ||
| 518 | struct cpmac_priv *priv = netdev_priv(dev); | ||
| 519 | |||
| 520 | desc = &priv->desc_ring[queue]; | ||
| 521 | cpmac_write(priv->regs, CPMAC_TX_ACK(queue), (u32)desc->mapping); | ||
| 522 | if (likely(desc->skb)) { | ||
| 523 | spin_lock(&priv->lock); | ||
| 524 | dev->stats.tx_packets++; | ||
| 525 | dev->stats.tx_bytes += desc->skb->len; | ||
| 526 | spin_unlock(&priv->lock); | ||
| 527 | dma_unmap_single(&dev->dev, desc->data_mapping, desc->skb->len, | ||
| 528 | DMA_TO_DEVICE); | ||
| 529 | |||
| 530 | if (unlikely(netif_msg_tx_done(priv))) | ||
| 531 | printk(KERN_DEBUG "%s: sent 0x%p, len=%d\n", dev->name, | ||
| 532 | desc->skb, desc->skb->len); | ||
| 533 | |||
| 534 | dev_kfree_skb_irq(desc->skb); | ||
| 535 | desc->skb = NULL; | ||
| 536 | #ifdef CONFIG_NETDEVICES_MULTIQUEUE | ||
| 537 | if (netif_subqueue_stopped(dev, queue)) | ||
| 538 | netif_wake_subqueue(dev, queue); | ||
| 539 | #else | ||
| 540 | if (netif_queue_stopped(dev)) | ||
| 541 | netif_wake_queue(dev); | ||
| 542 | #endif | ||
| 543 | } else { | ||
| 544 | if (netif_msg_tx_err(priv) && net_ratelimit()) | ||
| 545 | printk(KERN_WARNING | ||
| 546 | "%s: end_xmit: spurious interrupt\n", dev->name); | ||
| 547 | #ifdef CONFIG_NETDEVICES_MULTIQUEUE | ||
| 548 | if (netif_subqueue_stopped(dev, queue)) | ||
| 549 | netif_wake_subqueue(dev, queue); | ||
| 550 | #else | ||
| 551 | if (netif_queue_stopped(dev)) | ||
| 552 | netif_wake_queue(dev); | ||
| 553 | #endif | ||
| 554 | } | ||
| 555 | } | ||
| 556 | |||
| 557 | static void cpmac_hw_stop(struct net_device *dev) | ||
| 558 | { | ||
| 559 | int i; | ||
| 560 | struct cpmac_priv *priv = netdev_priv(dev); | ||
| 561 | struct plat_cpmac_data *pdata = priv->pdev->dev.platform_data; | ||
| 562 | |||
| 563 | ar7_device_reset(pdata->reset_bit); | ||
| 564 | cpmac_write(priv->regs, CPMAC_RX_CONTROL, | ||
| 565 | cpmac_read(priv->regs, CPMAC_RX_CONTROL) & ~1); | ||
| 566 | cpmac_write(priv->regs, CPMAC_TX_CONTROL, | ||
| 567 | cpmac_read(priv->regs, CPMAC_TX_CONTROL) & ~1); | ||
| 568 | for (i = 0; i < 8; i++) { | ||
| 569 | cpmac_write(priv->regs, CPMAC_TX_PTR(i), 0); | ||
| 570 | cpmac_write(priv->regs, CPMAC_RX_PTR(i), 0); | ||
| 571 | } | ||
| 572 | cpmac_write(priv->regs, CPMAC_UNICAST_CLEAR, 0xff); | ||
| 573 | cpmac_write(priv->regs, CPMAC_RX_INT_CLEAR, 0xff); | ||
| 574 | cpmac_write(priv->regs, CPMAC_TX_INT_CLEAR, 0xff); | ||
| 575 | cpmac_write(priv->regs, CPMAC_MAC_INT_CLEAR, 0xff); | ||
| 576 | cpmac_write(priv->regs, CPMAC_MAC_CONTROL, | ||
| 577 | cpmac_read(priv->regs, CPMAC_MAC_CONTROL) & ~MAC_MII); | ||
| 578 | } | ||
| 579 | |||
| 580 | static void cpmac_hw_start(struct net_device *dev) | ||
| 581 | { | ||
| 582 | int i; | ||
| 583 | struct cpmac_priv *priv = netdev_priv(dev); | ||
| 584 | struct plat_cpmac_data *pdata = priv->pdev->dev.platform_data; | ||
| 585 | |||
| 586 | ar7_device_reset(pdata->reset_bit); | ||
| 587 | for (i = 0; i < 8; i++) { | ||
| 588 | cpmac_write(priv->regs, CPMAC_TX_PTR(i), 0); | ||
| 589 | cpmac_write(priv->regs, CPMAC_RX_PTR(i), 0); | ||
| 590 | } | ||
| 591 | cpmac_write(priv->regs, CPMAC_RX_PTR(0), priv->rx_head->mapping); | ||
| 592 | |||
| 593 | cpmac_write(priv->regs, CPMAC_MBP, MBP_RXSHORT | MBP_RXBCAST | | ||
| 594 | MBP_RXMCAST); | ||
| 595 | cpmac_write(priv->regs, CPMAC_BUFFER_OFFSET, 0); | ||
| 596 | for (i = 0; i < 8; i++) | ||
| 597 | cpmac_write(priv->regs, CPMAC_MAC_ADDR_LO(i), dev->dev_addr[5]); | ||
| 598 | cpmac_write(priv->regs, CPMAC_MAC_ADDR_MID, dev->dev_addr[4]); | ||
| 599 | cpmac_write(priv->regs, CPMAC_MAC_ADDR_HI, dev->dev_addr[0] | | ||
| 600 | (dev->dev_addr[1] << 8) | (dev->dev_addr[2] << 16) | | ||
| 601 | (dev->dev_addr[3] << 24)); | ||
| 602 | cpmac_write(priv->regs, CPMAC_MAX_LENGTH, CPMAC_SKB_SIZE); | ||
| 603 | cpmac_write(priv->regs, CPMAC_UNICAST_CLEAR, 0xff); | ||
| 604 | cpmac_write(priv->regs, CPMAC_RX_INT_CLEAR, 0xff); | ||
| 605 | cpmac_write(priv->regs, CPMAC_TX_INT_CLEAR, 0xff); | ||
| 606 | cpmac_write(priv->regs, CPMAC_MAC_INT_CLEAR, 0xff); | ||
| 607 | cpmac_write(priv->regs, CPMAC_UNICAST_ENABLE, 1); | ||
| 608 | cpmac_write(priv->regs, CPMAC_RX_INT_ENABLE, 1); | ||
| 609 | cpmac_write(priv->regs, CPMAC_TX_INT_ENABLE, 0xff); | ||
| 610 | cpmac_write(priv->regs, CPMAC_MAC_INT_ENABLE, 3); | ||
| 611 | |||
| 612 | cpmac_write(priv->regs, CPMAC_RX_CONTROL, | ||
| 613 | cpmac_read(priv->regs, CPMAC_RX_CONTROL) | 1); | ||
| 614 | cpmac_write(priv->regs, CPMAC_TX_CONTROL, | ||
| 615 | cpmac_read(priv->regs, CPMAC_TX_CONTROL) | 1); | ||
| 616 | cpmac_write(priv->regs, CPMAC_MAC_CONTROL, | ||
| 617 | cpmac_read(priv->regs, CPMAC_MAC_CONTROL) | MAC_MII | | ||
| 618 | MAC_FDX); | ||
| 619 | } | ||
| 620 | |||
| 621 | static void cpmac_clear_rx(struct net_device *dev) | ||
| 622 | { | ||
| 623 | struct cpmac_priv *priv = netdev_priv(dev); | ||
| 624 | struct cpmac_desc *desc; | ||
| 625 | int i; | ||
| 626 | if (unlikely(!priv->rx_head)) | ||
| 627 | return; | ||
| 628 | desc = priv->rx_head; | ||
| 629 | for (i = 0; i < priv->ring_size; i++) { | ||
| 630 | if ((desc->dataflags & CPMAC_OWN) == 0) { | ||
| 631 | if (netif_msg_rx_err(priv) && net_ratelimit()) | ||
| 632 | printk(KERN_WARNING "%s: packet dropped\n", | ||
| 633 | dev->name); | ||
| 634 | if (unlikely(netif_msg_hw(priv))) | ||
| 635 | cpmac_dump_desc(dev, desc); | ||
| 636 | desc->dataflags = CPMAC_OWN; | ||
| 637 | dev->stats.rx_dropped++; | ||
| 638 | } | ||
| 639 | desc = desc->next; | ||
| 640 | } | ||
| 641 | } | ||
| 642 | |||
| 643 | static void cpmac_clear_tx(struct net_device *dev) | ||
| 644 | { | ||
| 645 | struct cpmac_priv *priv = netdev_priv(dev); | ||
| 646 | int i; | ||
| 647 | if (unlikely(!priv->desc_ring)) | ||
| 648 | return; | ||
| 649 | for (i = 0; i < CPMAC_QUEUES; i++) | ||
| 650 | if (priv->desc_ring[i].skb) { | ||
| 651 | dev_kfree_skb_any(priv->desc_ring[i].skb); | ||
| 652 | if (netif_subqueue_stopped(dev, i)) | ||
| 653 | netif_wake_subqueue(dev, i); | ||
| 654 | } | ||
| 655 | } | ||
| 656 | |||
| 657 | static void cpmac_hw_error(struct work_struct *work) | ||
| 658 | { | ||
| 659 | struct cpmac_priv *priv = | ||
| 660 | container_of(work, struct cpmac_priv, reset_work); | ||
| 661 | |||
| 662 | spin_lock(&priv->rx_lock); | ||
| 663 | cpmac_clear_rx(priv->dev); | ||
| 664 | spin_unlock(&priv->rx_lock); | ||
| 665 | cpmac_clear_tx(priv->dev); | ||
| 666 | cpmac_hw_start(priv->dev); | ||
| 667 | netif_start_queue(priv->dev); | ||
| 668 | } | ||
| 669 | |||
| 670 | static irqreturn_t cpmac_irq(int irq, void *dev_id) | ||
| 671 | { | ||
| 672 | struct net_device *dev = dev_id; | ||
| 673 | struct cpmac_priv *priv; | ||
| 674 | int queue; | ||
| 675 | u32 status; | ||
| 676 | |||
| 677 | if (!dev) | ||
| 678 | return IRQ_NONE; | ||
| 679 | |||
| 680 | priv = netdev_priv(dev); | ||
| 681 | |||
| 682 | status = cpmac_read(priv->regs, CPMAC_MAC_INT_VECTOR); | ||
| 683 | |||
| 684 | if (unlikely(netif_msg_intr(priv))) | ||
| 685 | printk(KERN_DEBUG "%s: interrupt status: 0x%08x\n", dev->name, | ||
| 686 | status); | ||
| 687 | |||
| 688 | if (status & MAC_INT_TX) | ||
| 689 | cpmac_end_xmit(dev, (status & 7)); | ||
| 690 | |||
| 691 | if (status & MAC_INT_RX) { | ||
| 692 | queue = (status >> 8) & 7; | ||
| 693 | netif_rx_schedule(dev); | ||
| 694 | cpmac_write(priv->regs, CPMAC_RX_INT_CLEAR, 1 << queue); | ||
| 695 | } | ||
| 696 | |||
| 697 | cpmac_write(priv->regs, CPMAC_MAC_EOI_VECTOR, 0); | ||
| 698 | |||
| 699 | if (unlikely(status & (MAC_INT_HOST | MAC_INT_STATUS))) { | ||
| 700 | if (netif_msg_drv(priv) && net_ratelimit()) | ||
| 701 | printk(KERN_ERR "%s: hw error, resetting...\n", | ||
| 702 | dev->name); | ||
| 703 | netif_stop_queue(dev); | ||
| 704 | cpmac_hw_stop(dev); | ||
| 705 | schedule_work(&priv->reset_work); | ||
| 706 | if (unlikely(netif_msg_hw(priv))) | ||
| 707 | cpmac_dump_regs(dev); | ||
| 708 | } | ||
| 709 | |||
| 710 | return IRQ_HANDLED; | ||
| 711 | } | ||
| 712 | |||
| 713 | static void cpmac_tx_timeout(struct net_device *dev) | ||
| 714 | { | ||
| 715 | struct cpmac_priv *priv = netdev_priv(dev); | ||
| 716 | int i; | ||
| 717 | |||
| 718 | spin_lock(&priv->lock); | ||
| 719 | dev->stats.tx_errors++; | ||
| 720 | spin_unlock(&priv->lock); | ||
| 721 | if (netif_msg_tx_err(priv) && net_ratelimit()) | ||
| 722 | printk(KERN_WARNING "%s: transmit timeout\n", dev->name); | ||
| 723 | /* | ||
| 724 | * FIXME: waking up random queue is not the best thing to | ||
| 725 | * do... on the other hand why we got here at all? | ||
| 726 | */ | ||
| 727 | #ifdef CONFIG_NETDEVICES_MULTIQUEUE | ||
| 728 | for (i = 0; i < CPMAC_QUEUES; i++) | ||
| 729 | if (priv->desc_ring[i].skb) { | ||
| 730 | dev_kfree_skb_any(priv->desc_ring[i].skb); | ||
| 731 | netif_wake_subqueue(dev, i); | ||
| 732 | break; | ||
| 733 | } | ||
| 734 | #else | ||
| 735 | if (priv->desc_ring[0].skb) | ||
| 736 | dev_kfree_skb_any(priv->desc_ring[0].skb); | ||
| 737 | netif_wake_queue(dev); | ||
| 738 | #endif | ||
| 739 | } | ||
| 740 | |||
| 741 | static int cpmac_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | ||
| 742 | { | ||
| 743 | struct cpmac_priv *priv = netdev_priv(dev); | ||
| 744 | if (!(netif_running(dev))) | ||
| 745 | return -EINVAL; | ||
| 746 | if (!priv->phy) | ||
| 747 | return -EINVAL; | ||
| 748 | if ((cmd == SIOCGMIIPHY) || (cmd == SIOCGMIIREG) || | ||
| 749 | (cmd == SIOCSMIIREG)) | ||
| 750 | return phy_mii_ioctl(priv->phy, if_mii(ifr), cmd); | ||
| 751 | |||
| 752 | return -EOPNOTSUPP; | ||
| 753 | } | ||
| 754 | |||
| 755 | static int cpmac_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) | ||
| 756 | { | ||
| 757 | struct cpmac_priv *priv = netdev_priv(dev); | ||
| 758 | |||
| 759 | if (priv->phy) | ||
| 760 | return phy_ethtool_gset(priv->phy, cmd); | ||
| 761 | |||
| 762 | return -EINVAL; | ||
| 763 | } | ||
| 764 | |||
| 765 | static int cpmac_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) | ||
| 766 | { | ||
| 767 | struct cpmac_priv *priv = netdev_priv(dev); | ||
| 768 | |||
| 769 | if (!capable(CAP_NET_ADMIN)) | ||
| 770 | return -EPERM; | ||
| 771 | |||
| 772 | if (priv->phy) | ||
| 773 | return phy_ethtool_sset(priv->phy, cmd); | ||
| 774 | |||
| 775 | return -EINVAL; | ||
| 776 | } | ||
| 777 | |||
| 778 | static void cpmac_get_ringparam(struct net_device *dev, struct ethtool_ringparam* ring) | ||
| 779 | { | ||
| 780 | struct cpmac_priv *priv = netdev_priv(dev); | ||
| 781 | |||
| 782 | ring->rx_max_pending = 1024; | ||
| 783 | ring->rx_mini_max_pending = 1; | ||
| 784 | ring->rx_jumbo_max_pending = 1; | ||
| 785 | ring->tx_max_pending = 1; | ||
| 786 | |||
| 787 | ring->rx_pending = priv->ring_size; | ||
| 788 | ring->rx_mini_pending = 1; | ||
| 789 | ring->rx_jumbo_pending = 1; | ||
| 790 | ring->tx_pending = 1; | ||
| 791 | } | ||
| 792 | |||
| 793 | static int cpmac_set_ringparam(struct net_device *dev, struct ethtool_ringparam* ring) | ||
| 794 | { | ||
| 795 | struct cpmac_priv *priv = netdev_priv(dev); | ||
| 796 | |||
| 797 | if (dev->flags && IFF_UP) | ||
| 798 | return -EBUSY; | ||
| 799 | priv->ring_size = ring->rx_pending; | ||
| 800 | return 0; | ||
| 801 | } | ||
| 802 | |||
| 803 | static void cpmac_get_drvinfo(struct net_device *dev, | ||
| 804 | struct ethtool_drvinfo *info) | ||
| 805 | { | ||
| 806 | strcpy(info->driver, "cpmac"); | ||
| 807 | strcpy(info->version, CPMAC_VERSION); | ||
| 808 | info->fw_version[0] = '\0'; | ||
| 809 | sprintf(info->bus_info, "%s", "cpmac"); | ||
| 810 | info->regdump_len = 0; | ||
| 811 | } | ||
| 812 | |||
| 813 | static const struct ethtool_ops cpmac_ethtool_ops = { | ||
| 814 | .get_settings = cpmac_get_settings, | ||
| 815 | .set_settings = cpmac_set_settings, | ||
| 816 | .get_drvinfo = cpmac_get_drvinfo, | ||
| 817 | .get_link = ethtool_op_get_link, | ||
| 818 | .get_ringparam = cpmac_get_ringparam, | ||
| 819 | .set_ringparam = cpmac_set_ringparam, | ||
| 820 | }; | ||
| 821 | |||
| 822 | static void cpmac_adjust_link(struct net_device *dev) | ||
| 823 | { | ||
| 824 | struct cpmac_priv *priv = netdev_priv(dev); | ||
| 825 | int new_state = 0; | ||
| 826 | |||
| 827 | spin_lock(&priv->lock); | ||
| 828 | if (priv->phy->link) { | ||
| 829 | netif_start_queue(dev); | ||
| 830 | if (priv->phy->duplex != priv->oldduplex) { | ||
| 831 | new_state = 1; | ||
| 832 | priv->oldduplex = priv->phy->duplex; | ||
| 833 | } | ||
| 834 | |||
| 835 | if (priv->phy->speed != priv->oldspeed) { | ||
| 836 | new_state = 1; | ||
| 837 | priv->oldspeed = priv->phy->speed; | ||
| 838 | } | ||
| 839 | |||
| 840 | if (!priv->oldlink) { | ||
| 841 | new_state = 1; | ||
| 842 | priv->oldlink = 1; | ||
| 843 | netif_schedule(dev); | ||
| 844 | } | ||
| 845 | } else if (priv->oldlink) { | ||
| 846 | netif_stop_queue(dev); | ||
| 847 | new_state = 1; | ||
| 848 | priv->oldlink = 0; | ||
| 849 | priv->oldspeed = 0; | ||
| 850 | priv->oldduplex = -1; | ||
| 851 | } | ||
| 852 | |||
| 853 | if (new_state && netif_msg_link(priv) && net_ratelimit()) | ||
| 854 | phy_print_status(priv->phy); | ||
| 855 | |||
| 856 | spin_unlock(&priv->lock); | ||
| 857 | } | ||
| 858 | |||
| 859 | static int cpmac_open(struct net_device *dev) | ||
| 860 | { | ||
| 861 | int i, size, res; | ||
| 862 | struct cpmac_priv *priv = netdev_priv(dev); | ||
| 863 | struct resource *mem; | ||
| 864 | struct cpmac_desc *desc; | ||
| 865 | struct sk_buff *skb; | ||
| 866 | |||
| 867 | priv->phy = phy_connect(dev, priv->phy_name, &cpmac_adjust_link, | ||
| 868 | 0, PHY_INTERFACE_MODE_MII); | ||
| 869 | if (IS_ERR(priv->phy)) { | ||
| 870 | if (netif_msg_drv(priv)) | ||
| 871 | printk(KERN_ERR "%s: Could not attach to PHY\n", | ||
| 872 | dev->name); | ||
| 873 | return PTR_ERR(priv->phy); | ||
| 874 | } | ||
| 875 | |||
| 876 | mem = platform_get_resource_byname(priv->pdev, IORESOURCE_MEM, "regs"); | ||
| 877 | if (!request_mem_region(mem->start, mem->end - mem->start, dev->name)) { | ||
| 878 | if (netif_msg_drv(priv)) | ||
| 879 | printk(KERN_ERR "%s: failed to request registers\n", | ||
| 880 | dev->name); | ||
| 881 | res = -ENXIO; | ||
| 882 | goto fail_reserve; | ||
| 883 | } | ||
| 884 | |||
| 885 | priv->regs = ioremap(mem->start, mem->end - mem->start); | ||
| 886 | if (!priv->regs) { | ||
| 887 | if (netif_msg_drv(priv)) | ||
| 888 | printk(KERN_ERR "%s: failed to remap registers\n", | ||
| 889 | dev->name); | ||
| 890 | res = -ENXIO; | ||
| 891 | goto fail_remap; | ||
| 892 | } | ||
| 893 | |||
| 894 | size = priv->ring_size + CPMAC_QUEUES; | ||
| 895 | priv->desc_ring = dma_alloc_coherent(&dev->dev, | ||
| 896 | sizeof(struct cpmac_desc) * size, | ||
| 897 | &priv->dma_ring, | ||
| 898 | GFP_KERNEL); | ||
| 899 | if (!priv->desc_ring) { | ||
| 900 | res = -ENOMEM; | ||
| 901 | goto fail_alloc; | ||
| 902 | } | ||
| 903 | |||
| 904 | for (i = 0; i < size; i++) | ||
| 905 | priv->desc_ring[i].mapping = priv->dma_ring + sizeof(*desc) * i; | ||
| 906 | |||
| 907 | priv->rx_head = &priv->desc_ring[CPMAC_QUEUES]; | ||
| 908 | for (i = 0, desc = priv->rx_head; i < priv->ring_size; i++, desc++) { | ||
| 909 | skb = netdev_alloc_skb(dev, CPMAC_SKB_SIZE); | ||
| 910 | if (unlikely(!skb)) { | ||
| 911 | res = -ENOMEM; | ||
| 912 | goto fail_desc; | ||
| 913 | } | ||
| 914 | skb_reserve(skb, 2); | ||
| 915 | desc->skb = skb; | ||
| 916 | desc->data_mapping = dma_map_single(&dev->dev, skb->data, | ||
| 917 | CPMAC_SKB_SIZE, | ||
| 918 | DMA_FROM_DEVICE); | ||
| 919 | desc->hw_data = (u32)desc->data_mapping; | ||
| 920 | desc->buflen = CPMAC_SKB_SIZE; | ||
| 921 | desc->dataflags = CPMAC_OWN; | ||
| 922 | desc->next = &priv->rx_head[(i + 1) % priv->ring_size]; | ||
| 923 | desc->hw_next = (u32)desc->next->mapping; | ||
| 924 | } | ||
| 925 | |||
| 926 | if ((res = request_irq(dev->irq, cpmac_irq, IRQF_SHARED, | ||
| 927 | dev->name, dev))) { | ||
| 928 | if (netif_msg_drv(priv)) | ||
| 929 | printk(KERN_ERR "%s: failed to obtain irq\n", | ||
| 930 | dev->name); | ||
| 931 | goto fail_irq; | ||
| 932 | } | ||
| 933 | |||
| 934 | INIT_WORK(&priv->reset_work, cpmac_hw_error); | ||
| 935 | cpmac_hw_start(dev); | ||
| 936 | |||
| 937 | priv->phy->state = PHY_CHANGELINK; | ||
| 938 | phy_start(priv->phy); | ||
| 939 | |||
| 940 | return 0; | ||
| 941 | |||
| 942 | fail_irq: | ||
| 943 | fail_desc: | ||
| 944 | for (i = 0; i < priv->ring_size; i++) { | ||
| 945 | if (priv->rx_head[i].skb) { | ||
| 946 | dma_unmap_single(&dev->dev, | ||
| 947 | priv->rx_head[i].data_mapping, | ||
| 948 | CPMAC_SKB_SIZE, | ||
| 949 | DMA_FROM_DEVICE); | ||
| 950 | kfree_skb(priv->rx_head[i].skb); | ||
| 951 | } | ||
| 952 | } | ||
| 953 | fail_alloc: | ||
| 954 | kfree(priv->desc_ring); | ||
| 955 | iounmap(priv->regs); | ||
| 956 | |||
| 957 | fail_remap: | ||
| 958 | release_mem_region(mem->start, mem->end - mem->start); | ||
| 959 | |||
| 960 | fail_reserve: | ||
| 961 | phy_disconnect(priv->phy); | ||
| 962 | |||
| 963 | return res; | ||
| 964 | } | ||
| 965 | |||
| 966 | static int cpmac_stop(struct net_device *dev) | ||
| 967 | { | ||
| 968 | int i; | ||
| 969 | struct cpmac_priv *priv = netdev_priv(dev); | ||
| 970 | struct resource *mem; | ||
| 971 | |||
| 972 | netif_stop_queue(dev); | ||
| 973 | |||
| 974 | cancel_work_sync(&priv->reset_work); | ||
| 975 | phy_stop(priv->phy); | ||
| 976 | phy_disconnect(priv->phy); | ||
| 977 | priv->phy = NULL; | ||
| 978 | |||
| 979 | cpmac_hw_stop(dev); | ||
| 980 | |||
| 981 | for (i = 0; i < 8; i++) | ||
| 982 | cpmac_write(priv->regs, CPMAC_TX_PTR(i), 0); | ||
| 983 | cpmac_write(priv->regs, CPMAC_RX_PTR(0), 0); | ||
| 984 | cpmac_write(priv->regs, CPMAC_MBP, 0); | ||
| 985 | |||
| 986 | free_irq(dev->irq, dev); | ||
| 987 | iounmap(priv->regs); | ||
| 988 | mem = platform_get_resource_byname(priv->pdev, IORESOURCE_MEM, "regs"); | ||
| 989 | release_mem_region(mem->start, mem->end - mem->start); | ||
| 990 | priv->rx_head = &priv->desc_ring[CPMAC_QUEUES]; | ||
| 991 | for (i = 0; i < priv->ring_size; i++) { | ||
| 992 | if (priv->rx_head[i].skb) { | ||
| 993 | dma_unmap_single(&dev->dev, | ||
| 994 | priv->rx_head[i].data_mapping, | ||
| 995 | CPMAC_SKB_SIZE, | ||
| 996 | DMA_FROM_DEVICE); | ||
| 997 | kfree_skb(priv->rx_head[i].skb); | ||
| 998 | } | ||
| 999 | } | ||
| 1000 | |||
| 1001 | dma_free_coherent(&dev->dev, sizeof(struct cpmac_desc) * | ||
| 1002 | (CPMAC_QUEUES + priv->ring_size), | ||
| 1003 | priv->desc_ring, priv->dma_ring); | ||
| 1004 | return 0; | ||
| 1005 | } | ||
| 1006 | |||
| 1007 | static int external_switch; | ||
| 1008 | |||
| 1009 | static int __devinit cpmac_probe(struct platform_device *pdev) | ||
| 1010 | { | ||
| 1011 | int rc, phy_id; | ||
| 1012 | struct resource *mem; | ||
| 1013 | struct cpmac_priv *priv; | ||
| 1014 | struct net_device *dev; | ||
| 1015 | struct plat_cpmac_data *pdata; | ||
| 1016 | |||
| 1017 | pdata = pdev->dev.platform_data; | ||
| 1018 | |||
| 1019 | for (phy_id = 0; phy_id < PHY_MAX_ADDR; phy_id++) { | ||
| 1020 | if (!(pdata->phy_mask & (1 << phy_id))) | ||
| 1021 | continue; | ||
| 1022 | if (!cpmac_mii.phy_map[phy_id]) | ||
| 1023 | continue; | ||
| 1024 | break; | ||
| 1025 | } | ||
| 1026 | |||
| 1027 | if (phy_id == PHY_MAX_ADDR) { | ||
| 1028 | if (external_switch || dumb_switch) | ||
| 1029 | phy_id = 0; | ||
| 1030 | else { | ||
| 1031 | printk(KERN_ERR "cpmac: no PHY present\n"); | ||
| 1032 | return -ENODEV; | ||
| 1033 | } | ||
| 1034 | } | ||
| 1035 | |||
| 1036 | dev = alloc_etherdev_mq(sizeof(*priv), CPMAC_QUEUES); | ||
| 1037 | |||
| 1038 | if (!dev) { | ||
| 1039 | printk(KERN_ERR "cpmac: Unable to allocate net_device\n"); | ||
| 1040 | return -ENOMEM; | ||
| 1041 | } | ||
| 1042 | |||
| 1043 | platform_set_drvdata(pdev, dev); | ||
| 1044 | priv = netdev_priv(dev); | ||
| 1045 | |||
| 1046 | priv->pdev = pdev; | ||
| 1047 | mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs"); | ||
| 1048 | if (!mem) { | ||
| 1049 | rc = -ENODEV; | ||
| 1050 | goto fail; | ||
| 1051 | } | ||
| 1052 | |||
| 1053 | dev->irq = platform_get_irq_byname(pdev, "irq"); | ||
| 1054 | |||
| 1055 | dev->open = cpmac_open; | ||
| 1056 | dev->stop = cpmac_stop; | ||
| 1057 | dev->set_config = cpmac_config; | ||
| 1058 | dev->hard_start_xmit = cpmac_start_xmit; | ||
| 1059 | dev->do_ioctl = cpmac_ioctl; | ||
| 1060 | dev->set_multicast_list = cpmac_set_multicast_list; | ||
| 1061 | dev->tx_timeout = cpmac_tx_timeout; | ||
| 1062 | dev->ethtool_ops = &cpmac_ethtool_ops; | ||
| 1063 | dev->poll = cpmac_poll; | ||
| 1064 | dev->weight = 64; | ||
| 1065 | dev->features |= NETIF_F_MULTI_QUEUE; | ||
| 1066 | |||
| 1067 | spin_lock_init(&priv->lock); | ||
| 1068 | spin_lock_init(&priv->rx_lock); | ||
| 1069 | priv->dev = dev; | ||
| 1070 | priv->ring_size = 64; | ||
| 1071 | priv->msg_enable = netif_msg_init(debug_level, 0xff); | ||
| 1072 | memcpy(dev->dev_addr, pdata->dev_addr, sizeof(dev->dev_addr)); | ||
| 1073 | if (phy_id == 31) { | ||
| 1074 | snprintf(priv->phy_name, BUS_ID_SIZE, PHY_ID_FMT, | ||
| 1075 | cpmac_mii.id, phy_id); | ||
| 1076 | } else | ||
| 1077 | snprintf(priv->phy_name, BUS_ID_SIZE, "fixed@%d:%d", 100, 1); | ||
| 1078 | |||
| 1079 | if ((rc = register_netdev(dev))) { | ||
| 1080 | printk(KERN_ERR "cpmac: error %i registering device %s\n", rc, | ||
| 1081 | dev->name); | ||
| 1082 | goto fail; | ||
| 1083 | } | ||
| 1084 | |||
| 1085 | if (netif_msg_probe(priv)) { | ||
| 1086 | printk(KERN_INFO | ||
| 1087 | "cpmac: device %s (regs: %p, irq: %d, phy: %s, mac: " | ||
| 1088 | MAC_FMT ")\n", dev->name, (void *)mem->start, dev->irq, | ||
| 1089 | priv->phy_name, MAC_ARG(dev->dev_addr)); | ||
| 1090 | } | ||
| 1091 | return 0; | ||
| 1092 | |||
| 1093 | fail: | ||
| 1094 | free_netdev(dev); | ||
| 1095 | return rc; | ||
| 1096 | } | ||
| 1097 | |||
| 1098 | static int __devexit cpmac_remove(struct platform_device *pdev) | ||
| 1099 | { | ||
| 1100 | struct net_device *dev = platform_get_drvdata(pdev); | ||
| 1101 | unregister_netdev(dev); | ||
| 1102 | free_netdev(dev); | ||
| 1103 | return 0; | ||
| 1104 | } | ||
| 1105 | |||
| 1106 | static struct platform_driver cpmac_driver = { | ||
| 1107 | .driver.name = "cpmac", | ||
| 1108 | .probe = cpmac_probe, | ||
| 1109 | .remove = __devexit_p(cpmac_remove), | ||
| 1110 | }; | ||
| 1111 | |||
| 1112 | int __devinit cpmac_init(void) | ||
| 1113 | { | ||
| 1114 | u32 mask; | ||
| 1115 | int i, res; | ||
| 1116 | |||
| 1117 | cpmac_mii.priv = ioremap(AR7_REGS_MDIO, 256); | ||
| 1118 | |||
| 1119 | if (!cpmac_mii.priv) { | ||
| 1120 | printk(KERN_ERR "Can't ioremap mdio registers\n"); | ||
| 1121 | return -ENXIO; | ||
| 1122 | } | ||
| 1123 | |||
| 1124 | #warning FIXME: unhardcode gpio&reset bits | ||
| 1125 | ar7_gpio_disable(26); | ||
| 1126 | ar7_gpio_disable(27); | ||
| 1127 | ar7_device_reset(AR7_RESET_BIT_CPMAC_LO); | ||
| 1128 | ar7_device_reset(AR7_RESET_BIT_CPMAC_HI); | ||
| 1129 | ar7_device_reset(AR7_RESET_BIT_EPHY); | ||
| 1130 | |||
| 1131 | cpmac_mii.reset(&cpmac_mii); | ||
| 1132 | |||
| 1133 | for (i = 0; i < 300000; i++) | ||
| 1134 | if ((mask = cpmac_read(cpmac_mii.priv, CPMAC_MDIO_ALIVE))) | ||
| 1135 | break; | ||
| 1136 | else | ||
| 1137 | cpu_relax(); | ||
| 1138 | |||
| 1139 | mask &= 0x7fffffff; | ||
| 1140 | if (mask & (mask - 1)) { | ||
| 1141 | external_switch = 1; | ||
| 1142 | mask = 0; | ||
| 1143 | } | ||
| 1144 | |||
| 1145 | cpmac_mii.phy_mask = ~(mask | 0x80000000); | ||
| 1146 | |||
| 1147 | res = mdiobus_register(&cpmac_mii); | ||
| 1148 | if (res) | ||
| 1149 | goto fail_mii; | ||
| 1150 | |||
| 1151 | res = platform_driver_register(&cpmac_driver); | ||
| 1152 | if (res) | ||
| 1153 | goto fail_cpmac; | ||
| 1154 | |||
| 1155 | return 0; | ||
| 1156 | |||
| 1157 | fail_cpmac: | ||
| 1158 | mdiobus_unregister(&cpmac_mii); | ||
| 1159 | |||
| 1160 | fail_mii: | ||
| 1161 | iounmap(cpmac_mii.priv); | ||
| 1162 | |||
| 1163 | return res; | ||
| 1164 | } | ||
| 1165 | |||
| 1166 | void __devexit cpmac_exit(void) | ||
| 1167 | { | ||
| 1168 | platform_driver_unregister(&cpmac_driver); | ||
| 1169 | mdiobus_unregister(&cpmac_mii); | ||
| 1170 | iounmap(cpmac_mii.priv); | ||
| 1171 | } | ||
| 1172 | |||
| 1173 | module_init(cpmac_init); | ||
| 1174 | module_exit(cpmac_exit); | ||
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 0db5e6fabe73..558440c15b6c 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c | |||
| @@ -168,7 +168,6 @@ static int gfar_probe(struct platform_device *pdev) | |||
| 168 | struct gfar_private *priv = NULL; | 168 | struct gfar_private *priv = NULL; |
| 169 | struct gianfar_platform_data *einfo; | 169 | struct gianfar_platform_data *einfo; |
| 170 | struct resource *r; | 170 | struct resource *r; |
| 171 | int idx; | ||
| 172 | int err = 0; | 171 | int err = 0; |
| 173 | DECLARE_MAC_BUF(mac); | 172 | DECLARE_MAC_BUF(mac); |
| 174 | 173 | ||
| @@ -261,7 +260,9 @@ static int gfar_probe(struct platform_device *pdev) | |||
| 261 | dev->hard_start_xmit = gfar_start_xmit; | 260 | dev->hard_start_xmit = gfar_start_xmit; |
| 262 | dev->tx_timeout = gfar_timeout; | 261 | dev->tx_timeout = gfar_timeout; |
| 263 | dev->watchdog_timeo = TX_TIMEOUT; | 262 | dev->watchdog_timeo = TX_TIMEOUT; |
| 263 | #ifdef CONFIG_GFAR_NAPI | ||
| 264 | netif_napi_add(dev, &priv->napi, gfar_poll, GFAR_DEV_WEIGHT); | 264 | netif_napi_add(dev, &priv->napi, gfar_poll, GFAR_DEV_WEIGHT); |
| 265 | #endif | ||
| 265 | #ifdef CONFIG_NET_POLL_CONTROLLER | 266 | #ifdef CONFIG_NET_POLL_CONTROLLER |
| 266 | dev->poll_controller = gfar_netpoll; | 267 | dev->poll_controller = gfar_netpoll; |
| 267 | #endif | 268 | #endif |
| @@ -931,9 +932,14 @@ tx_skb_fail: | |||
| 931 | /* Returns 0 for success. */ | 932 | /* Returns 0 for success. */ |
| 932 | static int gfar_enet_open(struct net_device *dev) | 933 | static int gfar_enet_open(struct net_device *dev) |
| 933 | { | 934 | { |
| 935 | #ifdef CONFIG_GFAR_NAPI | ||
| 936 | struct gfar_private *priv = netdev_priv(dev); | ||
| 937 | #endif | ||
| 934 | int err; | 938 | int err; |
| 935 | 939 | ||
| 940 | #ifdef CONFIG_GFAR_NAPI | ||
| 936 | napi_enable(&priv->napi); | 941 | napi_enable(&priv->napi); |
| 942 | #endif | ||
| 937 | 943 | ||
| 938 | /* Initialize a bunch of registers */ | 944 | /* Initialize a bunch of registers */ |
| 939 | init_registers(dev); | 945 | init_registers(dev); |
| @@ -943,13 +949,17 @@ static int gfar_enet_open(struct net_device *dev) | |||
| 943 | err = init_phy(dev); | 949 | err = init_phy(dev); |
| 944 | 950 | ||
| 945 | if(err) { | 951 | if(err) { |
| 952 | #ifdef CONFIG_GFAR_NAPI | ||
| 946 | napi_disable(&priv->napi); | 953 | napi_disable(&priv->napi); |
| 954 | #endif | ||
| 947 | return err; | 955 | return err; |
| 948 | } | 956 | } |
| 949 | 957 | ||
| 950 | err = startup_gfar(dev); | 958 | err = startup_gfar(dev); |
| 951 | if (err) | 959 | if (err) |
| 960 | #ifdef CONFIG_GFAR_NAPI | ||
| 952 | napi_disable(&priv->napi); | 961 | napi_disable(&priv->napi); |
| 962 | #endif | ||
| 953 | 963 | ||
| 954 | netif_start_queue(dev); | 964 | netif_start_queue(dev); |
| 955 | 965 | ||
| @@ -1103,7 +1113,9 @@ static int gfar_close(struct net_device *dev) | |||
| 1103 | { | 1113 | { |
| 1104 | struct gfar_private *priv = netdev_priv(dev); | 1114 | struct gfar_private *priv = netdev_priv(dev); |
| 1105 | 1115 | ||
| 1116 | #ifdef CONFIG_GFAR_NAPI | ||
| 1106 | napi_disable(&priv->napi); | 1117 | napi_disable(&priv->napi); |
| 1118 | #endif | ||
| 1107 | 1119 | ||
| 1108 | stop_gfar(dev); | 1120 | stop_gfar(dev); |
| 1109 | 1121 | ||
diff --git a/drivers/net/ibm_emac/ibm_emac_mal.c b/drivers/net/ibm_emac/ibm_emac_mal.c index 4e49e8c4f871..dcd8826fc749 100644 --- a/drivers/net/ibm_emac/ibm_emac_mal.c +++ b/drivers/net/ibm_emac/ibm_emac_mal.c | |||
| @@ -413,7 +413,10 @@ static int __init mal_probe(struct ocp_device *ocpdev) | |||
| 413 | ocpdev->def->index); | 413 | ocpdev->def->index); |
| 414 | return -ENOMEM; | 414 | return -ENOMEM; |
| 415 | } | 415 | } |
| 416 | mal->dcrbase = maldata->dcr_base; | 416 | |
| 417 | /* XXX This only works for native dcr for now */ | ||
| 418 | mal->dcrhost = dcr_map(NULL, maldata->dcr_base, 0); | ||
| 419 | |||
| 417 | mal->def = ocpdev->def; | 420 | mal->def = ocpdev->def; |
| 418 | 421 | ||
| 419 | INIT_LIST_HEAD(&mal->poll_list); | 422 | INIT_LIST_HEAD(&mal->poll_list); |
diff --git a/drivers/net/ibm_emac/ibm_emac_mal.h b/drivers/net/ibm_emac/ibm_emac_mal.h index 8f54d621994d..b8adbe6d4b01 100644 --- a/drivers/net/ibm_emac/ibm_emac_mal.h +++ b/drivers/net/ibm_emac/ibm_emac_mal.h | |||
| @@ -191,7 +191,6 @@ struct mal_commac { | |||
| 191 | }; | 191 | }; |
| 192 | 192 | ||
| 193 | struct ibm_ocp_mal { | 193 | struct ibm_ocp_mal { |
| 194 | int dcrbase; | ||
| 195 | dcr_host_t dcrhost; | 194 | dcr_host_t dcrhost; |
| 196 | 195 | ||
| 197 | struct list_head poll_list; | 196 | struct list_head poll_list; |
| @@ -209,12 +208,12 @@ struct ibm_ocp_mal { | |||
| 209 | 208 | ||
| 210 | static inline u32 get_mal_dcrn(struct ibm_ocp_mal *mal, int reg) | 209 | static inline u32 get_mal_dcrn(struct ibm_ocp_mal *mal, int reg) |
| 211 | { | 210 | { |
| 212 | return dcr_read(mal->dcrhost, mal->dcrbase + reg); | 211 | return dcr_read(mal->dcrhost, reg); |
| 213 | } | 212 | } |
| 214 | 213 | ||
| 215 | static inline void set_mal_dcrn(struct ibm_ocp_mal *mal, int reg, u32 val) | 214 | static inline void set_mal_dcrn(struct ibm_ocp_mal *mal, int reg, u32 val) |
| 216 | { | 215 | { |
| 217 | dcr_write(mal->dcrhost, mal->dcrbase + reg, val); | 216 | dcr_write(mal->dcrhost, reg, val); |
| 218 | } | 217 | } |
| 219 | 218 | ||
| 220 | /* Register MAL devices */ | 219 | /* Register MAL devices */ |
diff --git a/drivers/net/ibm_newemac/mal.c b/drivers/net/ibm_newemac/mal.c index 58854117b1a9..39f4cb6b0cf3 100644 --- a/drivers/net/ibm_newemac/mal.c +++ b/drivers/net/ibm_newemac/mal.c | |||
| @@ -461,6 +461,7 @@ static int __devinit mal_probe(struct of_device *ofdev, | |||
| 461 | struct mal_instance *mal; | 461 | struct mal_instance *mal; |
| 462 | int err = 0, i, bd_size; | 462 | int err = 0, i, bd_size; |
| 463 | int index = mal_count++; | 463 | int index = mal_count++; |
| 464 | unsigned int dcr_base; | ||
| 464 | const u32 *prop; | 465 | const u32 *prop; |
| 465 | u32 cfg; | 466 | u32 cfg; |
| 466 | 467 | ||
| @@ -497,14 +498,14 @@ static int __devinit mal_probe(struct of_device *ofdev, | |||
| 497 | } | 498 | } |
| 498 | mal->num_rx_chans = prop[0]; | 499 | mal->num_rx_chans = prop[0]; |
| 499 | 500 | ||
| 500 | mal->dcr_base = dcr_resource_start(ofdev->node, 0); | 501 | dcr_base = dcr_resource_start(ofdev->node, 0); |
| 501 | if (mal->dcr_base == 0) { | 502 | if (dcr_base == 0) { |
| 502 | printk(KERN_ERR | 503 | printk(KERN_ERR |
| 503 | "mal%d: can't find DCR resource!\n", index); | 504 | "mal%d: can't find DCR resource!\n", index); |
| 504 | err = -ENODEV; | 505 | err = -ENODEV; |
| 505 | goto fail; | 506 | goto fail; |
| 506 | } | 507 | } |
| 507 | mal->dcr_host = dcr_map(ofdev->node, mal->dcr_base, 0x100); | 508 | mal->dcr_host = dcr_map(ofdev->node, dcr_base, 0x100); |
| 508 | if (!DCR_MAP_OK(mal->dcr_host)) { | 509 | if (!DCR_MAP_OK(mal->dcr_host)) { |
| 509 | printk(KERN_ERR | 510 | printk(KERN_ERR |
| 510 | "mal%d: failed to map DCRs !\n", index); | 511 | "mal%d: failed to map DCRs !\n", index); |
| @@ -626,7 +627,7 @@ static int __devinit mal_probe(struct of_device *ofdev, | |||
| 626 | fail2: | 627 | fail2: |
| 627 | dma_free_coherent(&ofdev->dev, bd_size, mal->bd_virt, mal->bd_dma); | 628 | dma_free_coherent(&ofdev->dev, bd_size, mal->bd_virt, mal->bd_dma); |
| 628 | fail_unmap: | 629 | fail_unmap: |
| 629 | dcr_unmap(mal->dcr_host, mal->dcr_base, 0x100); | 630 | dcr_unmap(mal->dcr_host, 0x100); |
| 630 | fail: | 631 | fail: |
| 631 | kfree(mal); | 632 | kfree(mal); |
| 632 | 633 | ||
diff --git a/drivers/net/ibm_newemac/mal.h b/drivers/net/ibm_newemac/mal.h index cb1a16d589fe..784edb8ea822 100644 --- a/drivers/net/ibm_newemac/mal.h +++ b/drivers/net/ibm_newemac/mal.h | |||
| @@ -185,7 +185,6 @@ struct mal_commac { | |||
| 185 | 185 | ||
| 186 | struct mal_instance { | 186 | struct mal_instance { |
| 187 | int version; | 187 | int version; |
| 188 | int dcr_base; | ||
| 189 | dcr_host_t dcr_host; | 188 | dcr_host_t dcr_host; |
| 190 | 189 | ||
| 191 | int num_tx_chans; /* Number of TX channels */ | 190 | int num_tx_chans; /* Number of TX channels */ |
| @@ -213,12 +212,12 @@ struct mal_instance { | |||
| 213 | 212 | ||
| 214 | static inline u32 get_mal_dcrn(struct mal_instance *mal, int reg) | 213 | static inline u32 get_mal_dcrn(struct mal_instance *mal, int reg) |
| 215 | { | 214 | { |
| 216 | return dcr_read(mal->dcr_host, mal->dcr_base + reg); | 215 | return dcr_read(mal->dcr_host, reg); |
| 217 | } | 216 | } |
| 218 | 217 | ||
| 219 | static inline void set_mal_dcrn(struct mal_instance *mal, int reg, u32 val) | 218 | static inline void set_mal_dcrn(struct mal_instance *mal, int reg, u32 val) |
| 220 | { | 219 | { |
| 221 | dcr_write(mal->dcr_host, mal->dcr_base + reg, val); | 220 | dcr_write(mal->dcr_host, reg, val); |
| 222 | } | 221 | } |
| 223 | 222 | ||
| 224 | /* Register MAL devices */ | 223 | /* Register MAL devices */ |
diff --git a/drivers/net/irda/donauboe.c b/drivers/net/irda/donauboe.c index 3e5eca1aa987..a82d8f98383d 100644 --- a/drivers/net/irda/donauboe.c +++ b/drivers/net/irda/donauboe.c | |||
| @@ -840,7 +840,7 @@ toshoboe_probe (struct toshoboe_cb *self) | |||
| 840 | 840 | ||
| 841 | /* test 1: SIR filter and back to back */ | 841 | /* test 1: SIR filter and back to back */ |
| 842 | 842 | ||
| 843 | for (j = 0; j < (sizeof (bauds) / sizeof (int)); ++j) | 843 | for (j = 0; j < ARRAY_SIZE(bauds); ++j) |
| 844 | { | 844 | { |
| 845 | int fir = (j > 1); | 845 | int fir = (j > 1); |
| 846 | toshoboe_stopchip (self); | 846 | toshoboe_stopchip (self); |
diff --git a/drivers/net/jazzsonic.c b/drivers/net/jazzsonic.c index d3825c8ee994..5c154fe13859 100644 --- a/drivers/net/jazzsonic.c +++ b/drivers/net/jazzsonic.c | |||
| @@ -208,7 +208,6 @@ static int __init jazz_sonic_probe(struct platform_device *pdev) | |||
| 208 | struct sonic_local *lp; | 208 | struct sonic_local *lp; |
| 209 | struct resource *res; | 209 | struct resource *res; |
| 210 | int err = 0; | 210 | int err = 0; |
| 211 | int i; | ||
| 212 | DECLARE_MAC_BUF(mac); | 211 | DECLARE_MAC_BUF(mac); |
| 213 | 212 | ||
| 214 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 213 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
diff --git a/drivers/net/mipsnet.c b/drivers/net/mipsnet.c index d593175ab6f0..37707a0c0498 100644 --- a/drivers/net/mipsnet.c +++ b/drivers/net/mipsnet.c | |||
| @@ -7,12 +7,12 @@ | |||
| 7 | #define DEBUG | 7 | #define DEBUG |
| 8 | 8 | ||
| 9 | #include <linux/init.h> | 9 | #include <linux/init.h> |
| 10 | #include <linux/io.h> | ||
| 10 | #include <linux/kernel.h> | 11 | #include <linux/kernel.h> |
| 11 | #include <linux/module.h> | 12 | #include <linux/module.h> |
| 12 | #include <linux/netdevice.h> | 13 | #include <linux/netdevice.h> |
| 13 | #include <linux/etherdevice.h> | 14 | #include <linux/etherdevice.h> |
| 14 | #include <linux/platform_device.h> | 15 | #include <linux/platform_device.h> |
| 15 | #include <asm/io.h> | ||
| 16 | #include <asm/mips-boards/simint.h> | 16 | #include <asm/mips-boards/simint.h> |
| 17 | 17 | ||
| 18 | #include "mipsnet.h" /* actual device IO mapping */ | 18 | #include "mipsnet.h" /* actual device IO mapping */ |
| @@ -33,9 +33,8 @@ static int ioiocpy_frommipsnet(struct net_device *dev, unsigned char *kdata, | |||
| 33 | if (available_len < len) | 33 | if (available_len < len) |
| 34 | return -EFAULT; | 34 | return -EFAULT; |
| 35 | 35 | ||
| 36 | for (; len > 0; len--, kdata++) { | 36 | for (; len > 0; len--, kdata++) |
| 37 | *kdata = inb(mipsnet_reg_address(dev, rxDataBuffer)); | 37 | *kdata = inb(mipsnet_reg_address(dev, rxDataBuffer)); |
| 38 | } | ||
| 39 | 38 | ||
| 40 | return inl(mipsnet_reg_address(dev, rxDataCount)); | 39 | return inl(mipsnet_reg_address(dev, rxDataCount)); |
| 41 | } | 40 | } |
| @@ -47,16 +46,15 @@ static inline ssize_t mipsnet_put_todevice(struct net_device *dev, | |||
| 47 | char *buf_ptr = skb->data; | 46 | char *buf_ptr = skb->data; |
| 48 | 47 | ||
| 49 | pr_debug("%s: %s(): telling MIPSNET txDataCount(%d)\n", | 48 | pr_debug("%s: %s(): telling MIPSNET txDataCount(%d)\n", |
| 50 | dev->name, __FUNCTION__, skb->len); | 49 | dev->name, __FUNCTION__, skb->len); |
| 51 | 50 | ||
| 52 | outl(skb->len, mipsnet_reg_address(dev, txDataCount)); | 51 | outl(skb->len, mipsnet_reg_address(dev, txDataCount)); |
| 53 | 52 | ||
| 54 | pr_debug("%s: %s(): sending data to MIPSNET txDataBuffer(%d)\n", | 53 | pr_debug("%s: %s(): sending data to MIPSNET txDataBuffer(%d)\n", |
| 55 | dev->name, __FUNCTION__, skb->len); | 54 | dev->name, __FUNCTION__, skb->len); |
| 56 | 55 | ||
| 57 | for (; count_to_go; buf_ptr++, count_to_go--) { | 56 | for (; count_to_go; buf_ptr++, count_to_go--) |
| 58 | outb(*buf_ptr, mipsnet_reg_address(dev, txDataBuffer)); | 57 | outb(*buf_ptr, mipsnet_reg_address(dev, txDataBuffer)); |
| 59 | } | ||
| 60 | 58 | ||
| 61 | dev->stats.tx_packets++; | 59 | dev->stats.tx_packets++; |
| 62 | dev->stats.tx_bytes += skb->len; | 60 | dev->stats.tx_bytes += skb->len; |
| @@ -67,7 +65,7 @@ static inline ssize_t mipsnet_put_todevice(struct net_device *dev, | |||
| 67 | static int mipsnet_xmit(struct sk_buff *skb, struct net_device *dev) | 65 | static int mipsnet_xmit(struct sk_buff *skb, struct net_device *dev) |
| 68 | { | 66 | { |
| 69 | pr_debug("%s:%s(): transmitting %d bytes\n", | 67 | pr_debug("%s:%s(): transmitting %d bytes\n", |
| 70 | dev->name, __FUNCTION__, skb->len); | 68 | dev->name, __FUNCTION__, skb->len); |
| 71 | 69 | ||
| 72 | /* Only one packet at a time. Once TXDONE interrupt is serviced, the | 70 | /* Only one packet at a time. Once TXDONE interrupt is serviced, the |
| 73 | * queue will be restarted. | 71 | * queue will be restarted. |
| @@ -83,7 +81,8 @@ static inline ssize_t mipsnet_get_fromdev(struct net_device *dev, size_t count) | |||
| 83 | struct sk_buff *skb; | 81 | struct sk_buff *skb; |
| 84 | size_t len = count; | 82 | size_t len = count; |
| 85 | 83 | ||
| 86 | if (!(skb = alloc_skb(len + 2, GFP_KERNEL))) { | 84 | skb = alloc_skb(len + 2, GFP_KERNEL); |
| 85 | if (!skb) { | ||
| 87 | dev->stats.rx_dropped++; | 86 | dev->stats.rx_dropped++; |
| 88 | return -ENOMEM; | 87 | return -ENOMEM; |
| 89 | } | 88 | } |
| @@ -96,7 +95,7 @@ static inline ssize_t mipsnet_get_fromdev(struct net_device *dev, size_t count) | |||
| 96 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 95 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
| 97 | 96 | ||
| 98 | pr_debug("%s:%s(): pushing RXed data to kernel\n", | 97 | pr_debug("%s:%s(): pushing RXed data to kernel\n", |
| 99 | dev->name, __FUNCTION__); | 98 | dev->name, __FUNCTION__); |
| 100 | netif_rx(skb); | 99 | netif_rx(skb); |
| 101 | 100 | ||
| 102 | dev->stats.rx_packets++; | 101 | dev->stats.rx_packets++; |
| @@ -114,42 +113,44 @@ static irqreturn_t mipsnet_interrupt(int irq, void *dev_id) | |||
| 114 | 113 | ||
| 115 | if (irq == dev->irq) { | 114 | if (irq == dev->irq) { |
| 116 | pr_debug("%s:%s(): irq %d for device\n", | 115 | pr_debug("%s:%s(): irq %d for device\n", |
| 117 | dev->name, __FUNCTION__, irq); | 116 | dev->name, __FUNCTION__, irq); |
| 118 | 117 | ||
| 119 | retval = IRQ_HANDLED; | 118 | retval = IRQ_HANDLED; |
| 120 | 119 | ||
| 121 | interruptFlags = | 120 | interruptFlags = |
| 122 | inl(mipsnet_reg_address(dev, interruptControl)); | 121 | inl(mipsnet_reg_address(dev, interruptControl)); |
| 123 | pr_debug("%s:%s(): intCtl=0x%016llx\n", dev->name, | 122 | pr_debug("%s:%s(): intCtl=0x%016llx\n", dev->name, |
| 124 | __FUNCTION__, interruptFlags); | 123 | __FUNCTION__, interruptFlags); |
| 125 | 124 | ||
| 126 | if (interruptFlags & MIPSNET_INTCTL_TXDONE) { | 125 | if (interruptFlags & MIPSNET_INTCTL_TXDONE) { |
| 127 | pr_debug("%s:%s(): got TXDone\n", | 126 | pr_debug("%s:%s(): got TXDone\n", |
| 128 | dev->name, __FUNCTION__); | 127 | dev->name, __FUNCTION__); |
| 129 | outl(MIPSNET_INTCTL_TXDONE, | 128 | outl(MIPSNET_INTCTL_TXDONE, |
| 130 | mipsnet_reg_address(dev, interruptControl)); | 129 | mipsnet_reg_address(dev, interruptControl)); |
| 131 | // only one packet at a time, we are done. | 130 | /* only one packet at a time, we are done. */ |
| 132 | netif_wake_queue(dev); | 131 | netif_wake_queue(dev); |
| 133 | } else if (interruptFlags & MIPSNET_INTCTL_RXDONE) { | 132 | } else if (interruptFlags & MIPSNET_INTCTL_RXDONE) { |
| 134 | pr_debug("%s:%s(): got RX data\n", | 133 | pr_debug("%s:%s(): got RX data\n", |
| 135 | dev->name, __FUNCTION__); | 134 | dev->name, __FUNCTION__); |
| 136 | mipsnet_get_fromdev(dev, | 135 | mipsnet_get_fromdev(dev, |
| 137 | inl(mipsnet_reg_address(dev, rxDataCount))); | 136 | inl(mipsnet_reg_address(dev, rxDataCount))); |
| 138 | pr_debug("%s:%s(): clearing RX int\n", | 137 | pr_debug("%s:%s(): clearing RX int\n", |
| 139 | dev->name, __FUNCTION__); | 138 | dev->name, __FUNCTION__); |
| 140 | outl(MIPSNET_INTCTL_RXDONE, | 139 | outl(MIPSNET_INTCTL_RXDONE, |
| 141 | mipsnet_reg_address(dev, interruptControl)); | 140 | mipsnet_reg_address(dev, interruptControl)); |
| 142 | 141 | ||
| 143 | } else if (interruptFlags & MIPSNET_INTCTL_TESTBIT) { | 142 | } else if (interruptFlags & MIPSNET_INTCTL_TESTBIT) { |
| 144 | pr_debug("%s:%s(): got test interrupt\n", | 143 | pr_debug("%s:%s(): got test interrupt\n", |
| 145 | dev->name, __FUNCTION__); | 144 | dev->name, __FUNCTION__); |
| 146 | // TESTBIT is cleared on read. | 145 | /* |
| 147 | // And takes effect after a write with 0 | 146 | * TESTBIT is cleared on read. |
| 147 | * And takes effect after a write with 0 | ||
| 148 | */ | ||
| 148 | outl(0, mipsnet_reg_address(dev, interruptControl)); | 149 | outl(0, mipsnet_reg_address(dev, interruptControl)); |
| 149 | } else { | 150 | } else { |
| 150 | pr_debug("%s:%s(): no valid fags 0x%016llx\n", | 151 | pr_debug("%s:%s(): no valid fags 0x%016llx\n", |
| 151 | dev->name, __FUNCTION__, interruptFlags); | 152 | dev->name, __FUNCTION__, interruptFlags); |
| 152 | // Maybe shared IRQ, just ignore, no clearing. | 153 | /* Maybe shared IRQ, just ignore, no clearing. */ |
| 153 | retval = IRQ_NONE; | 154 | retval = IRQ_NONE; |
| 154 | } | 155 | } |
| 155 | 156 | ||
| @@ -159,7 +160,7 @@ static irqreturn_t mipsnet_interrupt(int irq, void *dev_id) | |||
| 159 | retval = IRQ_NONE; | 160 | retval = IRQ_NONE; |
| 160 | } | 161 | } |
| 161 | return retval; | 162 | return retval; |
| 162 | } //mipsnet_interrupt() | 163 | } |
| 163 | 164 | ||
| 164 | static int mipsnet_open(struct net_device *dev) | 165 | static int mipsnet_open(struct net_device *dev) |
| 165 | { | 166 | { |
| @@ -171,18 +172,18 @@ static int mipsnet_open(struct net_device *dev) | |||
| 171 | 172 | ||
| 172 | if (err) { | 173 | if (err) { |
| 173 | pr_debug("%s: %s(): can't get irq %d\n", | 174 | pr_debug("%s: %s(): can't get irq %d\n", |
| 174 | dev->name, __FUNCTION__, dev->irq); | 175 | dev->name, __FUNCTION__, dev->irq); |
| 175 | release_region(dev->base_addr, MIPSNET_IO_EXTENT); | 176 | release_region(dev->base_addr, MIPSNET_IO_EXTENT); |
| 176 | return err; | 177 | return err; |
| 177 | } | 178 | } |
| 178 | 179 | ||
| 179 | pr_debug("%s: %s(): got IO region at 0x%04lx and irq %d for dev.\n", | 180 | pr_debug("%s: %s(): got IO region at 0x%04lx and irq %d for dev.\n", |
| 180 | dev->name, __FUNCTION__, dev->base_addr, dev->irq); | 181 | dev->name, __FUNCTION__, dev->base_addr, dev->irq); |
| 181 | 182 | ||
| 182 | 183 | ||
| 183 | netif_start_queue(dev); | 184 | netif_start_queue(dev); |
| 184 | 185 | ||
| 185 | // test interrupt handler | 186 | /* test interrupt handler */ |
| 186 | outl(MIPSNET_INTCTL_TESTBIT, | 187 | outl(MIPSNET_INTCTL_TESTBIT, |
| 187 | mipsnet_reg_address(dev, interruptControl)); | 188 | mipsnet_reg_address(dev, interruptControl)); |
| 188 | 189 | ||
| @@ -199,8 +200,6 @@ static int mipsnet_close(struct net_device *dev) | |||
| 199 | 200 | ||
| 200 | static void mipsnet_set_mclist(struct net_device *dev) | 201 | static void mipsnet_set_mclist(struct net_device *dev) |
| 201 | { | 202 | { |
| 202 | // we don't do anything | ||
| 203 | return; | ||
| 204 | } | 203 | } |
| 205 | 204 | ||
| 206 | static int __init mipsnet_probe(struct device *dev) | 205 | static int __init mipsnet_probe(struct device *dev) |
| @@ -226,13 +225,13 @@ static int __init mipsnet_probe(struct device *dev) | |||
| 226 | */ | 225 | */ |
| 227 | netdev->base_addr = 0x4200; | 226 | netdev->base_addr = 0x4200; |
| 228 | netdev->irq = MIPS_CPU_IRQ_BASE + MIPSCPU_INT_MB0 + | 227 | netdev->irq = MIPS_CPU_IRQ_BASE + MIPSCPU_INT_MB0 + |
| 229 | inl(mipsnet_reg_address(netdev, interruptInfo)); | 228 | inl(mipsnet_reg_address(netdev, interruptInfo)); |
| 230 | 229 | ||
| 231 | // Get the io region now, get irq on open() | 230 | /* Get the io region now, get irq on open() */ |
| 232 | if (!request_region(netdev->base_addr, MIPSNET_IO_EXTENT, "mipsnet")) { | 231 | if (!request_region(netdev->base_addr, MIPSNET_IO_EXTENT, "mipsnet")) { |
| 233 | pr_debug("%s: %s(): IO region {start: 0x%04lux, len: %d} " | 232 | pr_debug("%s: %s(): IO region {start: 0x%04lux, len: %d} " |
| 234 | "for dev is not availble.\n", netdev->name, | 233 | "for dev is not availble.\n", netdev->name, |
| 235 | __FUNCTION__, netdev->base_addr, MIPSNET_IO_EXTENT); | 234 | __FUNCTION__, netdev->base_addr, MIPSNET_IO_EXTENT); |
| 236 | err = -EBUSY; | 235 | err = -EBUSY; |
| 237 | goto out_free_netdev; | 236 | goto out_free_netdev; |
| 238 | } | 237 | } |
diff --git a/drivers/net/mipsnet.h b/drivers/net/mipsnet.h index 026c732024c9..0132c6714a40 100644 --- a/drivers/net/mipsnet.h +++ b/drivers/net/mipsnet.h | |||
| @@ -9,32 +9,34 @@ | |||
| 9 | /* | 9 | /* |
| 10 | * Id of this Net device, as seen by the core. | 10 | * Id of this Net device, as seen by the core. |
| 11 | */ | 11 | */ |
| 12 | #define MIPS_NET_DEV_ID ((uint64_t) \ | 12 | #define MIPS_NET_DEV_ID ((uint64_t) \ |
| 13 | ((uint64_t)'M'<< 0)| \ | 13 | ((uint64_t) 'M' << 0)| \ |
| 14 | ((uint64_t)'I'<< 8)| \ | 14 | ((uint64_t) 'I' << 8)| \ |
| 15 | ((uint64_t)'P'<<16)| \ | 15 | ((uint64_t) 'P' << 16)| \ |
| 16 | ((uint64_t)'S'<<24)| \ | 16 | ((uint64_t) 'S' << 24)| \ |
| 17 | ((uint64_t)'N'<<32)| \ | 17 | ((uint64_t) 'N' << 32)| \ |
| 18 | ((uint64_t)'E'<<40)| \ | 18 | ((uint64_t) 'E' << 40)| \ |
| 19 | ((uint64_t)'T'<<48)| \ | 19 | ((uint64_t) 'T' << 48)| \ |
| 20 | ((uint64_t)'0'<<56)) | 20 | ((uint64_t) '0' << 56)) |
| 21 | 21 | ||
| 22 | /* | 22 | /* |
| 23 | * Net status/control block as seen by sw in the core. | 23 | * Net status/control block as seen by sw in the core. |
| 24 | * (Why not use bit fields? can't be bothered with cross-platform struct | 24 | * (Why not use bit fields? can't be bothered with cross-platform struct |
| 25 | * packing.) | 25 | * packing.) |
| 26 | */ | 26 | */ |
| 27 | typedef struct _net_control_block { | 27 | struct net_control_block { |
| 28 | /// dev info for probing | 28 | /* |
| 29 | /// reads as MIPSNET%d where %d is some form of version | 29 | * dev info for probing |
| 30 | uint64_t devId; /*0x00 */ | 30 | * reads as MIPSNET%d where %d is some form of version |
| 31 | */ | ||
| 32 | uint64_t devId; /* 0x00 */ | ||
| 31 | 33 | ||
| 32 | /* | 34 | /* |
| 33 | * read only busy flag. | 35 | * read only busy flag. |
| 34 | * Set and cleared by the Net Device to indicate that an rx or a tx | 36 | * Set and cleared by the Net Device to indicate that an rx or a tx |
| 35 | * is in progress. | 37 | * is in progress. |
| 36 | */ | 38 | */ |
| 37 | uint32_t busy; /*0x08 */ | 39 | uint32_t busy; /* 0x08 */ |
| 38 | 40 | ||
| 39 | /* | 41 | /* |
| 40 | * Set by the Net Device. | 42 | * Set by the Net Device. |
| @@ -43,16 +45,16 @@ typedef struct _net_control_block { | |||
| 43 | * rxDataBuffer. The value will decrease till 0 until all the data | 45 | * rxDataBuffer. The value will decrease till 0 until all the data |
| 44 | * from rxDataBuffer has been read. | 46 | * from rxDataBuffer has been read. |
| 45 | */ | 47 | */ |
| 46 | uint32_t rxDataCount; /*0x0c */ | 48 | uint32_t rxDataCount; /* 0x0c */ |
| 47 | #define MIPSNET_MAX_RXTX_DATACOUNT (1<<16) | 49 | #define MIPSNET_MAX_RXTX_DATACOUNT (1<<16) |
| 48 | 50 | ||
| 49 | /* | 51 | /* |
| 50 | * Settable from the MIPS core, cleared by the Net Device. | 52 | * Settable from the MIPS core, cleared by the Net Device. The core |
| 51 | * The core should set the number of bytes it wants to send, | 53 | * should set the number of bytes it wants to send, then it should |
| 52 | * then it should write those bytes of data to txDataBuffer. | 54 | * write those bytes of data to txDataBuffer. The device will clear |
| 53 | * The device will clear txDataCount has been processed (not necessarily sent). | 55 | * txDataCount has been processed (not necessarily sent). |
| 54 | */ | 56 | */ |
| 55 | uint32_t txDataCount; /*0x10 */ | 57 | uint32_t txDataCount; /* 0x10 */ |
| 56 | 58 | ||
| 57 | /* | 59 | /* |
| 58 | * Interrupt control | 60 | * Interrupt control |
| @@ -69,39 +71,42 @@ typedef struct _net_control_block { | |||
| 69 | * To clear the test interrupt, write 0 to this register. | 71 | * To clear the test interrupt, write 0 to this register. |
| 70 | */ | 72 | */ |
| 71 | uint32_t interruptControl; /*0x14 */ | 73 | uint32_t interruptControl; /*0x14 */ |
| 72 | #define MIPSNET_INTCTL_TXDONE ((uint32_t)(1<< 0)) | 74 | #define MIPSNET_INTCTL_TXDONE ((uint32_t)(1 << 0)) |
| 73 | #define MIPSNET_INTCTL_RXDONE ((uint32_t)(1<< 1)) | 75 | #define MIPSNET_INTCTL_RXDONE ((uint32_t)(1 << 1)) |
| 74 | #define MIPSNET_INTCTL_TESTBIT ((uint32_t)(1<<31)) | 76 | #define MIPSNET_INTCTL_TESTBIT ((uint32_t)(1 << 31)) |
| 75 | #define MIPSNET_INTCTL_ALLSOURCES (MIPSNET_INTCTL_TXDONE|MIPSNET_INTCTL_RXDONE|MIPSNET_INTCTL_TESTBIT) | 77 | #define MIPSNET_INTCTL_ALLSOURCES (MIPSNET_INTCTL_TXDONE | \ |
| 78 | MIPSNET_INTCTL_RXDONE | \ | ||
| 79 | MIPSNET_INTCTL_TESTBIT) | ||
| 76 | 80 | ||
| 77 | /* | 81 | /* |
| 78 | * Readonly core-specific interrupt info for the device to signal the core. | 82 | * Readonly core-specific interrupt info for the device to signal the |
| 79 | * The meaning of the contents of this field might change. | 83 | * core. The meaning of the contents of this field might change. |
| 80 | */ | 84 | * |
| 81 | /*###\todo: the whole memIntf interrupt scheme is messy: the device should have | 85 | * TODO: the whole memIntf interrupt scheme is messy: the device should |
| 82 | * no control what so ever of what VPE/register set is being used. | 86 | * have no control what so ever of what VPE/register set is being |
| 83 | * The MemIntf should only expose interrupt lines, and something in the | 87 | * used. The MemIntf should only expose interrupt lines, and |
| 84 | * config should be responsible for the line<->core/vpe bindings. | 88 | * something in the config should be responsible for the |
| 89 | * line<->core/vpe bindings. | ||
| 85 | */ | 90 | */ |
| 86 | uint32_t interruptInfo; /*0x18 */ | 91 | uint32_t interruptInfo; /* 0x18 */ |
| 87 | 92 | ||
| 88 | /* | 93 | /* |
| 89 | * This is where the received data is read out. | 94 | * This is where the received data is read out. |
| 90 | * There is more data to read until rxDataReady is 0. | 95 | * There is more data to read until rxDataReady is 0. |
| 91 | * Only 1 byte at this regs offset is used. | 96 | * Only 1 byte at this regs offset is used. |
| 92 | */ | 97 | */ |
| 93 | uint32_t rxDataBuffer; /*0x1c */ | 98 | uint32_t rxDataBuffer; /* 0x1c */ |
| 94 | 99 | ||
| 95 | /* | 100 | /* |
| 96 | * This is where the data to transmit is written. | 101 | * This is where the data to transmit is written. Data should be |
| 97 | * Data should be written for the amount specified in the txDataCount register. | 102 | * written for the amount specified in the txDataCount register. Only |
| 98 | * Only 1 byte at this regs offset is used. | 103 | * 1 byte at this regs offset is used. |
| 99 | */ | 104 | */ |
| 100 | uint32_t txDataBuffer; /*0x20 */ | 105 | uint32_t txDataBuffer; /* 0x20 */ |
| 101 | } MIPS_T_NetControl; | 106 | }; |
| 102 | 107 | ||
| 103 | #define MIPSNET_IO_EXTENT 0x40 /* being generous */ | 108 | #define MIPSNET_IO_EXTENT 0x40 /* being generous */ |
| 104 | 109 | ||
| 105 | #define field_offset(field) ((int)&((MIPS_T_NetControl*)(0))->field) | 110 | #define field_offset(field) (offsetof(struct net_control_block, field)) |
| 106 | 111 | ||
| 107 | #endif /* __MIPSNET_H */ | 112 | #endif /* __MIPSNET_H */ |
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index e8afa101433e..64c8151f2004 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c | |||
| @@ -75,7 +75,7 @@ | |||
| 75 | #include "myri10ge_mcp.h" | 75 | #include "myri10ge_mcp.h" |
| 76 | #include "myri10ge_mcp_gen_header.h" | 76 | #include "myri10ge_mcp_gen_header.h" |
| 77 | 77 | ||
| 78 | #define MYRI10GE_VERSION_STR "1.3.2-1.269" | 78 | #define MYRI10GE_VERSION_STR "1.3.2-1.287" |
| 79 | 79 | ||
| 80 | MODULE_DESCRIPTION("Myricom 10G driver (10GbE)"); | 80 | MODULE_DESCRIPTION("Myricom 10G driver (10GbE)"); |
| 81 | MODULE_AUTHOR("Maintainer: help@myri.com"); | 81 | MODULE_AUTHOR("Maintainer: help@myri.com"); |
| @@ -214,6 +214,8 @@ struct myri10ge_priv { | |||
| 214 | unsigned long serial_number; | 214 | unsigned long serial_number; |
| 215 | int vendor_specific_offset; | 215 | int vendor_specific_offset; |
| 216 | int fw_multicast_support; | 216 | int fw_multicast_support; |
| 217 | unsigned long features; | ||
| 218 | u32 max_tso6; | ||
| 217 | u32 read_dma; | 219 | u32 read_dma; |
| 218 | u32 write_dma; | 220 | u32 write_dma; |
| 219 | u32 read_write_dma; | 221 | u32 read_write_dma; |
| @@ -311,6 +313,7 @@ MODULE_PARM_DESC(myri10ge_wcfifo, "Enable WC Fifo when WC is enabled\n"); | |||
| 311 | #define myri10ge_pio_copy(to,from,size) __iowrite64_copy(to,from,size/8) | 313 | #define myri10ge_pio_copy(to,from,size) __iowrite64_copy(to,from,size/8) |
| 312 | 314 | ||
| 313 | static void myri10ge_set_multicast_list(struct net_device *dev); | 315 | static void myri10ge_set_multicast_list(struct net_device *dev); |
| 316 | static int myri10ge_sw_tso(struct sk_buff *skb, struct net_device *dev); | ||
| 314 | 317 | ||
| 315 | static inline void put_be32(__be32 val, __be32 __iomem * p) | 318 | static inline void put_be32(__be32 val, __be32 __iomem * p) |
| 316 | { | 319 | { |
| @@ -612,6 +615,7 @@ static int myri10ge_load_firmware(struct myri10ge_priv *mgp) | |||
| 612 | __be32 buf[16]; | 615 | __be32 buf[16]; |
| 613 | u32 dma_low, dma_high, size; | 616 | u32 dma_low, dma_high, size; |
| 614 | int status, i; | 617 | int status, i; |
| 618 | struct myri10ge_cmd cmd; | ||
| 615 | 619 | ||
| 616 | size = 0; | 620 | size = 0; |
| 617 | status = myri10ge_load_hotplug_firmware(mgp, &size); | 621 | status = myri10ge_load_hotplug_firmware(mgp, &size); |
| @@ -688,6 +692,14 @@ static int myri10ge_load_firmware(struct myri10ge_priv *mgp) | |||
| 688 | dev_info(&mgp->pdev->dev, "handoff confirmed\n"); | 692 | dev_info(&mgp->pdev->dev, "handoff confirmed\n"); |
| 689 | myri10ge_dummy_rdma(mgp, 1); | 693 | myri10ge_dummy_rdma(mgp, 1); |
| 690 | 694 | ||
| 695 | /* probe for IPv6 TSO support */ | ||
| 696 | mgp->features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_TSO; | ||
| 697 | status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_MAX_TSO6_HDR_SIZE, | ||
| 698 | &cmd, 0); | ||
| 699 | if (status == 0) { | ||
| 700 | mgp->max_tso6 = cmd.data0; | ||
| 701 | mgp->features |= NETIF_F_TSO6; | ||
| 702 | } | ||
| 691 | return 0; | 703 | return 0; |
| 692 | } | 704 | } |
| 693 | 705 | ||
| @@ -1047,7 +1059,8 @@ myri10ge_rx_done(struct myri10ge_priv *mgp, struct myri10ge_rx_buf *rx, | |||
| 1047 | 1059 | ||
| 1048 | hlen = MYRI10GE_HLEN > len ? len : MYRI10GE_HLEN; | 1060 | hlen = MYRI10GE_HLEN > len ? len : MYRI10GE_HLEN; |
| 1049 | 1061 | ||
| 1050 | /* allocate an skb to attach the page(s) to. */ | 1062 | /* allocate an skb to attach the page(s) to. This is done |
| 1063 | * after trying LRO, so as to avoid skb allocation overheads */ | ||
| 1051 | 1064 | ||
| 1052 | skb = netdev_alloc_skb(dev, MYRI10GE_HLEN + 16); | 1065 | skb = netdev_alloc_skb(dev, MYRI10GE_HLEN + 16); |
| 1053 | if (unlikely(skb == NULL)) { | 1066 | if (unlikely(skb == NULL)) { |
| @@ -1217,7 +1230,8 @@ static inline void myri10ge_check_statblock(struct myri10ge_priv *mgp) | |||
| 1217 | 1230 | ||
| 1218 | static int myri10ge_poll(struct napi_struct *napi, int budget) | 1231 | static int myri10ge_poll(struct napi_struct *napi, int budget) |
| 1219 | { | 1232 | { |
| 1220 | struct myri10ge_priv *mgp = container_of(napi, struct myri10ge_priv, napi); | 1233 | struct myri10ge_priv *mgp = |
| 1234 | container_of(napi, struct myri10ge_priv, napi); | ||
| 1221 | struct net_device *netdev = mgp->dev; | 1235 | struct net_device *netdev = mgp->dev; |
| 1222 | struct myri10ge_rx_done *rx_done = &mgp->rx_done; | 1236 | struct myri10ge_rx_done *rx_done = &mgp->rx_done; |
| 1223 | int work_done; | 1237 | int work_done; |
| @@ -1382,6 +1396,18 @@ static int myri10ge_set_rx_csum(struct net_device *netdev, u32 csum_enabled) | |||
| 1382 | return 0; | 1396 | return 0; |
| 1383 | } | 1397 | } |
| 1384 | 1398 | ||
| 1399 | static int myri10ge_set_tso(struct net_device *netdev, u32 tso_enabled) | ||
| 1400 | { | ||
| 1401 | struct myri10ge_priv *mgp = netdev_priv(netdev); | ||
| 1402 | unsigned long flags = mgp->features & (NETIF_F_TSO6 | NETIF_F_TSO); | ||
| 1403 | |||
| 1404 | if (tso_enabled) | ||
| 1405 | netdev->features |= flags; | ||
| 1406 | else | ||
| 1407 | netdev->features &= ~flags; | ||
| 1408 | return 0; | ||
| 1409 | } | ||
| 1410 | |||
| 1385 | static const char myri10ge_gstrings_stats[][ETH_GSTRING_LEN] = { | 1411 | static const char myri10ge_gstrings_stats[][ETH_GSTRING_LEN] = { |
| 1386 | "rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors", | 1412 | "rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors", |
| 1387 | "tx_errors", "rx_dropped", "tx_dropped", "multicast", "collisions", | 1413 | "tx_errors", "rx_dropped", "tx_dropped", "multicast", "collisions", |
| @@ -1506,7 +1532,7 @@ static const struct ethtool_ops myri10ge_ethtool_ops = { | |||
| 1506 | .set_rx_csum = myri10ge_set_rx_csum, | 1532 | .set_rx_csum = myri10ge_set_rx_csum, |
| 1507 | .set_tx_csum = ethtool_op_set_tx_hw_csum, | 1533 | .set_tx_csum = ethtool_op_set_tx_hw_csum, |
| 1508 | .set_sg = ethtool_op_set_sg, | 1534 | .set_sg = ethtool_op_set_sg, |
| 1509 | .set_tso = ethtool_op_set_tso, | 1535 | .set_tso = myri10ge_set_tso, |
| 1510 | .get_link = ethtool_op_get_link, | 1536 | .get_link = ethtool_op_get_link, |
| 1511 | .get_strings = myri10ge_get_strings, | 1537 | .get_strings = myri10ge_get_strings, |
| 1512 | .get_sset_count = myri10ge_get_sset_count, | 1538 | .get_sset_count = myri10ge_get_sset_count, |
| @@ -2164,7 +2190,8 @@ again: | |||
| 2164 | pseudo_hdr_offset = cksum_offset + skb->csum_offset; | 2190 | pseudo_hdr_offset = cksum_offset + skb->csum_offset; |
| 2165 | /* If the headers are excessively large, then we must | 2191 | /* If the headers are excessively large, then we must |
| 2166 | * fall back to a software checksum */ | 2192 | * fall back to a software checksum */ |
| 2167 | if (unlikely(cksum_offset > 255 || pseudo_hdr_offset > 127)) { | 2193 | if (unlikely(!mss && (cksum_offset > 255 || |
| 2194 | pseudo_hdr_offset > 127))) { | ||
| 2168 | if (skb_checksum_help(skb)) | 2195 | if (skb_checksum_help(skb)) |
| 2169 | goto drop; | 2196 | goto drop; |
| 2170 | cksum_offset = 0; | 2197 | cksum_offset = 0; |
| @@ -2184,9 +2211,18 @@ again: | |||
| 2184 | /* negative cum_len signifies to the | 2211 | /* negative cum_len signifies to the |
| 2185 | * send loop that we are still in the | 2212 | * send loop that we are still in the |
| 2186 | * header portion of the TSO packet. | 2213 | * header portion of the TSO packet. |
| 2187 | * TSO header must be at most 134 bytes long */ | 2214 | * TSO header can be at most 1KB long */ |
| 2188 | cum_len = -(skb_transport_offset(skb) + tcp_hdrlen(skb)); | 2215 | cum_len = -(skb_transport_offset(skb) + tcp_hdrlen(skb)); |
| 2189 | 2216 | ||
| 2217 | /* for IPv6 TSO, the checksum offset stores the | ||
| 2218 | * TCP header length, to save the firmware from | ||
| 2219 | * the need to parse the headers */ | ||
| 2220 | if (skb_is_gso_v6(skb)) { | ||
| 2221 | cksum_offset = tcp_hdrlen(skb); | ||
| 2222 | /* Can only handle headers <= max_tso6 long */ | ||
| 2223 | if (unlikely(-cum_len > mgp->max_tso6)) | ||
| 2224 | return myri10ge_sw_tso(skb, dev); | ||
| 2225 | } | ||
| 2190 | /* for TSO, pseudo_hdr_offset holds mss. | 2226 | /* for TSO, pseudo_hdr_offset holds mss. |
| 2191 | * The firmware figures out where to put | 2227 | * The firmware figures out where to put |
| 2192 | * the checksum by parsing the header. */ | 2228 | * the checksum by parsing the header. */ |
| @@ -2301,10 +2337,12 @@ again: | |||
| 2301 | req++; | 2337 | req++; |
| 2302 | count++; | 2338 | count++; |
| 2303 | rdma_count++; | 2339 | rdma_count++; |
| 2304 | if (unlikely(cksum_offset > seglen)) | 2340 | if (cksum_offset != 0 && !(mss && skb_is_gso_v6(skb))) { |
| 2305 | cksum_offset -= seglen; | 2341 | if (unlikely(cksum_offset > seglen)) |
| 2306 | else | 2342 | cksum_offset -= seglen; |
| 2307 | cksum_offset = 0; | 2343 | else |
| 2344 | cksum_offset = 0; | ||
| 2345 | } | ||
| 2308 | } | 2346 | } |
| 2309 | if (frag_idx == frag_cnt) | 2347 | if (frag_idx == frag_cnt) |
| 2310 | break; | 2348 | break; |
| @@ -2387,6 +2425,41 @@ drop: | |||
| 2387 | 2425 | ||
| 2388 | } | 2426 | } |
| 2389 | 2427 | ||
| 2428 | static int myri10ge_sw_tso(struct sk_buff *skb, struct net_device *dev) | ||
| 2429 | { | ||
| 2430 | struct sk_buff *segs, *curr; | ||
| 2431 | struct myri10ge_priv *mgp = dev->priv; | ||
| 2432 | int status; | ||
| 2433 | |||
| 2434 | segs = skb_gso_segment(skb, dev->features & ~NETIF_F_TSO6); | ||
| 2435 | if (unlikely(IS_ERR(segs))) | ||
| 2436 | goto drop; | ||
| 2437 | |||
| 2438 | while (segs) { | ||
| 2439 | curr = segs; | ||
| 2440 | segs = segs->next; | ||
| 2441 | curr->next = NULL; | ||
| 2442 | status = myri10ge_xmit(curr, dev); | ||
| 2443 | if (status != 0) { | ||
| 2444 | dev_kfree_skb_any(curr); | ||
| 2445 | if (segs != NULL) { | ||
| 2446 | curr = segs; | ||
| 2447 | segs = segs->next; | ||
| 2448 | curr->next = NULL; | ||
| 2449 | dev_kfree_skb_any(segs); | ||
| 2450 | } | ||
| 2451 | goto drop; | ||
| 2452 | } | ||
| 2453 | } | ||
| 2454 | dev_kfree_skb_any(skb); | ||
| 2455 | return 0; | ||
| 2456 | |||
| 2457 | drop: | ||
| 2458 | dev_kfree_skb_any(skb); | ||
| 2459 | mgp->stats.tx_dropped += 1; | ||
| 2460 | return 0; | ||
| 2461 | } | ||
| 2462 | |||
| 2390 | static struct net_device_stats *myri10ge_get_stats(struct net_device *dev) | 2463 | static struct net_device_stats *myri10ge_get_stats(struct net_device *dev) |
| 2391 | { | 2464 | { |
| 2392 | struct myri10ge_priv *mgp = netdev_priv(dev); | 2465 | struct myri10ge_priv *mgp = netdev_priv(dev); |
| @@ -2706,7 +2779,6 @@ static void myri10ge_select_firmware(struct myri10ge_priv *mgp) | |||
| 2706 | } | 2779 | } |
| 2707 | 2780 | ||
| 2708 | #ifdef CONFIG_PM | 2781 | #ifdef CONFIG_PM |
| 2709 | |||
| 2710 | static int myri10ge_suspend(struct pci_dev *pdev, pm_message_t state) | 2782 | static int myri10ge_suspend(struct pci_dev *pdev, pm_message_t state) |
| 2711 | { | 2783 | { |
| 2712 | struct myri10ge_priv *mgp; | 2784 | struct myri10ge_priv *mgp; |
| @@ -2787,7 +2859,6 @@ abort_with_enabled: | |||
| 2787 | return -EIO; | 2859 | return -EIO; |
| 2788 | 2860 | ||
| 2789 | } | 2861 | } |
| 2790 | |||
| 2791 | #endif /* CONFIG_PM */ | 2862 | #endif /* CONFIG_PM */ |
| 2792 | 2863 | ||
| 2793 | static u32 myri10ge_read_reboot(struct myri10ge_priv *mgp) | 2864 | static u32 myri10ge_read_reboot(struct myri10ge_priv *mgp) |
| @@ -2954,8 +3025,7 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
| 2954 | 3025 | ||
| 2955 | mgp = netdev_priv(netdev); | 3026 | mgp = netdev_priv(netdev); |
| 2956 | mgp->dev = netdev; | 3027 | mgp->dev = netdev; |
| 2957 | netif_napi_add(netdev, &mgp->napi, | 3028 | netif_napi_add(netdev, &mgp->napi, myri10ge_poll, myri10ge_napi_weight); |
| 2958 | myri10ge_poll, myri10ge_napi_weight); | ||
| 2959 | mgp->pdev = pdev; | 3029 | mgp->pdev = pdev; |
| 2960 | mgp->csum_flag = MXGEFW_FLAGS_CKSUM; | 3030 | mgp->csum_flag = MXGEFW_FLAGS_CKSUM; |
| 2961 | mgp->pause = myri10ge_flow_control; | 3031 | mgp->pause = myri10ge_flow_control; |
| @@ -3077,7 +3147,7 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
| 3077 | netdev->change_mtu = myri10ge_change_mtu; | 3147 | netdev->change_mtu = myri10ge_change_mtu; |
| 3078 | netdev->set_multicast_list = myri10ge_set_multicast_list; | 3148 | netdev->set_multicast_list = myri10ge_set_multicast_list; |
| 3079 | netdev->set_mac_address = myri10ge_set_mac_address; | 3149 | netdev->set_mac_address = myri10ge_set_mac_address; |
| 3080 | netdev->features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_TSO; | 3150 | netdev->features = mgp->features; |
| 3081 | if (dac_enabled) | 3151 | if (dac_enabled) |
| 3082 | netdev->features |= NETIF_F_HIGHDMA; | 3152 | netdev->features |= NETIF_F_HIGHDMA; |
| 3083 | 3153 | ||
diff --git a/drivers/net/myri10ge/myri10ge_mcp.h b/drivers/net/myri10ge/myri10ge_mcp.h index a1d2a22296a9..58e57178c563 100644 --- a/drivers/net/myri10ge/myri10ge_mcp.h +++ b/drivers/net/myri10ge/myri10ge_mcp.h | |||
| @@ -10,7 +10,7 @@ struct mcp_dma_addr { | |||
| 10 | __be32 low; | 10 | __be32 low; |
| 11 | }; | 11 | }; |
| 12 | 12 | ||
| 13 | /* 4 Bytes */ | 13 | /* 4 Bytes. 8 Bytes for NDIS drivers. */ |
| 14 | struct mcp_slot { | 14 | struct mcp_slot { |
| 15 | __sum16 checksum; | 15 | __sum16 checksum; |
| 16 | __be16 length; | 16 | __be16 length; |
| @@ -205,8 +205,87 @@ enum myri10ge_mcp_cmd_type { | |||
| 205 | /* same than DMA_TEST (same args) but abort with UNALIGNED on unaligned | 205 | /* same than DMA_TEST (same args) but abort with UNALIGNED on unaligned |
| 206 | * chipset */ | 206 | * chipset */ |
| 207 | 207 | ||
| 208 | MXGEFW_CMD_UNALIGNED_STATUS | 208 | MXGEFW_CMD_UNALIGNED_STATUS, |
| 209 | /* return data = boolean, true if the chipset is known to be unaligned */ | 209 | /* return data = boolean, true if the chipset is known to be unaligned */ |
| 210 | |||
| 211 | MXGEFW_CMD_ALWAYS_USE_N_BIG_BUFFERS, | ||
| 212 | /* data0 = number of big buffers to use. It must be 0 or a power of 2. | ||
| 213 | * 0 indicates that the NIC consumes as many buffers as they are required | ||
| 214 | * for packet. This is the default behavior. | ||
| 215 | * A power of 2 number indicates that the NIC always uses the specified | ||
| 216 | * number of buffers for each big receive packet. | ||
| 217 | * It is up to the driver to ensure that this value is big enough for | ||
| 218 | * the NIC to be able to receive maximum-sized packets. | ||
| 219 | */ | ||
| 220 | |||
| 221 | MXGEFW_CMD_GET_MAX_RSS_QUEUES, | ||
| 222 | MXGEFW_CMD_ENABLE_RSS_QUEUES, | ||
| 223 | /* data0 = number of slices n (0, 1, ..., n-1) to enable | ||
| 224 | * data1 = interrupt mode. 0=share one INTx/MSI, 1=use one MSI-X per queue. | ||
| 225 | * If all queues share one interrupt, the driver must have set | ||
| 226 | * RSS_SHARED_INTERRUPT_DMA before enabling queues. | ||
| 227 | */ | ||
| 228 | MXGEFW_CMD_GET_RSS_SHARED_INTERRUPT_MASK_OFFSET, | ||
| 229 | MXGEFW_CMD_SET_RSS_SHARED_INTERRUPT_DMA, | ||
| 230 | /* data0, data1 = bus address lsw, msw */ | ||
| 231 | MXGEFW_CMD_GET_RSS_TABLE_OFFSET, | ||
| 232 | /* get the offset of the indirection table */ | ||
| 233 | MXGEFW_CMD_SET_RSS_TABLE_SIZE, | ||
| 234 | /* set the size of the indirection table */ | ||
| 235 | MXGEFW_CMD_GET_RSS_KEY_OFFSET, | ||
| 236 | /* get the offset of the secret key */ | ||
| 237 | MXGEFW_CMD_RSS_KEY_UPDATED, | ||
| 238 | /* tell nic that the secret key's been updated */ | ||
| 239 | MXGEFW_CMD_SET_RSS_ENABLE, | ||
| 240 | /* data0 = enable/disable rss | ||
| 241 | * 0: disable rss. nic does not distribute receive packets. | ||
| 242 | * 1: enable rss. nic distributes receive packets among queues. | ||
| 243 | * data1 = hash type | ||
| 244 | * 1: IPV4 | ||
| 245 | * 2: TCP_IPV4 | ||
| 246 | * 3: IPV4 | TCP_IPV4 | ||
| 247 | */ | ||
| 248 | |||
| 249 | MXGEFW_CMD_GET_MAX_TSO6_HDR_SIZE, | ||
| 250 | /* Return data = the max. size of the entire headers of a IPv6 TSO packet. | ||
| 251 | * If the header size of a IPv6 TSO packet is larger than the specified | ||
| 252 | * value, then the driver must not use TSO. | ||
| 253 | * This size restriction only applies to IPv6 TSO. | ||
| 254 | * For IPv4 TSO, the maximum size of the headers is fixed, and the NIC | ||
| 255 | * always has enough header buffer to store maximum-sized headers. | ||
| 256 | */ | ||
| 257 | |||
| 258 | MXGEFW_CMD_SET_TSO_MODE, | ||
| 259 | /* data0 = TSO mode. | ||
| 260 | * 0: Linux/FreeBSD style (NIC default) | ||
| 261 | * 1: NDIS/NetBSD style | ||
| 262 | */ | ||
| 263 | |||
| 264 | MXGEFW_CMD_MDIO_READ, | ||
| 265 | /* data0 = dev_addr (PMA/PMD or PCS ...), data1 = register/addr */ | ||
| 266 | MXGEFW_CMD_MDIO_WRITE, | ||
| 267 | /* data0 = dev_addr, data1 = register/addr, data2 = value */ | ||
| 268 | |||
| 269 | MXGEFW_CMD_XFP_I2C_READ, | ||
| 270 | /* Starts to get a fresh copy of one byte or of the whole xfp i2c table, the | ||
| 271 | * obtained data is cached inside the xaui-xfi chip : | ||
| 272 | * data0 : "all" flag : 0 => get one byte, 1=> get 256 bytes, | ||
| 273 | * data1 : if (data0 == 0): index of byte to refresh [ not used otherwise ] | ||
| 274 | * The operation might take ~1ms for a single byte or ~65ms when refreshing all 256 bytes | ||
| 275 | * During the i2c operation, MXGEFW_CMD_XFP_I2C_READ or MXGEFW_CMD_XFP_BYTE attempts | ||
| 276 | * will return MXGEFW_CMD_ERROR_BUSY | ||
| 277 | */ | ||
| 278 | MXGEFW_CMD_XFP_BYTE, | ||
| 279 | /* Return the last obtained copy of a given byte in the xfp i2c table | ||
| 280 | * (copy cached during the last relevant MXGEFW_CMD_XFP_I2C_READ) | ||
| 281 | * data0 : index of the desired table entry | ||
| 282 | * Return data = the byte stored at the requested index in the table | ||
| 283 | */ | ||
| 284 | |||
| 285 | MXGEFW_CMD_GET_VPUMP_OFFSET, | ||
| 286 | /* Return data = NIC memory offset of mcp_vpump_public_global */ | ||
| 287 | MXGEFW_CMD_RESET_VPUMP, | ||
| 288 | /* Resets the VPUMP state */ | ||
| 210 | }; | 289 | }; |
| 211 | 290 | ||
| 212 | enum myri10ge_mcp_cmd_status { | 291 | enum myri10ge_mcp_cmd_status { |
| @@ -220,7 +299,10 @@ enum myri10ge_mcp_cmd_status { | |||
| 220 | MXGEFW_CMD_ERROR_BAD_PORT, | 299 | MXGEFW_CMD_ERROR_BAD_PORT, |
| 221 | MXGEFW_CMD_ERROR_RESOURCES, | 300 | MXGEFW_CMD_ERROR_RESOURCES, |
| 222 | MXGEFW_CMD_ERROR_MULTICAST, | 301 | MXGEFW_CMD_ERROR_MULTICAST, |
| 223 | MXGEFW_CMD_ERROR_UNALIGNED | 302 | MXGEFW_CMD_ERROR_UNALIGNED, |
| 303 | MXGEFW_CMD_ERROR_NO_MDIO, | ||
| 304 | MXGEFW_CMD_ERROR_XFP_FAILURE, | ||
| 305 | MXGEFW_CMD_ERROR_XFP_ABSENT | ||
| 224 | }; | 306 | }; |
| 225 | 307 | ||
| 226 | #define MXGEFW_OLD_IRQ_DATA_LEN 40 | 308 | #define MXGEFW_OLD_IRQ_DATA_LEN 40 |
diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index 527f9dcc7f69..50e1ec67ef9c 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c | |||
| @@ -1576,7 +1576,7 @@ static int netdev_open(struct net_device *dev) | |||
| 1576 | 1576 | ||
| 1577 | /* Set the timer to check for link beat. */ | 1577 | /* Set the timer to check for link beat. */ |
| 1578 | init_timer(&np->timer); | 1578 | init_timer(&np->timer); |
| 1579 | np->timer.expires = jiffies + NATSEMI_TIMER_FREQ; | 1579 | np->timer.expires = round_jiffies(jiffies + NATSEMI_TIMER_FREQ); |
| 1580 | np->timer.data = (unsigned long)dev; | 1580 | np->timer.data = (unsigned long)dev; |
| 1581 | np->timer.function = &netdev_timer; /* timer handler */ | 1581 | np->timer.function = &netdev_timer; /* timer handler */ |
| 1582 | add_timer(&np->timer); | 1582 | add_timer(&np->timer); |
| @@ -1856,7 +1856,11 @@ static void netdev_timer(unsigned long data) | |||
| 1856 | next_tick = 1; | 1856 | next_tick = 1; |
| 1857 | } | 1857 | } |
| 1858 | } | 1858 | } |
| 1859 | mod_timer(&np->timer, jiffies + next_tick); | 1859 | |
| 1860 | if (next_tick > 1) | ||
| 1861 | mod_timer(&np->timer, round_jiffies(jiffies + next_tick)); | ||
| 1862 | else | ||
| 1863 | mod_timer(&np->timer, jiffies + next_tick); | ||
| 1860 | } | 1864 | } |
| 1861 | 1865 | ||
| 1862 | static void dump_ring(struct net_device *dev) | 1866 | static void dump_ring(struct net_device *dev) |
| @@ -3310,13 +3314,19 @@ static int natsemi_resume (struct pci_dev *pdev) | |||
| 3310 | { | 3314 | { |
| 3311 | struct net_device *dev = pci_get_drvdata (pdev); | 3315 | struct net_device *dev = pci_get_drvdata (pdev); |
| 3312 | struct netdev_private *np = netdev_priv(dev); | 3316 | struct netdev_private *np = netdev_priv(dev); |
| 3317 | int ret = 0; | ||
| 3313 | 3318 | ||
| 3314 | rtnl_lock(); | 3319 | rtnl_lock(); |
| 3315 | if (netif_device_present(dev)) | 3320 | if (netif_device_present(dev)) |
| 3316 | goto out; | 3321 | goto out; |
| 3317 | if (netif_running(dev)) { | 3322 | if (netif_running(dev)) { |
| 3318 | BUG_ON(!np->hands_off); | 3323 | BUG_ON(!np->hands_off); |
| 3319 | pci_enable_device(pdev); | 3324 | ret = pci_enable_device(pdev); |
| 3325 | if (ret < 0) { | ||
| 3326 | dev_err(&pdev->dev, | ||
| 3327 | "pci_enable_device() failed: %d\n", ret); | ||
| 3328 | goto out; | ||
| 3329 | } | ||
| 3320 | /* pci_power_on(pdev); */ | 3330 | /* pci_power_on(pdev); */ |
| 3321 | 3331 | ||
| 3322 | napi_enable(&np->napi); | 3332 | napi_enable(&np->napi); |
| @@ -3331,12 +3341,12 @@ static int natsemi_resume (struct pci_dev *pdev) | |||
| 3331 | spin_unlock_irq(&np->lock); | 3341 | spin_unlock_irq(&np->lock); |
| 3332 | enable_irq(dev->irq); | 3342 | enable_irq(dev->irq); |
| 3333 | 3343 | ||
| 3334 | mod_timer(&np->timer, jiffies + 1*HZ); | 3344 | mod_timer(&np->timer, round_jiffies(jiffies + 1*HZ)); |
| 3335 | } | 3345 | } |
| 3336 | netif_device_attach(dev); | 3346 | netif_device_attach(dev); |
| 3337 | out: | 3347 | out: |
| 3338 | rtnl_unlock(); | 3348 | rtnl_unlock(); |
| 3339 | return 0; | 3349 | return ret; |
| 3340 | } | 3350 | } |
| 3341 | 3351 | ||
| 3342 | #endif /* CONFIG_PM */ | 3352 | #endif /* CONFIG_PM */ |
diff --git a/drivers/net/ne-h8300.c b/drivers/net/ne-h8300.c index 368f2560856d..fbc7531d3c7d 100644 --- a/drivers/net/ne-h8300.c +++ b/drivers/net/ne-h8300.c | |||
| @@ -93,7 +93,7 @@ static int __init init_reg_offset(struct net_device *dev,unsigned long base_addr | |||
| 93 | bus_width = *(volatile unsigned char *)ABWCR; | 93 | bus_width = *(volatile unsigned char *)ABWCR; |
| 94 | bus_width &= 1 << ((base_addr >> 21) & 7); | 94 | bus_width &= 1 << ((base_addr >> 21) & 7); |
| 95 | 95 | ||
| 96 | for (i = 0; i < sizeof(reg_offset) / sizeof(u32); i++) | 96 | for (i = 0; i < ARRAY_SIZE(reg_offset); i++) |
| 97 | if (bus_width == 0) | 97 | if (bus_width == 0) |
| 98 | reg_offset[i] = i * 2 + 1; | 98 | reg_offset[i] = i * 2 + 1; |
| 99 | else | 99 | else |
| @@ -115,7 +115,7 @@ static int h8300_ne_irq[] = {EXT_IRQ5}; | |||
| 115 | 115 | ||
| 116 | static inline int init_dev(struct net_device *dev) | 116 | static inline int init_dev(struct net_device *dev) |
| 117 | { | 117 | { |
| 118 | if (h8300_ne_count < (sizeof(h8300_ne_base) / sizeof(unsigned long))) { | 118 | if (h8300_ne_count < ARRAY_SIZE(h8300_ne_base)) { |
| 119 | dev->base_addr = h8300_ne_base[h8300_ne_count]; | 119 | dev->base_addr = h8300_ne_base[h8300_ne_count]; |
| 120 | dev->irq = h8300_ne_irq[h8300_ne_count]; | 120 | dev->irq = h8300_ne_irq[h8300_ne_count]; |
| 121 | h8300_ne_count++; | 121 | h8300_ne_count++; |
diff --git a/drivers/net/saa9730.c b/drivers/net/saa9730.c index 14361e885415..c65199df8a7f 100644 --- a/drivers/net/saa9730.c +++ b/drivers/net/saa9730.c | |||
| @@ -97,13 +97,16 @@ static void evm_saa9730_unblock_lan_int(struct lan_saa9730_private *lp) | |||
| 97 | &lp->evm_saa9730_regs->InterruptBlock1); | 97 | &lp->evm_saa9730_regs->InterruptBlock1); |
| 98 | } | 98 | } |
| 99 | 99 | ||
| 100 | static void __attribute_used__ show_saa9730_regs(struct lan_saa9730_private *lp) | 100 | static void __used show_saa9730_regs(struct net_device *dev) |
| 101 | { | 101 | { |
| 102 | struct lan_saa9730_private *lp = netdev_priv(dev); | ||
| 102 | int i, j; | 103 | int i, j; |
| 104 | |||
| 103 | printk("TxmBufferA = %p\n", lp->TxmBuffer[0][0]); | 105 | printk("TxmBufferA = %p\n", lp->TxmBuffer[0][0]); |
| 104 | printk("TxmBufferB = %p\n", lp->TxmBuffer[1][0]); | 106 | printk("TxmBufferB = %p\n", lp->TxmBuffer[1][0]); |
| 105 | printk("RcvBufferA = %p\n", lp->RcvBuffer[0][0]); | 107 | printk("RcvBufferA = %p\n", lp->RcvBuffer[0][0]); |
| 106 | printk("RcvBufferB = %p\n", lp->RcvBuffer[1][0]); | 108 | printk("RcvBufferB = %p\n", lp->RcvBuffer[1][0]); |
| 109 | |||
| 107 | for (i = 0; i < LAN_SAA9730_BUFFERS; i++) { | 110 | for (i = 0; i < LAN_SAA9730_BUFFERS; i++) { |
| 108 | for (j = 0; j < LAN_SAA9730_TXM_Q_SIZE; j++) { | 111 | for (j = 0; j < LAN_SAA9730_TXM_Q_SIZE; j++) { |
| 109 | printk("TxmBuffer[%d][%d] = %x\n", i, j, | 112 | printk("TxmBuffer[%d][%d] = %x\n", i, j, |
| @@ -146,11 +149,13 @@ static void __attribute_used__ show_saa9730_regs(struct lan_saa9730_private *lp) | |||
| 146 | readl(&lp->lan_saa9730_regs->RxCtl)); | 149 | readl(&lp->lan_saa9730_regs->RxCtl)); |
| 147 | printk("lp->lan_saa9730_regs->RxStatus = %x\n", | 150 | printk("lp->lan_saa9730_regs->RxStatus = %x\n", |
| 148 | readl(&lp->lan_saa9730_regs->RxStatus)); | 151 | readl(&lp->lan_saa9730_regs->RxStatus)); |
| 152 | |||
| 149 | for (i = 0; i < LAN_SAA9730_CAM_DWORDS; i++) { | 153 | for (i = 0; i < LAN_SAA9730_CAM_DWORDS; i++) { |
| 150 | writel(i, &lp->lan_saa9730_regs->CamAddress); | 154 | writel(i, &lp->lan_saa9730_regs->CamAddress); |
| 151 | printk("lp->lan_saa9730_regs->CamData = %x\n", | 155 | printk("lp->lan_saa9730_regs->CamData = %x\n", |
| 152 | readl(&lp->lan_saa9730_regs->CamData)); | 156 | readl(&lp->lan_saa9730_regs->CamData)); |
| 153 | } | 157 | } |
| 158 | |||
| 154 | printk("dev->stats.tx_packets = %lx\n", dev->stats.tx_packets); | 159 | printk("dev->stats.tx_packets = %lx\n", dev->stats.tx_packets); |
| 155 | printk("dev->stats.tx_errors = %lx\n", dev->stats.tx_errors); | 160 | printk("dev->stats.tx_errors = %lx\n", dev->stats.tx_errors); |
| 156 | printk("dev->stats.tx_aborted_errors = %lx\n", | 161 | printk("dev->stats.tx_aborted_errors = %lx\n", |
| @@ -855,7 +860,7 @@ static void lan_saa9730_tx_timeout(struct net_device *dev) | |||
| 855 | /* Transmitter timeout, serious problems */ | 860 | /* Transmitter timeout, serious problems */ |
| 856 | dev->stats.tx_errors++; | 861 | dev->stats.tx_errors++; |
| 857 | printk("%s: transmit timed out, reset\n", dev->name); | 862 | printk("%s: transmit timed out, reset\n", dev->name); |
| 858 | /*show_saa9730_regs(lp); */ | 863 | /*show_saa9730_regs(dev); */ |
| 859 | lan_saa9730_restart(lp); | 864 | lan_saa9730_restart(lp); |
| 860 | 865 | ||
| 861 | dev->trans_start = jiffies; | 866 | dev->trans_start = jiffies; |
diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c index a679f4310ce1..8038f2882c9b 100644 --- a/drivers/net/tc35815.c +++ b/drivers/net/tc35815.c | |||
| @@ -1461,7 +1461,6 @@ static irqreturn_t tc35815_interrupt(int irq, void *dev_id) | |||
| 1461 | } | 1461 | } |
| 1462 | return IRQ_NONE; | 1462 | return IRQ_NONE; |
| 1463 | #else | 1463 | #else |
| 1464 | struct tc35815_local *lp = dev->priv; | ||
| 1465 | int handled; | 1464 | int handled; |
| 1466 | u32 status; | 1465 | u32 status; |
| 1467 | 1466 | ||
diff --git a/drivers/net/tehuti.c b/drivers/net/tehuti.c index 8d04654f0c59..4e1b84e6d66a 100644 --- a/drivers/net/tehuti.c +++ b/drivers/net/tehuti.c | |||
| @@ -1906,7 +1906,7 @@ bdx_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
| 1906 | 1906 | ||
| 1907 | /************** pci *****************/ | 1907 | /************** pci *****************/ |
| 1908 | if ((err = pci_enable_device(pdev))) /* it trigers interrupt, dunno why. */ | 1908 | if ((err = pci_enable_device(pdev))) /* it trigers interrupt, dunno why. */ |
| 1909 | RET(err); /* it's not a problem though */ | 1909 | goto err_pci; /* it's not a problem though */ |
| 1910 | 1910 | ||
| 1911 | if (!(err = pci_set_dma_mask(pdev, DMA_64BIT_MASK)) && | 1911 | if (!(err = pci_set_dma_mask(pdev, DMA_64BIT_MASK)) && |
| 1912 | !(err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK))) { | 1912 | !(err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK))) { |
| @@ -2076,6 +2076,7 @@ err_out_res: | |||
| 2076 | pci_release_regions(pdev); | 2076 | pci_release_regions(pdev); |
| 2077 | err_dma: | 2077 | err_dma: |
| 2078 | pci_disable_device(pdev); | 2078 | pci_disable_device(pdev); |
| 2079 | err_pci: | ||
| 2079 | vfree(nic); | 2080 | vfree(nic); |
| 2080 | 2081 | ||
| 2081 | RET(err); | 2082 | RET(err); |
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index b9e1dc662363..014dc2cfe4d6 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c | |||
| @@ -9040,7 +9040,7 @@ static int tg3_do_mem_test(struct tg3 *tp, u32 offset, u32 len) | |||
| 9040 | int i; | 9040 | int i; |
| 9041 | u32 j; | 9041 | u32 j; |
| 9042 | 9042 | ||
| 9043 | for (i = 0; i < sizeof(test_pattern)/sizeof(u32); i++) { | 9043 | for (i = 0; i < ARRAY_SIZE(test_pattern); i++) { |
| 9044 | for (j = 0; j < len; j += 4) { | 9044 | for (j = 0; j < len; j += 4) { |
| 9045 | u32 val; | 9045 | u32 val; |
| 9046 | 9046 | ||
diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c index 9b9cd83fb8b6..41f34bb91cad 100644 --- a/drivers/net/tulip/de4x5.c +++ b/drivers/net/tulip/de4x5.c | |||
| @@ -1041,7 +1041,7 @@ static struct InfoLeaf infoleaf_array[] = { | |||
| 1041 | {DC21142, dc21142_infoleaf}, | 1041 | {DC21142, dc21142_infoleaf}, |
| 1042 | {DC21143, dc21143_infoleaf} | 1042 | {DC21143, dc21143_infoleaf} |
| 1043 | }; | 1043 | }; |
| 1044 | #define INFOLEAF_SIZE (sizeof(infoleaf_array)/(sizeof(int)+sizeof(int *))) | 1044 | #define INFOLEAF_SIZE ARRAY_SIZE(infoleaf_array) |
| 1045 | 1045 | ||
| 1046 | /* | 1046 | /* |
| 1047 | ** List the SROM info block functions | 1047 | ** List the SROM info block functions |
| @@ -1056,7 +1056,7 @@ static int (*dc_infoblock[])(struct net_device *dev, u_char, u_char *) = { | |||
| 1056 | compact_infoblock | 1056 | compact_infoblock |
| 1057 | }; | 1057 | }; |
| 1058 | 1058 | ||
| 1059 | #define COMPACT (sizeof(dc_infoblock)/sizeof(int *) - 1) | 1059 | #define COMPACT (ARRAY_SIZE(dc_infoblock) - 1) |
| 1060 | 1060 | ||
| 1061 | /* | 1061 | /* |
| 1062 | ** Miscellaneous defines... | 1062 | ** Miscellaneous defines... |
diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index d00e7d41f6a5..bec413ba9bca 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c | |||
| @@ -63,7 +63,7 @@ | |||
| 63 | #define UGETH_MSG_DEFAULT (NETIF_MSG_IFUP << 1 ) - 1 | 63 | #define UGETH_MSG_DEFAULT (NETIF_MSG_IFUP << 1 ) - 1 |
| 64 | 64 | ||
| 65 | void uec_set_ethtool_ops(struct net_device *netdev); | 65 | void uec_set_ethtool_ops(struct net_device *netdev); |
| 66 | 66 | ||
| 67 | static DEFINE_SPINLOCK(ugeth_lock); | 67 | static DEFINE_SPINLOCK(ugeth_lock); |
| 68 | 68 | ||
| 69 | static struct { | 69 | static struct { |
| @@ -3454,9 +3454,12 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit | |||
| 3454 | u16 length, howmany = 0; | 3454 | u16 length, howmany = 0; |
| 3455 | u32 bd_status; | 3455 | u32 bd_status; |
| 3456 | u8 *bdBuffer; | 3456 | u8 *bdBuffer; |
| 3457 | struct net_device * dev; | ||
| 3457 | 3458 | ||
| 3458 | ugeth_vdbg("%s: IN", __FUNCTION__); | 3459 | ugeth_vdbg("%s: IN", __FUNCTION__); |
| 3459 | 3460 | ||
| 3461 | dev = ugeth->dev; | ||
| 3462 | |||
| 3460 | /* collect received buffers */ | 3463 | /* collect received buffers */ |
| 3461 | bd = ugeth->rxBd[rxQ]; | 3464 | bd = ugeth->rxBd[rxQ]; |
| 3462 | 3465 | ||
diff --git a/drivers/net/wan/sdla.c b/drivers/net/wan/sdla.c index b39a541b2509..05df0a345b60 100644 --- a/drivers/net/wan/sdla.c +++ b/drivers/net/wan/sdla.c | |||
| @@ -1342,11 +1342,11 @@ static int sdla_set_config(struct net_device *dev, struct ifmap *map) | |||
| 1342 | if (flp->initialized) | 1342 | if (flp->initialized) |
| 1343 | return(-EINVAL); | 1343 | return(-EINVAL); |
| 1344 | 1344 | ||
| 1345 | for(i=0;i < sizeof(valid_port) / sizeof (int) ; i++) | 1345 | for(i=0; i < ARRAY_SIZE(valid_port); i++) |
| 1346 | if (valid_port[i] == map->base_addr) | 1346 | if (valid_port[i] == map->base_addr) |
| 1347 | break; | 1347 | break; |
| 1348 | 1348 | ||
| 1349 | if (i == sizeof(valid_port) / sizeof(int)) | 1349 | if (i == ARRAY_SIZE(valid_port)) |
| 1350 | return(-EINVAL); | 1350 | return(-EINVAL); |
| 1351 | 1351 | ||
| 1352 | if (!request_region(map->base_addr, SDLA_IO_EXTENTS, dev->name)){ | 1352 | if (!request_region(map->base_addr, SDLA_IO_EXTENTS, dev->name)){ |
| @@ -1487,12 +1487,12 @@ got_type: | |||
| 1487 | } | 1487 | } |
| 1488 | } | 1488 | } |
| 1489 | 1489 | ||
| 1490 | for(i=0;i < sizeof(valid_mem) / sizeof (int) ; i++) | 1490 | for(i=0; i < ARRAY_SIZE(valid_mem); i++) |
| 1491 | if (valid_mem[i] == map->mem_start) | 1491 | if (valid_mem[i] == map->mem_start) |
| 1492 | break; | 1492 | break; |
| 1493 | 1493 | ||
| 1494 | err = -EINVAL; | 1494 | err = -EINVAL; |
| 1495 | if (i == sizeof(valid_mem) / sizeof(int)) | 1495 | if (i == ARRAY_SIZE(valid_mem)) |
| 1496 | goto fail2; | 1496 | goto fail2; |
| 1497 | 1497 | ||
| 1498 | if (flp->type == SDLA_S502A && (map->mem_start & 0xF000) >> 12 == 0x0E) | 1498 | if (flp->type == SDLA_S502A && (map->mem_start & 0xF000) >> 12 == 0x0E) |
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index f464b82c7d5f..7fd505cc4f7a 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c | |||
| @@ -74,22 +74,12 @@ struct netfront_info { | |||
| 74 | 74 | ||
| 75 | struct napi_struct napi; | 75 | struct napi_struct napi; |
| 76 | 76 | ||
| 77 | struct xen_netif_tx_front_ring tx; | ||
| 78 | struct xen_netif_rx_front_ring rx; | ||
| 79 | |||
| 80 | spinlock_t tx_lock; | ||
| 81 | spinlock_t rx_lock; | ||
| 82 | |||
| 83 | unsigned int evtchn; | 77 | unsigned int evtchn; |
| 78 | struct xenbus_device *xbdev; | ||
| 84 | 79 | ||
| 85 | /* Receive-ring batched refills. */ | 80 | spinlock_t tx_lock; |
| 86 | #define RX_MIN_TARGET 8 | 81 | struct xen_netif_tx_front_ring tx; |
| 87 | #define RX_DFL_MIN_TARGET 64 | 82 | int tx_ring_ref; |
| 88 | #define RX_MAX_TARGET min_t(int, NET_RX_RING_SIZE, 256) | ||
| 89 | unsigned rx_min_target, rx_max_target, rx_target; | ||
| 90 | struct sk_buff_head rx_batch; | ||
| 91 | |||
| 92 | struct timer_list rx_refill_timer; | ||
| 93 | 83 | ||
| 94 | /* | 84 | /* |
| 95 | * {tx,rx}_skbs store outstanding skbuffs. Free tx_skb entries | 85 | * {tx,rx}_skbs store outstanding skbuffs. Free tx_skb entries |
| @@ -108,14 +98,23 @@ struct netfront_info { | |||
| 108 | grant_ref_t grant_tx_ref[NET_TX_RING_SIZE]; | 98 | grant_ref_t grant_tx_ref[NET_TX_RING_SIZE]; |
| 109 | unsigned tx_skb_freelist; | 99 | unsigned tx_skb_freelist; |
| 110 | 100 | ||
| 101 | spinlock_t rx_lock ____cacheline_aligned_in_smp; | ||
| 102 | struct xen_netif_rx_front_ring rx; | ||
| 103 | int rx_ring_ref; | ||
| 104 | |||
| 105 | /* Receive-ring batched refills. */ | ||
| 106 | #define RX_MIN_TARGET 8 | ||
| 107 | #define RX_DFL_MIN_TARGET 64 | ||
| 108 | #define RX_MAX_TARGET min_t(int, NET_RX_RING_SIZE, 256) | ||
| 109 | unsigned rx_min_target, rx_max_target, rx_target; | ||
| 110 | struct sk_buff_head rx_batch; | ||
| 111 | |||
| 112 | struct timer_list rx_refill_timer; | ||
| 113 | |||
| 111 | struct sk_buff *rx_skbs[NET_RX_RING_SIZE]; | 114 | struct sk_buff *rx_skbs[NET_RX_RING_SIZE]; |
| 112 | grant_ref_t gref_rx_head; | 115 | grant_ref_t gref_rx_head; |
| 113 | grant_ref_t grant_rx_ref[NET_RX_RING_SIZE]; | 116 | grant_ref_t grant_rx_ref[NET_RX_RING_SIZE]; |
| 114 | 117 | ||
| 115 | struct xenbus_device *xbdev; | ||
| 116 | int tx_ring_ref; | ||
| 117 | int rx_ring_ref; | ||
| 118 | |||
| 119 | unsigned long rx_pfn_array[NET_RX_RING_SIZE]; | 118 | unsigned long rx_pfn_array[NET_RX_RING_SIZE]; |
| 120 | struct multicall_entry rx_mcl[NET_RX_RING_SIZE+1]; | 119 | struct multicall_entry rx_mcl[NET_RX_RING_SIZE+1]; |
| 121 | struct mmu_update rx_mmu[NET_RX_RING_SIZE]; | 120 | struct mmu_update rx_mmu[NET_RX_RING_SIZE]; |
diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c index e8010a702e73..3ac080ee6e2f 100644 --- a/drivers/scsi/gdth.c +++ b/drivers/scsi/gdth.c | |||
| @@ -5213,6 +5213,10 @@ static int __init gdth_init(void) | |||
| 5213 | #endif /* CONFIG_PCI */ | 5213 | #endif /* CONFIG_PCI */ |
| 5214 | 5214 | ||
| 5215 | TRACE2(("gdth_detect() %d controller detected\n", gdth_ctr_count)); | 5215 | TRACE2(("gdth_detect() %d controller detected\n", gdth_ctr_count)); |
| 5216 | |||
| 5217 | if (list_empty(&gdth_instances)) | ||
| 5218 | return -ENODEV; | ||
| 5219 | |||
| 5216 | #ifdef GDTH_STATISTICS | 5220 | #ifdef GDTH_STATISTICS |
| 5217 | TRACE2(("gdth_detect(): Initializing timer !\n")); | 5221 | TRACE2(("gdth_detect(): Initializing timer !\n")); |
| 5218 | init_timer(&gdth_timer); | 5222 | init_timer(&gdth_timer); |
