From 467a44b0372d8268ce5bd90e58bde7db51c1d476 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Sat, 3 May 2014 16:57:00 +0100 Subject: iio: adc: at91_adc: Repair broken platform_data support Trying to use the at91_adc driver while not using device tree is ending up in a kernel crash: Unable to handle kernel NULL pointer dereference at virtual address 00000004 [...] [] (at91_adc_probe) from [] (platform_drv_probe+0x18/0x48) [] (platform_drv_probe) from [] (driver_probe_device+0x100/0x218) [] (driver_probe_device) from [] (__driver_attach+0x8c/0x90) [] (__driver_attach) from [] (bus_for_each_dev+0x58/0x88) [] (bus_for_each_dev) from [] (bus_add_driver+0xd4/0x1d4) [] (bus_add_driver) from [] (driver_register+0x78/0xf4) [] (driver_register) from [] (do_one_initcall+0xe8/0x14c) [] (do_one_initcall) from [] (kernel_init_freeable+0xec/0x1b4) [] (kernel_init_freeable) from [] (kernel_init+0x8/0xe4) [] (kernel_init) from [] (ret_from_fork+0x14/0x24) This is because the at91_adc_caps structure is mandatory but is not filled when using platform_data. Correct that by using an id_table. It ensues that the driver will not match "at91_adc" anymore but it was crashing anyway. Fixes: c46016665fff (iio: at91: ADC start-up time calculation changed since at91sam9x5) Cc: stable@vger.kernel.org # v3.13+ Signed-off-by: Alexandre Belloni Tested-by: Josh Wu Acked-by: Josh Wu Signed-off-by: Jonathan Cameron --- drivers/iio/adc/at91_adc.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c index 5b1aa027c03..bbba014c993 100644 --- a/drivers/iio/adc/at91_adc.c +++ b/drivers/iio/adc/at91_adc.c @@ -765,14 +765,17 @@ static int at91_adc_probe_pdata(struct at91_adc_state *st, if (!pdata) return -EINVAL; + st->caps = (struct at91_adc_caps *) + platform_get_device_id(pdev)->driver_data; + st->use_external = pdata->use_external_triggers; st->vref_mv = pdata->vref; st->channels_mask = pdata->channels_used; - st->num_channels = pdata->num_channels; + st->num_channels = st->caps->num_channels; st->startup_time = pdata->startup_time; st->trigger_number = pdata->trigger_number; st->trigger_list = pdata->trigger_list; - st->registers = pdata->registers; + st->registers = &st->caps->registers; return 0; } @@ -1101,7 +1104,6 @@ static int at91_adc_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_OF static struct at91_adc_caps at91sam9260_caps = { .calc_startup_ticks = calc_startup_ticks_9260, .num_channels = 4, @@ -1154,11 +1156,27 @@ static const struct of_device_id at91_adc_dt_ids[] = { {}, }; MODULE_DEVICE_TABLE(of, at91_adc_dt_ids); -#endif + +static const struct platform_device_id at91_adc_ids[] = { + { + .name = "at91sam9260-adc", + .driver_data = (unsigned long)&at91sam9260_caps, + }, { + .name = "at91sam9g45-adc", + .driver_data = (unsigned long)&at91sam9g45_caps, + }, { + .name = "at91sam9x5-adc", + .driver_data = (unsigned long)&at91sam9x5_caps, + }, { + /* terminator */ + } +}; +MODULE_DEVICE_TABLE(platform, at91_adc_ids); static struct platform_driver at91_adc_driver = { .probe = at91_adc_probe, .remove = at91_adc_remove, + .id_table = at91_adc_ids, .driver = { .name = DRIVER_NAME, .of_match_table = of_match_ptr(at91_adc_dt_ids), -- cgit v1.2.3-70-g09d2 From 41c897f8789d0d1039ed873ddcd0caabd5756e0f Mon Sep 17 00:00:00 2001 From: Beomho Seo Date: Wed, 3 Dec 2014 00:57:00 +0000 Subject: iio: cm32181: Fix read integration time function In read integration time function, assign 0 to val. Because, prevent return inaccurate value when call read integration time. Cc: Stable@vger.kernel.org Cc: Kevin Tsai Signed-off-by: Beomho Seo Signed-off-by: Jonathan Cameron --- drivers/iio/light/cm32181.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/iio/light/cm32181.c b/drivers/iio/light/cm32181.c index 47a6dbac2d0..d976e6ce60d 100644 --- a/drivers/iio/light/cm32181.c +++ b/drivers/iio/light/cm32181.c @@ -221,6 +221,7 @@ static int cm32181_read_raw(struct iio_dev *indio_dev, *val = cm32181->calibscale; return IIO_VAL_INT; case IIO_CHAN_INFO_INT_TIME: + *val = 0; ret = cm32181_read_als_it(cm32181, val2); return ret; } -- cgit v1.2.3-70-g09d2 From 8f32b6ba56ef8c8434635b9f08ff6a23510960a5 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 3 Mar 2014 18:07:00 +0000 Subject: iio: adc: at91_adc: correct default shtim value When sample_hold_time is zero (this is the case when DT is not used or if atmel,adc-sample-hold-time is omitted), then the calculated shtim is large. Make that 0, which is the default for that register and the ADC will then use a sane value of 2/ADCCLK or 1/ADCCLK depending on the version. Signed-off-by: Alexandre Belloni Acked-by: Josh Wu Signed-off-by: Jonathan Cameron --- drivers/iio/adc/at91_adc.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c index bbba014c993..89777ed9abd 100644 --- a/drivers/iio/adc/at91_adc.c +++ b/drivers/iio/adc/at91_adc.c @@ -1007,8 +1007,11 @@ static int at91_adc_probe(struct platform_device *pdev) * the best converted final value between two channels selection * The formula thus is : Sample and Hold Time = (shtim + 1) / ADCClock */ - shtim = round_up((st->sample_hold_time * adc_clk_khz / - 1000) - 1, 1); + if (st->sample_hold_time > 0) + shtim = round_up((st->sample_hold_time * adc_clk_khz / 1000) + - 1, 1); + else + shtim = 0; reg = AT91_ADC_PRESCAL_(prsc) & st->registers->mr_prescal_mask; reg |= AT91_ADC_STARTUP_(ticks) & st->registers->mr_startup_mask; -- cgit v1.2.3-70-g09d2 From 6b9da2e77249bd62bb0902319cfa22398f32c538 Mon Sep 17 00:00:00 2001 From: Jimmy Li Date: Sat, 22 Mar 2014 05:58:00 +0000 Subject: staging:iio:ad2s1200 fix a missing break Signed-off-by: Jimmy Li Signed-off-by: Jonathan Cameron --- drivers/staging/iio/resolver/ad2s1200.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/staging/iio/resolver/ad2s1200.c b/drivers/staging/iio/resolver/ad2s1200.c index 36eedd8a0ea..e2b48204515 100644 --- a/drivers/staging/iio/resolver/ad2s1200.c +++ b/drivers/staging/iio/resolver/ad2s1200.c @@ -70,6 +70,7 @@ static int ad2s1200_read_raw(struct iio_dev *indio_dev, vel = (((s16)(st->rx[0])) << 4) | ((st->rx[1] & 0xF0) >> 4); vel = (vel << 4) >> 4; *val = vel; + break; default: mutex_unlock(&st->lock); return -EINVAL; -- cgit v1.2.3-70-g09d2 From 2076a20fc1a06f7b0333c62a2bb4eeeac7ed1bcb Mon Sep 17 00:00:00 2001 From: Alec Berg Date: Wed, 19 Mar 2014 18:50:00 +0000 Subject: iio: querying buffer scan_mask should return 0/1 Ensure that querying the IIO buffer scan_mask returns a value of 0 or 1. Currently querying the scan mask has the value returned by test_bit(), which returns either true or false. For some architectures test_bit() may return -1 for true, which will appear to return an error when returning from iio_scan_mask_query(). Additionally, it's important for the sysfs interface to consistently return the same thing when querying the scan_mask. Signed-off-by: Alec Berg Cc: stable@vger.kernel.org Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-buffer.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index c67d83bdc8f..fe25042f056 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -165,7 +165,8 @@ static ssize_t iio_scan_el_show(struct device *dev, int ret; struct iio_dev *indio_dev = dev_to_iio_dev(dev); - ret = test_bit(to_iio_dev_attr(attr)->address, + /* Ensure ret is 0 or 1. */ + ret = !!test_bit(to_iio_dev_attr(attr)->address, indio_dev->buffer->scan_mask); return sprintf(buf, "%d\n", ret); @@ -866,7 +867,8 @@ int iio_scan_mask_query(struct iio_dev *indio_dev, if (!buffer->scan_mask) return 0; - return test_bit(bit, buffer->scan_mask); + /* Ensure return value is 0 or 1. */ + return !!test_bit(bit, buffer->scan_mask); }; EXPORT_SYMBOL_GPL(iio_scan_mask_query); -- cgit v1.2.3-70-g09d2 From d0a588a57c2b0748df8307a0865a1bbbf1624c53 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 18 Mar 2014 08:13:00 +0000 Subject: iio: cm36651: Fix i2c client leak and possible NULL pointer dereference During probe the driver allocates dummy I2C devices (i2c_new_dummy()) but they aren't unregistered during driver remove or probe failure. Additionally driver does not check the return value of i2c_new_dummy(). In case of error (i2c_new_device(): memory allocation failure or I2C address cannot be used) this function returns NULL which is later dereferenced by i2c_smbus_{read,write}_data() functions. Fix issues by properly checking for i2c_new_dummy() return value and unregistering I2C devices on driver remove or probe failure. Signed-off-by: Krzysztof Kozlowski Acked-by: Beomho Seo Cc: stable@vger.kernel.org Signed-off-by: Jonathan Cameron --- drivers/iio/light/cm36651.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/light/cm36651.c b/drivers/iio/light/cm36651.c index a45e07492db..39fc67e8213 100644 --- a/drivers/iio/light/cm36651.c +++ b/drivers/iio/light/cm36651.c @@ -652,7 +652,19 @@ static int cm36651_probe(struct i2c_client *client, cm36651->client = client; cm36651->ps_client = i2c_new_dummy(client->adapter, CM36651_I2C_ADDR_PS); + if (!cm36651->ps_client) { + dev_err(&client->dev, "%s: new i2c device failed\n", __func__); + ret = -ENODEV; + goto error_disable_reg; + } + cm36651->ara_client = i2c_new_dummy(client->adapter, CM36651_ARA); + if (!cm36651->ara_client) { + dev_err(&client->dev, "%s: new i2c device failed\n", __func__); + ret = -ENODEV; + goto error_i2c_unregister_ps; + } + mutex_init(&cm36651->lock); indio_dev->dev.parent = &client->dev; indio_dev->channels = cm36651_channels; @@ -664,7 +676,7 @@ static int cm36651_probe(struct i2c_client *client, ret = cm36651_setup_reg(cm36651); if (ret) { dev_err(&client->dev, "%s: register setup failed\n", __func__); - goto error_disable_reg; + goto error_i2c_unregister_ara; } ret = request_threaded_irq(client->irq, NULL, cm36651_irq_handler, @@ -672,7 +684,7 @@ static int cm36651_probe(struct i2c_client *client, "cm36651", indio_dev); if (ret) { dev_err(&client->dev, "%s: request irq failed\n", __func__); - goto error_disable_reg; + goto error_i2c_unregister_ara; } ret = iio_device_register(indio_dev); @@ -685,6 +697,10 @@ static int cm36651_probe(struct i2c_client *client, error_free_irq: free_irq(client->irq, indio_dev); +error_i2c_unregister_ara: + i2c_unregister_device(cm36651->ara_client); +error_i2c_unregister_ps: + i2c_unregister_device(cm36651->ps_client); error_disable_reg: regulator_disable(cm36651->vled_reg); return ret; @@ -698,6 +714,8 @@ static int cm36651_remove(struct i2c_client *client) iio_device_unregister(indio_dev); regulator_disable(cm36651->vled_reg); free_irq(client->irq, indio_dev); + i2c_unregister_device(cm36651->ps_client); + i2c_unregister_device(cm36651->ara_client); return 0; } -- cgit v1.2.3-70-g09d2 From e036f71e8ce310dc58b1351c3eb967b892f4641c Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 17 Mar 2014 16:43:00 +0000 Subject: iio: adc: mxs-lradc: fix warning when buidling on avr32 This fixes: drivers/staging/iio/adc/mxs-lradc.c: In function 'mxs_lradc_probe': drivers/staging/iio/adc/mxs-lradc.c:1558: warning: comparison of distinct pointer types lacks a cast drivers/staging/iio/adc/mxs-lradc.c:1558: warning: right shift count >= width of type drivers/staging/iio/adc/mxs-lradc.c:1558: warning: passing argument 1 of '__div64_32' from incompatible pointer type When building on avr32. Reported-by: Fengguang Wu Signed-off-by: Alexandre Belloni Signed-off-by: Jonathan Cameron --- drivers/staging/iio/adc/mxs-lradc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/iio/adc/mxs-lradc.c b/drivers/staging/iio/adc/mxs-lradc.c index 514844efac7..53b3f963a7e 100644 --- a/drivers/staging/iio/adc/mxs-lradc.c +++ b/drivers/staging/iio/adc/mxs-lradc.c @@ -1527,7 +1527,7 @@ static int mxs_lradc_probe(struct platform_device *pdev) struct resource *iores; int ret = 0, touch_ret; int i, s; - unsigned int scale_uv; + uint64_t scale_uv; /* Allocate the IIO device. */ iio = devm_iio_device_alloc(dev, sizeof(*lradc)); -- cgit v1.2.3-70-g09d2 From 74c03eb63061c834893e7ebf8d298573bdccfd08 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 2 Apr 2014 12:41:59 -0400 Subject: libata: make AHCI_XGENE depend on PHY_XGENE AHCI_XGENE is only applicable on ARM64 but it can also be enabled for compile testing; however, AHCI_XGENE selects PHY_XGENE which has other arch specific dependencies. This leads to the following warning when enabling it on other archs for compile testing. warning: (AHCI_XGENE) selects PHY_XGENE which has unmet direct dependencies (HAS_IOMEM && OF && (ARM64 || COMPILE_TEST)) Selecting a config option which itself has dependencies can easily lead to broken configurations. For now, let's just make AHCI_XGENE depend on PHY_XGENE which has all the necessary dependencies already. Signed-off-by: Tejun Heo Reported-by: Linus Torvalds Cc: Loc Ho Cc: Bartlomiej Zolnierkiewicz Cc: Kishon Vijay Abraham I --- drivers/ata/Kconfig | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 20e03a7eb8b..2e4da3bc47f 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -134,8 +134,7 @@ config AHCI_SUNXI config AHCI_XGENE tristate "APM X-Gene 6.0Gbps AHCI SATA host controller support" - depends on ARM64 || COMPILE_TEST - select PHY_XGENE + depends on PHY_XGENE help This option enables support for APM X-Gene SoC SATA host controller. -- cgit v1.2.3-70-g09d2 From d121f7d0cbb875abce249dbf7eb191f9bafe80b7 Mon Sep 17 00:00:00 2001 From: "Martin K. Petersen" Date: Tue, 1 Apr 2014 20:42:37 -0400 Subject: libata: Update queued trim blacklist for M5x0 drives Crucial/Micron M500 drives properly support queued DSM TRIM starting with firmware MU05. Update the blacklist so we only disable queued trim for older firmware releases. Early M550 series drives suffer from the same issue as M500. A bugfix firmware is in the pipeline but not ready yet. Until then, blacklist queued trim for M550. Signed-off-by: Martin K. Petersen Cc: Chris Samuel Cc: Marc MERLIN Signed-off-by: Tejun Heo Cc: stable@vger.kernel.org --- drivers/ata/libata-core.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 34406f7fdd7..f2a6020366e 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4224,8 +4224,10 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { { "PIONEER DVD-RW DVR-216D", NULL, ATA_HORKAGE_NOSETXFER }, /* devices that don't properly handle queued TRIM commands */ - { "Micron_M500*", NULL, ATA_HORKAGE_NO_NCQ_TRIM, }, - { "Crucial_CT???M500SSD*", NULL, ATA_HORKAGE_NO_NCQ_TRIM, }, + { "Micron_M500*", "MU0[1-4]*", ATA_HORKAGE_NO_NCQ_TRIM, }, + { "Crucial_CT???M500SSD*", "MU0[1-4]*", ATA_HORKAGE_NO_NCQ_TRIM, }, + { "Micron_M550*", NULL, ATA_HORKAGE_NO_NCQ_TRIM, }, + { "Crucial_CT???M550SSD*", NULL, ATA_HORKAGE_NO_NCQ_TRIM, }, /* * Some WD SATA-I drives spin up and down erratically when the link -- cgit v1.2.3-70-g09d2 From 27aa64b9d1bd0d23fd692c91763a48309b694311 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Mon, 31 Mar 2014 19:51:14 +0200 Subject: pata_at91: fix ata_host_activate() failure handling Add missing clk_put() call to ata_host_activate() failure path. Sergei says, "Hm, I have once fixed that (see that *if* (!ret)) but looks like a later commit 477c87e90853d136b188c50c0e4a93d01cad872e (ARM: at91/pata: use gpio_is_valid to check the gpio) broke it again. :-( Would be good if the changelog did mention that..." Cc: Andrew Victor Cc: Nicolas Ferre Cc: Jean-Christophe Plagniol-Villard Cc: Sergei Shtylyov Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: Tejun Heo Cc: stable@vger.kernel.org --- drivers/ata/pata_at91.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/pata_at91.c b/drivers/ata/pata_at91.c index e9c87274a78..8a66f23af4c 100644 --- a/drivers/ata/pata_at91.c +++ b/drivers/ata/pata_at91.c @@ -407,12 +407,13 @@ static int pata_at91_probe(struct platform_device *pdev) host->private_data = info; - return ata_host_activate(host, gpio_is_valid(irq) ? gpio_to_irq(irq) : 0, - gpio_is_valid(irq) ? ata_sff_interrupt : NULL, - irq_flags, &pata_at91_sht); + ret = ata_host_activate(host, gpio_is_valid(irq) ? gpio_to_irq(irq) : 0, + gpio_is_valid(irq) ? ata_sff_interrupt : NULL, + irq_flags, &pata_at91_sht); + if (ret) + goto err_put; - if (!ret) - return 0; + return 0; err_put: clk_put(info->mck); -- cgit v1.2.3-70-g09d2 From 2cf8ee9044d744df57adf8485f205e8f2d4c6f02 Mon Sep 17 00:00:00 2001 From: Frank Praznik Date: Wed, 2 Apr 2014 12:31:19 -0400 Subject: HID: sony: Fix cancel_work_sync mismerge Remove redundant cancel_work_sync() call caused by mismerge. Signed-off-by: Frank Praznik Signed-off-by: Jiri Kosina --- drivers/hid/hid-sony.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index 69204afea7a..908de278921 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -1721,8 +1721,6 @@ static void sony_remove(struct hid_device *hdev) if (sc->quirks & SONY_LED_SUPPORT) sony_leds_remove(hdev); - if (sc->worker_initialized) - cancel_work_sync(&sc->state_worker); if (sc->quirks & SONY_BATTERY_SUPPORT) { hid_hw_close(hdev); sony_battery_remove(sc); -- cgit v1.2.3-70-g09d2 From 30f58877bfdaa562d329ec870f948b4d03e1ab03 Mon Sep 17 00:00:00 2001 From: Stephen Chandler Paul Date: Thu, 3 Apr 2014 16:27:55 -0400 Subject: HID: sensor-hub: add sensor hub quirk for ThinkPad Helix Just like some of the other laptops/tablets on the market with ultrabook sensors, the ThinkPad Helix's sensor hub requires a special quirk in order for it to power on properly. Without it the sensors are detected by the kernel and set up as usual, but they won't output any data. This will also fix the sensors on any other laptops with the same model of sensor hub. Signed-off-by: Stephen Chandler Paul Acked-by: Srinivas Pandruvada Signed-off-by: Jiri Kosina --- drivers/hid/hid-ids.h | 3 ++- drivers/hid/hid-sensor-hub.c | 7 +++++-- 2 files changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index bd221263c73..3312f1b568e 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -455,7 +455,8 @@ #define USB_VENDOR_ID_INTEL_0 0x8086 #define USB_VENDOR_ID_INTEL_1 0x8087 -#define USB_DEVICE_ID_INTEL_HID_SENSOR 0x09fa +#define USB_DEVICE_ID_INTEL_HID_SENSOR_0 0x09fa +#define USB_DEVICE_ID_INTEL_HID_SENSOR_1 0x0a04 #define USB_VENDOR_ID_STM_0 0x0483 #define USB_DEVICE_ID_STM_HID_SENSOR 0x91d1 diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c index 5182031f7b5..af8244b1c1f 100644 --- a/drivers/hid/hid-sensor-hub.c +++ b/drivers/hid/hid-sensor-hub.c @@ -697,10 +697,13 @@ static void sensor_hub_remove(struct hid_device *hdev) static const struct hid_device_id sensor_hub_devices[] = { { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_INTEL_0, - USB_DEVICE_ID_INTEL_HID_SENSOR), + USB_DEVICE_ID_INTEL_HID_SENSOR_0), .driver_data = HID_SENSOR_HUB_ENUM_QUIRK}, { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_INTEL_1, - USB_DEVICE_ID_INTEL_HID_SENSOR), + USB_DEVICE_ID_INTEL_HID_SENSOR_0), + .driver_data = HID_SENSOR_HUB_ENUM_QUIRK}, + { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_INTEL_1, + USB_DEVICE_ID_INTEL_HID_SENSOR_1), .driver_data = HID_SENSOR_HUB_ENUM_QUIRK}, { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_STM_0, USB_DEVICE_ID_STM_HID_SENSOR), -- cgit v1.2.3-70-g09d2 From f3b0cbce01cd5c242b420d986b208d306bdc5083 Mon Sep 17 00:00:00 2001 From: Derya Date: Mon, 31 Mar 2014 13:27:09 -0400 Subject: Revert "HID: microsoft: Add ID's for Surface Type/Touch Cover 2" This reverts commit 117309c51dca42121f70cacec801511b76acf75c. The MS Surface Pro 2 has an USB composite device with 3 interfaces - interface 0 - sensor hub - interface 1 - wacom digitizer - interface 2 - the keyboard cover, if one is attached This USB composite device changes it product id dependent on if and which keyboard cover is attached. Adding the covers to hid_have_special_driver prevents loading the right hid drivers for the other two interfaces, all 3 get loaded with hid-microsoft. We don't even need hid-microsoft for the keyboards. We have to revert this to load the right hid modules for each interface. CC: stable@vger.kernel.org # kernel 3.14 only Signed-off-by: Derya Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 2 -- drivers/hid/hid-ids.h | 2 -- drivers/hid/hid-microsoft.c | 4 ---- 3 files changed, 8 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 9e8064205bc..3f488ff88e0 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1821,8 +1821,6 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_USB) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_3K) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) }, - { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_2) }, - { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TOUCH_COVER_2) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_OFFICE_KB) }, { HID_USB_DEVICE(USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E) }, { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 3312f1b568e..c8af7202c28 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -630,8 +630,6 @@ #define USB_DEVICE_ID_MS_PRESENTER_8K_USB 0x0713 #define USB_DEVICE_ID_MS_DIGITAL_MEDIA_3K 0x0730 #define USB_DEVICE_ID_MS_COMFORT_MOUSE_4500 0x076c -#define USB_DEVICE_ID_MS_TOUCH_COVER_2 0x07a7 -#define USB_DEVICE_ID_MS_TYPE_COVER_2 0x07a9 #define USB_VENDOR_ID_MOJO 0x8282 #define USB_DEVICE_ID_RETRO_ADAPTER 0x3201 diff --git a/drivers/hid/hid-microsoft.c b/drivers/hid/hid-microsoft.c index 6fd58175a29..8ba17a946f2 100644 --- a/drivers/hid/hid-microsoft.c +++ b/drivers/hid/hid-microsoft.c @@ -274,10 +274,6 @@ static const struct hid_device_id ms_devices[] = { .driver_data = MS_NOGET }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_MOUSE_4500), .driver_data = MS_DUPLICATE_USAGES }, - { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_2), - .driver_data = 0 }, - { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TOUCH_COVER_2), - .driver_data = 0 }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT), .driver_data = MS_PRESENTER }, -- cgit v1.2.3-70-g09d2 From e24d0d399b2fce71b627043e900ef28283850482 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Mon, 31 Mar 2014 13:27:10 -0400 Subject: HID: core: do not scan constant input report The Microsoft Surface Type/Touch Cover 2 is a fancy device which advertised itself as a multitouch device but with constant input reports. This way, hid_scan_report() gives the group MULTITOUCH to it, but hid-multitouch can not handle it due to the constant collection ignored by hid-input. To prevent such crap in the future, and while we do not fix this particular device, make the scan_report coherent with hid-input.c, and ignore constant input reports. CC: stable@vger.kernel.org # 3.12+ Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 3f488ff88e0..10a2c086645 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -718,6 +718,9 @@ static int hid_scan_main(struct hid_parser *parser, struct hid_item *item) case HID_MAIN_ITEM_TAG_END_COLLECTION: break; case HID_MAIN_ITEM_TAG_INPUT: + /* ignore constant inputs, they will be ignored by hid-input */ + if (data & HID_MAIN_ITEM_CONSTANT) + break; for (i = 0; i < parser->local.usage_index; i++) hid_scan_input_usage(parser, parser->local.usage[i]); break; -- cgit v1.2.3-70-g09d2 From f5f85ee065f2e243f4165d7dd7d1a4a95daa1801 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 8 Apr 2014 11:06:26 +0200 Subject: ata: fix i.MX AHCI driver dependencies The ahci_imx driver is only needed on Freescale i.MX platforms so don't let it be built on other platforms, except for build test purpose. Signed-off-by: Jean Delvare Cc: Tejun Heo Cc: Richard Zhu Signed-off-by: Tejun Heo --- drivers/ata/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 2e4da3bc47f..c2706047337 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -116,7 +116,7 @@ config AHCI_ST config AHCI_IMX tristate "Freescale i.MX AHCI SATA support" - depends on MFD_SYSCON + depends on MFD_SYSCON && (ARCH_MXC || COMPILE_TEST) help This option enables support for the Freescale i.MX SoC's onboard AHCI SATA. -- cgit v1.2.3-70-g09d2 From 5e3283e2920a0bd8a806964d80274b8756e0dd7f Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Tue, 8 Apr 2014 11:08:41 +0100 Subject: dm thin: irqsave must always be used with the pool->lock spinlock Commit c140e1c4e23 ("dm thin: use per thin device deferred bio lists") incorrectly stopped disabling irqs when taking the pool's spinlock. Irqs must be disabled when taking the pool's spinlock otherwise a thread could spin_lock(), then get interrupted to service thin_endio() in interrupt context, which would then deadlock in spin_lock_irqsave(). Signed-off-by: Joe Thornber Signed-off-by: Mike Snitzer --- drivers/md/dm-thin.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c index 53728be84de..ae5fd0b9c75 100644 --- a/drivers/md/dm-thin.c +++ b/drivers/md/dm-thin.c @@ -3101,6 +3101,7 @@ static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv) struct thin_c *tc; struct dm_dev *pool_dev, *origin_dev; struct mapped_device *pool_md; + unsigned long flags; mutex_lock(&dm_thin_pool_table.mutex); @@ -3191,9 +3192,9 @@ static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv) mutex_unlock(&dm_thin_pool_table.mutex); - spin_lock(&tc->pool->lock); + spin_lock_irqsave(&tc->pool->lock, flags); list_add_tail_rcu(&tc->list, &tc->pool->active_thins); - spin_unlock(&tc->pool->lock); + spin_unlock_irqrestore(&tc->pool->lock, flags); /* * This synchronize_rcu() call is needed here otherwise we risk a * wake_worker() call finding no bios to process (because the newly -- cgit v1.2.3-70-g09d2 From 1ca2030563534bc0b057df9fddd30fb6257826cb Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 7 Apr 2014 10:37:44 +0200 Subject: drm/tegra: dp: Support address-only I2C-over-AUX transactions Certain types of I2C-over-AUX transactions require that only the address is transferred. Detect this by looking at the AUX message's size and set the address-only bit appropriately. Signed-off-by: Thierry Reding --- drivers/gpu/drm/tegra/dpaux.c | 44 ++++++++++++++++++++++++++++++------------- drivers/gpu/drm/tegra/dpaux.h | 1 + 2 files changed, 32 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/tegra/dpaux.c b/drivers/gpu/drm/tegra/dpaux.c index d536ed381fb..005c19bd92d 100644 --- a/drivers/gpu/drm/tegra/dpaux.c +++ b/drivers/gpu/drm/tegra/dpaux.c @@ -99,55 +99,73 @@ static void tegra_dpaux_read_fifo(struct tegra_dpaux *dpaux, u8 *buffer, static ssize_t tegra_dpaux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) { - unsigned long value = DPAUX_DP_AUXCTL_TRANSACTREQ; unsigned long timeout = msecs_to_jiffies(250); struct tegra_dpaux *dpaux = to_dpaux(aux); unsigned long status; ssize_t ret = 0; + u32 value; - if (msg->size < 1 || msg->size > 16) + /* Tegra has 4x4 byte DP AUX transmit and receive FIFOs. */ + if (msg->size > 16) return -EINVAL; - tegra_dpaux_writel(dpaux, msg->address, DPAUX_DP_AUXADDR); + /* + * Allow zero-sized messages only for I2C, in which case they specify + * address-only transactions. + */ + if (msg->size < 1) { + switch (msg->request & ~DP_AUX_I2C_MOT) { + case DP_AUX_I2C_WRITE: + case DP_AUX_I2C_READ: + value = DPAUX_DP_AUXCTL_CMD_ADDRESS_ONLY; + break; + + default: + return -EINVAL; + } + } else { + /* For non-zero-sized messages, set the CMDLEN field. */ + value = DPAUX_DP_AUXCTL_CMDLEN(msg->size - 1); + } switch (msg->request & ~DP_AUX_I2C_MOT) { case DP_AUX_I2C_WRITE: if (msg->request & DP_AUX_I2C_MOT) - value = DPAUX_DP_AUXCTL_CMD_MOT_WR; + value |= DPAUX_DP_AUXCTL_CMD_MOT_WR; else - value = DPAUX_DP_AUXCTL_CMD_I2C_WR; + value |= DPAUX_DP_AUXCTL_CMD_I2C_WR; break; case DP_AUX_I2C_READ: if (msg->request & DP_AUX_I2C_MOT) - value = DPAUX_DP_AUXCTL_CMD_MOT_RD; + value |= DPAUX_DP_AUXCTL_CMD_MOT_RD; else - value = DPAUX_DP_AUXCTL_CMD_I2C_RD; + value |= DPAUX_DP_AUXCTL_CMD_I2C_RD; break; case DP_AUX_I2C_STATUS: if (msg->request & DP_AUX_I2C_MOT) - value = DPAUX_DP_AUXCTL_CMD_MOT_RQ; + value |= DPAUX_DP_AUXCTL_CMD_MOT_RQ; else - value = DPAUX_DP_AUXCTL_CMD_I2C_RQ; + value |= DPAUX_DP_AUXCTL_CMD_I2C_RQ; break; case DP_AUX_NATIVE_WRITE: - value = DPAUX_DP_AUXCTL_CMD_AUX_WR; + value |= DPAUX_DP_AUXCTL_CMD_AUX_WR; break; case DP_AUX_NATIVE_READ: - value = DPAUX_DP_AUXCTL_CMD_AUX_RD; + value |= DPAUX_DP_AUXCTL_CMD_AUX_RD; break; default: return -EINVAL; } - value |= DPAUX_DP_AUXCTL_CMDLEN(msg->size - 1); + tegra_dpaux_writel(dpaux, msg->address, DPAUX_DP_AUXADDR); tegra_dpaux_writel(dpaux, value, DPAUX_DP_AUXCTL); if ((msg->request & DP_AUX_I2C_READ) == 0) { @@ -198,7 +216,7 @@ static ssize_t tegra_dpaux_transfer(struct drm_dp_aux *aux, break; } - if (msg->reply == DP_AUX_NATIVE_REPLY_ACK) { + if ((msg->size > 0) && (msg->reply == DP_AUX_NATIVE_REPLY_ACK)) { if (msg->request & DP_AUX_I2C_READ) { size_t count = value & DPAUX_DP_AUXSTAT_REPLY_MASK; diff --git a/drivers/gpu/drm/tegra/dpaux.h b/drivers/gpu/drm/tegra/dpaux.h index 4f5bf10fdff..806e245ca78 100644 --- a/drivers/gpu/drm/tegra/dpaux.h +++ b/drivers/gpu/drm/tegra/dpaux.h @@ -32,6 +32,7 @@ #define DPAUX_DP_AUXCTL_CMD_I2C_RQ (2 << 12) #define DPAUX_DP_AUXCTL_CMD_I2C_RD (1 << 12) #define DPAUX_DP_AUXCTL_CMD_I2C_WR (0 << 12) +#define DPAUX_DP_AUXCTL_CMD_ADDRESS_ONLY (1 << 8) #define DPAUX_DP_AUXCTL_CMDLEN(x) ((x) & 0xff) #define DPAUX_DP_AUXSTAT 0x31 -- cgit v1.2.3-70-g09d2 From a6c8aff022d4d06e4b41455ae9b2a5d3d503bf76 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 7 Apr 2014 12:37:25 +0300 Subject: drm/i915: support address only i2c-over-aux transactions To support bare address requests used by the drm dp helpers. Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_dp.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index a0dad1a2f81..d2a55884ad5 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -575,7 +575,8 @@ out: return ret; } -#define HEADER_SIZE 4 +#define BARE_ADDRESS_SIZE 3 +#define HEADER_SIZE (BARE_ADDRESS_SIZE + 1) static ssize_t intel_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) { @@ -592,7 +593,7 @@ intel_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) switch (msg->request & ~DP_AUX_I2C_MOT) { case DP_AUX_NATIVE_WRITE: case DP_AUX_I2C_WRITE: - txsize = HEADER_SIZE + msg->size; + txsize = msg->size ? HEADER_SIZE + msg->size : BARE_ADDRESS_SIZE; rxsize = 1; if (WARN_ON(txsize > 20)) @@ -611,7 +612,7 @@ intel_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) case DP_AUX_NATIVE_READ: case DP_AUX_I2C_READ: - txsize = HEADER_SIZE; + txsize = msg->size ? HEADER_SIZE : BARE_ADDRESS_SIZE; rxsize = msg->size + 1; if (WARN_ON(rxsize > 20)) -- cgit v1.2.3-70-g09d2 From 25377b921b4078a509f384fdd328b50d46414d9c Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 7 Apr 2014 10:33:43 -0400 Subject: drm/radeon/dp: handle zero sized i2c over aux transactions (v2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Needed for proper i2c over aux handling for certain monitors and configurations (e.g., dp bridges or adapters). v2: add comments clarifying tx_size setting. Signed-off-by: Alex Deucher Signed-off-by: Christian König --- drivers/gpu/drm/radeon/atombios_dp.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c index 8b0ab170cef..e4483042aee 100644 --- a/drivers/gpu/drm/radeon/atombios_dp.c +++ b/drivers/gpu/drm/radeon/atombios_dp.c @@ -142,7 +142,8 @@ static int radeon_process_aux_ch(struct radeon_i2c_chan *chan, return recv_bytes; } -#define HEADER_SIZE 4 +#define BARE_ADDRESS_SIZE 3 +#define HEADER_SIZE (BARE_ADDRESS_SIZE + 1) static ssize_t radeon_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) @@ -160,13 +161,19 @@ radeon_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) tx_buf[0] = msg->address & 0xff; tx_buf[1] = msg->address >> 8; tx_buf[2] = msg->request << 4; - tx_buf[3] = msg->size - 1; + tx_buf[3] = msg->size ? (msg->size - 1) : 0; switch (msg->request & ~DP_AUX_I2C_MOT) { case DP_AUX_NATIVE_WRITE: case DP_AUX_I2C_WRITE: + /* tx_size needs to be 4 even for bare address packets since the atom + * table needs the info in tx_buf[3]. + */ tx_size = HEADER_SIZE + msg->size; - tx_buf[3] |= tx_size << 4; + if (msg->size == 0) + tx_buf[3] |= BARE_ADDRESS_SIZE << 4; + else + tx_buf[3] |= tx_size << 4; memcpy(tx_buf + HEADER_SIZE, msg->buffer, msg->size); ret = radeon_process_aux_ch(chan, tx_buf, tx_size, NULL, 0, delay, &ack); @@ -176,8 +183,14 @@ radeon_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) break; case DP_AUX_NATIVE_READ: case DP_AUX_I2C_READ: + /* tx_size needs to be 4 even for bare address packets since the atom + * table needs the info in tx_buf[3]. + */ tx_size = HEADER_SIZE; - tx_buf[3] |= tx_size << 4; + if (msg->size == 0) + tx_buf[3] |= BARE_ADDRESS_SIZE << 4; + else + tx_buf[3] |= tx_size << 4; ret = radeon_process_aux_ch(chan, tx_buf, tx_size, msg->buffer, msg->size, delay, &ack); break; @@ -186,7 +199,7 @@ radeon_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) break; } - if (ret > 0) + if (ret >= 0) msg->reply = ack >> 4; return ret; -- cgit v1.2.3-70-g09d2 From ccdb516e1873d9c69377bfec1e3392f3ed660102 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 7 Apr 2014 10:33:44 -0400 Subject: drm/dp/i2c: send bare addresses to properly reset i2c connections (v4) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We need bare address packets at the start and end of each i2c over aux transaction to properly reset the connection between transactions. This mirrors what the existing dp i2c over aux algo currently does. This fixes EDID fetches on certain monitors especially with dp bridges. v2: update as per Ville's comments - Set buffer to NULL for zero sized packets - abort the entre transaction if one of the messages fails v3: drop leftover debugging code v4: integrate Thierry's comments - add comments about address only transactions - switch back to i and j Signed-off-by: Alex Deucher Cc: Ville Syrjälä Cc: Jani Nikula Cc: Thierry Reding Reviewed-by: Ville Syrjälä Signed-off-by: Christian König --- drivers/gpu/drm/drm_dp_helper.c | 51 ++++++++++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index 27671489477..bcfb0d07718 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c @@ -665,11 +665,26 @@ static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, { struct drm_dp_aux *aux = adapter->algo_data; unsigned int i, j; + struct drm_dp_aux_msg msg; + int err = 0; - for (i = 0; i < num; i++) { - struct drm_dp_aux_msg msg; - int err; + memset(&msg, 0, sizeof(msg)); + for (i = 0; i < num; i++) { + msg.address = msgs[i].addr; + msg.request = (msgs[i].flags & I2C_M_RD) ? + DP_AUX_I2C_READ : + DP_AUX_I2C_WRITE; + msg.request |= DP_AUX_I2C_MOT; + /* Send a bare address packet to start the transaction. + * Zero sized messages specify an address only (bare + * address) transaction. + */ + msg.buffer = NULL; + msg.size = 0; + err = drm_dp_i2c_do_msg(aux, &msg); + if (err < 0) + break; /* * Many hardware implementations support FIFOs larger than a * single byte, but it has been empirically determined that @@ -678,30 +693,28 @@ static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, * transferred byte-by-byte. */ for (j = 0; j < msgs[i].len; j++) { - memset(&msg, 0, sizeof(msg)); - msg.address = msgs[i].addr; - - msg.request = (msgs[i].flags & I2C_M_RD) ? - DP_AUX_I2C_READ : - DP_AUX_I2C_WRITE; - - /* - * All messages except the last one are middle-of- - * transfer messages. - */ - if ((i < num - 1) || (j < msgs[i].len - 1)) - msg.request |= DP_AUX_I2C_MOT; - msg.buffer = msgs[i].buf + j; msg.size = 1; err = drm_dp_i2c_do_msg(aux, &msg); if (err < 0) - return err; + break; } + if (err < 0) + break; } + if (err >= 0) + err = num; + /* Send a bare address packet to close out the transaction. + * Zero sized messages specify an address only (bare + * address) transaction. + */ + msg.request &= ~DP_AUX_I2C_MOT; + msg.buffer = NULL; + msg.size = 0; + (void)drm_dp_i2c_do_msg(aux, &msg); - return num; + return err; } static const struct i2c_algorithm drm_dp_i2c_algo = { -- cgit v1.2.3-70-g09d2 From 732d50b431dca2f3f78fc21ba9b7ed9d06bb01ce Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 7 Apr 2014 10:33:45 -0400 Subject: drm/dp/i2c: Update comments about common i2c over dp assumptions (v3) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If you are using the common dp over i2c functionality, it is asumed that the aux transfer function does not modify the any of the msg structure other than the reply field. Doing so breaks the logic in the common code. v2: update struct drm_dp_aux comments about assumptions v3 (chk): rebased on upstream changes Signed-off-by: Alex Deucher Cc: Ville Syrjälä Cc: Jani Nikula Cc: Thierry Reding Reviewed-by: Ville Syrjälä Signed-off-by: Christian König --- drivers/gpu/drm/drm_dp_helper.c | 4 +++- include/drm/drm_dp_helper.h | 4 ++++ 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index bcfb0d07718..4b6e6f3ba0a 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c @@ -577,7 +577,9 @@ static u32 drm_dp_i2c_functionality(struct i2c_adapter *adapter) /* * Transfer a single I2C-over-AUX message and handle various error conditions, - * retrying the transaction as appropriate. + * retrying the transaction as appropriate. It is assumed that the + * aux->transfer function does not modify anything in the msg other than the + * reply field. */ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) { diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index b4f58914bf7..cfcacec5b89 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -456,6 +456,10 @@ struct drm_dp_aux_msg { * transactions. The drm_dp_aux_register_i2c_bus() function registers an * I2C adapter that can be passed to drm_probe_ddc(). Upon removal, drivers * should call drm_dp_aux_unregister_i2c_bus() to remove the I2C adapter. + * + * Note that the aux helper code assumes that the .transfer() function + * only modifies the reply field of the drm_dp_aux_msg structure. The + * retry logic and i2c helpers assume this is the case. */ struct drm_dp_aux { const char *name; -- cgit v1.2.3-70-g09d2 From 379dfc25e257ffe10eb53b86d2375f7c0f4f33ef Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 7 Apr 2014 10:33:46 -0400 Subject: drm/radeon/dp: switch to the common i2c over aux code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Provides a nice cleanup in radeon. Signed-off-by: Alex Deucher Signed-off-by: Christian König --- drivers/gpu/drm/radeon/atombios_dp.c | 117 +++++------------------------ drivers/gpu/drm/radeon/radeon_connectors.c | 44 ++--------- drivers/gpu/drm/radeon/radeon_display.c | 11 ++- drivers/gpu/drm/radeon/radeon_i2c.c | 60 ++++----------- drivers/gpu/drm/radeon/radeon_mode.h | 12 +-- 5 files changed, 44 insertions(+), 200 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c index e4483042aee..15936524f22 100644 --- a/drivers/gpu/drm/radeon/atombios_dp.c +++ b/drivers/gpu/drm/radeon/atombios_dp.c @@ -207,98 +207,15 @@ radeon_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) void radeon_dp_aux_init(struct radeon_connector *radeon_connector) { - struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv; - - dig_connector->dp_i2c_bus->aux.dev = radeon_connector->base.kdev; - dig_connector->dp_i2c_bus->aux.transfer = radeon_dp_aux_transfer; -} - -int radeon_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode, - u8 write_byte, u8 *read_byte) -{ - struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data; - struct radeon_i2c_chan *auxch = i2c_get_adapdata(adapter); - u16 address = algo_data->address; - u8 msg[5]; - u8 reply[2]; - unsigned retry; - int msg_bytes; - int reply_bytes = 1; int ret; - u8 ack; - - /* Set up the address */ - msg[0] = address; - msg[1] = address >> 8; - - /* Set up the command byte */ - if (mode & MODE_I2C_READ) { - msg[2] = DP_AUX_I2C_READ << 4; - msg_bytes = 4; - msg[3] = msg_bytes << 4; - } else { - msg[2] = DP_AUX_I2C_WRITE << 4; - msg_bytes = 5; - msg[3] = msg_bytes << 4; - msg[4] = write_byte; - } - /* special handling for start/stop */ - if (mode & (MODE_I2C_START | MODE_I2C_STOP)) - msg[3] = 3 << 4; - - /* Set MOT bit for all but stop */ - if ((mode & MODE_I2C_STOP) == 0) - msg[2] |= DP_AUX_I2C_MOT << 4; - - for (retry = 0; retry < 7; retry++) { - ret = radeon_process_aux_ch(auxch, - msg, msg_bytes, reply, reply_bytes, 0, &ack); - if (ret == -EBUSY) - continue; - else if (ret < 0) { - DRM_DEBUG_KMS("aux_ch failed %d\n", ret); - return ret; - } + radeon_connector->ddc_bus->aux.dev = radeon_connector->base.kdev; + radeon_connector->ddc_bus->aux.transfer = radeon_dp_aux_transfer; + ret = drm_dp_aux_register_i2c_bus(&radeon_connector->ddc_bus->aux); + if (!ret) + radeon_connector->ddc_bus->has_aux = true; - switch ((ack >> 4) & DP_AUX_NATIVE_REPLY_MASK) { - case DP_AUX_NATIVE_REPLY_ACK: - /* I2C-over-AUX Reply field is only valid - * when paired with AUX ACK. - */ - break; - case DP_AUX_NATIVE_REPLY_NACK: - DRM_DEBUG_KMS("aux_ch native nack\n"); - return -EREMOTEIO; - case DP_AUX_NATIVE_REPLY_DEFER: - DRM_DEBUG_KMS("aux_ch native defer\n"); - usleep_range(500, 600); - continue; - default: - DRM_ERROR("aux_ch invalid native reply 0x%02x\n", ack); - return -EREMOTEIO; - } - - switch ((ack >> 4) & DP_AUX_I2C_REPLY_MASK) { - case DP_AUX_I2C_REPLY_ACK: - if (mode == MODE_I2C_READ) - *read_byte = reply[0]; - return ret; - case DP_AUX_I2C_REPLY_NACK: - DRM_DEBUG_KMS("aux_i2c nack\n"); - return -EREMOTEIO; - case DP_AUX_I2C_REPLY_DEFER: - DRM_DEBUG_KMS("aux_i2c defer\n"); - usleep_range(400, 500); - break; - default: - DRM_ERROR("aux_i2c invalid reply 0x%02x\n", ack); - return -EREMOTEIO; - } - } - - DRM_DEBUG_KMS("aux i2c too many retries, giving up\n"); - return -EREMOTEIO; + WARN(ret, "drm_dp_aux_register_i2c_bus() failed with error %d\n", ret); } /***** general DP utility functions *****/ @@ -433,12 +350,11 @@ static u8 radeon_dp_encoder_service(struct radeon_device *rdev, u8 radeon_dp_getsinktype(struct radeon_connector *radeon_connector) { - struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv; struct drm_device *dev = radeon_connector->base.dev; struct radeon_device *rdev = dev->dev_private; return radeon_dp_encoder_service(rdev, ATOM_DP_ACTION_GET_SINK_TYPE, 0, - dig_connector->dp_i2c_bus->rec.i2c_id, 0); + radeon_connector->ddc_bus->rec.i2c_id, 0); } static void radeon_dp_probe_oui(struct radeon_connector *radeon_connector) @@ -449,11 +365,11 @@ static void radeon_dp_probe_oui(struct radeon_connector *radeon_connector) if (!(dig_connector->dpcd[DP_DOWN_STREAM_PORT_COUNT] & DP_OUI_SUPPORT)) return; - if (drm_dp_dpcd_read(&dig_connector->dp_i2c_bus->aux, DP_SINK_OUI, buf, 3)) + if (drm_dp_dpcd_read(&radeon_connector->ddc_bus->aux, DP_SINK_OUI, buf, 3)) DRM_DEBUG_KMS("Sink OUI: %02hx%02hx%02hx\n", buf[0], buf[1], buf[2]); - if (drm_dp_dpcd_read(&dig_connector->dp_i2c_bus->aux, DP_BRANCH_OUI, buf, 3)) + if (drm_dp_dpcd_read(&radeon_connector->ddc_bus->aux, DP_BRANCH_OUI, buf, 3)) DRM_DEBUG_KMS("Branch OUI: %02hx%02hx%02hx\n", buf[0], buf[1], buf[2]); } @@ -464,7 +380,7 @@ bool radeon_dp_getdpcd(struct radeon_connector *radeon_connector) u8 msg[DP_DPCD_SIZE]; int ret, i; - ret = drm_dp_dpcd_read(&dig_connector->dp_i2c_bus->aux, DP_DPCD_REV, msg, + ret = drm_dp_dpcd_read(&radeon_connector->ddc_bus->aux, DP_DPCD_REV, msg, DP_DPCD_SIZE); if (ret > 0) { memcpy(dig_connector->dpcd, msg, DP_DPCD_SIZE); @@ -502,7 +418,7 @@ int radeon_dp_get_panel_mode(struct drm_encoder *encoder, if (dp_bridge != ENCODER_OBJECT_ID_NONE) { /* DP bridge chips */ - drm_dp_dpcd_readb(&dig_connector->dp_i2c_bus->aux, + drm_dp_dpcd_readb(&radeon_connector->ddc_bus->aux, DP_EDP_CONFIGURATION_CAP, &tmp); if (tmp & 1) panel_mode = DP_PANEL_MODE_INTERNAL_DP2_MODE; @@ -513,7 +429,7 @@ int radeon_dp_get_panel_mode(struct drm_encoder *encoder, panel_mode = DP_PANEL_MODE_EXTERNAL_DP_MODE; } else if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) { /* eDP */ - drm_dp_dpcd_readb(&dig_connector->dp_i2c_bus->aux, + drm_dp_dpcd_readb(&radeon_connector->ddc_bus->aux, DP_EDP_CONFIGURATION_CAP, &tmp); if (tmp & 1) panel_mode = DP_PANEL_MODE_INTERNAL_DP2_MODE; @@ -567,7 +483,8 @@ bool radeon_dp_needs_link_train(struct radeon_connector *radeon_connector) u8 link_status[DP_LINK_STATUS_SIZE]; struct radeon_connector_atom_dig *dig = radeon_connector->con_priv; - if (drm_dp_dpcd_read_link_status(&dig->dp_i2c_bus->aux, link_status) <= 0) + if (drm_dp_dpcd_read_link_status(&radeon_connector->ddc_bus->aux, link_status) + <= 0) return false; if (drm_dp_channel_eq_ok(link_status, dig->dp_lane_count)) return false; @@ -587,7 +504,7 @@ void radeon_dp_set_rx_power_state(struct drm_connector *connector, /* power up/down the sink */ if (dig_connector->dpcd[0] >= 0x11) { - drm_dp_dpcd_writeb(&dig_connector->dp_i2c_bus->aux, + drm_dp_dpcd_writeb(&radeon_connector->ddc_bus->aux, DP_SET_POWER, power_state); usleep_range(1000, 2000); } @@ -891,7 +808,7 @@ void radeon_dp_link_train(struct drm_encoder *encoder, else dp_info.enc_id |= ATOM_DP_CONFIG_LINK_A; - drm_dp_dpcd_readb(&dig_connector->dp_i2c_bus->aux, DP_MAX_LANE_COUNT, &tmp); + drm_dp_dpcd_readb(&radeon_connector->ddc_bus->aux, DP_MAX_LANE_COUNT, &tmp); if (ASIC_IS_DCE5(rdev) && (tmp & DP_TPS3_SUPPORTED)) dp_info.tp3_supported = true; else @@ -903,7 +820,7 @@ void radeon_dp_link_train(struct drm_encoder *encoder, dp_info.connector = connector; dp_info.dp_lane_count = dig_connector->dp_lane_count; dp_info.dp_clock = dig_connector->dp_clock; - dp_info.aux = &dig_connector->dp_i2c_bus->aux; + dp_info.aux = &radeon_connector->ddc_bus->aux; if (radeon_dp_link_train_init(&dp_info)) goto done; diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index c566b486ca0..ea50e0ae7bf 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -1261,21 +1261,6 @@ static const struct drm_connector_funcs radeon_dvi_connector_funcs = { .force = radeon_dvi_force, }; -static void radeon_dp_connector_destroy(struct drm_connector *connector) -{ - struct radeon_connector *radeon_connector = to_radeon_connector(connector); - struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv; - - if (radeon_connector->edid) - kfree(radeon_connector->edid); - if (radeon_dig_connector->dp_i2c_bus) - radeon_i2c_destroy(radeon_dig_connector->dp_i2c_bus); - kfree(radeon_connector->con_priv); - drm_sysfs_connector_remove(connector); - drm_connector_cleanup(connector); - kfree(connector); -} - static int radeon_dp_get_modes(struct drm_connector *connector) { struct radeon_connector *radeon_connector = to_radeon_connector(connector); @@ -1553,7 +1538,7 @@ static const struct drm_connector_funcs radeon_dp_connector_funcs = { .detect = radeon_dp_detect, .fill_modes = drm_helper_probe_single_connector_modes, .set_property = radeon_connector_set_property, - .destroy = radeon_dp_connector_destroy, + .destroy = radeon_connector_destroy, .force = radeon_dvi_force, }; @@ -1562,7 +1547,7 @@ static const struct drm_connector_funcs radeon_edp_connector_funcs = { .detect = radeon_dp_detect, .fill_modes = drm_helper_probe_single_connector_modes, .set_property = radeon_lvds_set_property, - .destroy = radeon_dp_connector_destroy, + .destroy = radeon_connector_destroy, .force = radeon_dvi_force, }; @@ -1571,7 +1556,7 @@ static const struct drm_connector_funcs radeon_lvds_bridge_connector_funcs = { .detect = radeon_dp_detect, .fill_modes = drm_helper_probe_single_connector_modes, .set_property = radeon_lvds_set_property, - .destroy = radeon_dp_connector_destroy, + .destroy = radeon_connector_destroy, .force = radeon_dvi_force, }; @@ -1668,17 +1653,10 @@ radeon_add_atom_connector(struct drm_device *dev, radeon_dig_connector->igp_lane_info = igp_lane_info; radeon_connector->con_priv = radeon_dig_connector; if (i2c_bus->valid) { - /* add DP i2c bus */ - if (connector_type == DRM_MODE_CONNECTOR_eDP) - radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "eDP-auxch"); - else - radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "DP-auxch"); - if (radeon_dig_connector->dp_i2c_bus) + radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); + if (radeon_connector->ddc_bus) has_aux = true; else - DRM_ERROR("DP: Failed to assign dp ddc bus! Check dmesg for i2c errors.\n"); - radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); - if (!radeon_connector->ddc_bus) DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); } switch (connector_type) { @@ -1893,10 +1871,6 @@ radeon_add_atom_connector(struct drm_device *dev, drm_connector_init(dev, &radeon_connector->base, &radeon_dp_connector_funcs, connector_type); drm_connector_helper_add(&radeon_connector->base, &radeon_dp_connector_helper_funcs); if (i2c_bus->valid) { - /* add DP i2c bus */ - radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "DP-auxch"); - if (!radeon_dig_connector->dp_i2c_bus) - DRM_ERROR("DP: Failed to assign dp ddc bus! Check dmesg for i2c errors.\n"); radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); if (radeon_connector->ddc_bus) has_aux = true; @@ -1942,14 +1916,10 @@ radeon_add_atom_connector(struct drm_device *dev, drm_connector_init(dev, &radeon_connector->base, &radeon_edp_connector_funcs, connector_type); drm_connector_helper_add(&radeon_connector->base, &radeon_dp_connector_helper_funcs); if (i2c_bus->valid) { - /* add DP i2c bus */ - radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "eDP-auxch"); - if (radeon_dig_connector->dp_i2c_bus) + radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); + if (radeon_connector->ddc_bus) has_aux = true; else - DRM_ERROR("DP: Failed to assign dp ddc bus! Check dmesg for i2c errors.\n"); - radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); - if (!radeon_connector->ddc_bus) DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); } drm_object_attach_property(&radeon_connector->base.base, diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 386cfa4c194..776e03d6ac8 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -759,19 +759,18 @@ int radeon_ddc_get_modes(struct radeon_connector *radeon_connector) if (radeon_connector_encoder_get_dp_bridge_encoder_id(&radeon_connector->base) != ENCODER_OBJECT_ID_NONE) { - struct radeon_connector_atom_dig *dig = radeon_connector->con_priv; - - if (dig->dp_i2c_bus) + if (radeon_connector->ddc_bus->has_aux) radeon_connector->edid = drm_get_edid(&radeon_connector->base, - &dig->dp_i2c_bus->adapter); + &radeon_connector->ddc_bus->aux.ddc); } else if ((radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_DisplayPort) || (radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_eDP)) { struct radeon_connector_atom_dig *dig = radeon_connector->con_priv; if ((dig->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT || - dig->dp_sink_type == CONNECTOR_OBJECT_ID_eDP) && dig->dp_i2c_bus) + dig->dp_sink_type == CONNECTOR_OBJECT_ID_eDP) && + radeon_connector->ddc_bus->has_aux) radeon_connector->edid = drm_get_edid(&radeon_connector->base, - &dig->dp_i2c_bus->adapter); + &radeon_connector->ddc_bus->aux.ddc); else if (radeon_connector->ddc_bus && !radeon_connector->edid) radeon_connector->edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter); diff --git a/drivers/gpu/drm/radeon/radeon_i2c.c b/drivers/gpu/drm/radeon/radeon_i2c.c index e24ca6ab96d..7b944142a9f 100644 --- a/drivers/gpu/drm/radeon/radeon_i2c.c +++ b/drivers/gpu/drm/radeon/radeon_i2c.c @@ -64,8 +64,7 @@ bool radeon_ddc_probe(struct radeon_connector *radeon_connector, bool use_aux) radeon_router_select_ddc_port(radeon_connector); if (use_aux) { - struct radeon_connector_atom_dig *dig = radeon_connector->con_priv; - ret = i2c_transfer(&dig->dp_i2c_bus->adapter, msgs, 2); + ret = i2c_transfer(&radeon_connector->ddc_bus->aux.ddc, msgs, 2); } else { ret = i2c_transfer(&radeon_connector->ddc_bus->adapter, msgs, 2); } @@ -950,16 +949,16 @@ struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev, /* set the radeon bit adapter */ snprintf(i2c->adapter.name, sizeof(i2c->adapter.name), "Radeon i2c bit bus %s", name); - i2c->adapter.algo_data = &i2c->algo.bit; - i2c->algo.bit.pre_xfer = pre_xfer; - i2c->algo.bit.post_xfer = post_xfer; - i2c->algo.bit.setsda = set_data; - i2c->algo.bit.setscl = set_clock; - i2c->algo.bit.getsda = get_data; - i2c->algo.bit.getscl = get_clock; - i2c->algo.bit.udelay = 10; - i2c->algo.bit.timeout = usecs_to_jiffies(2200); /* from VESA */ - i2c->algo.bit.data = i2c; + i2c->adapter.algo_data = &i2c->bit; + i2c->bit.pre_xfer = pre_xfer; + i2c->bit.post_xfer = post_xfer; + i2c->bit.setsda = set_data; + i2c->bit.setscl = set_clock; + i2c->bit.getsda = get_data; + i2c->bit.getscl = get_clock; + i2c->bit.udelay = 10; + i2c->bit.timeout = usecs_to_jiffies(2200); /* from VESA */ + i2c->bit.data = i2c; ret = i2c_bit_add_bus(&i2c->adapter); if (ret) { DRM_ERROR("Failed to register bit i2c %s\n", name); @@ -974,46 +973,13 @@ out_free: } -struct radeon_i2c_chan *radeon_i2c_create_dp(struct drm_device *dev, - struct radeon_i2c_bus_rec *rec, - const char *name) -{ - struct radeon_i2c_chan *i2c; - int ret; - - i2c = kzalloc(sizeof(struct radeon_i2c_chan), GFP_KERNEL); - if (i2c == NULL) - return NULL; - - i2c->rec = *rec; - i2c->adapter.owner = THIS_MODULE; - i2c->adapter.class = I2C_CLASS_DDC; - i2c->adapter.dev.parent = &dev->pdev->dev; - i2c->dev = dev; - snprintf(i2c->adapter.name, sizeof(i2c->adapter.name), - "Radeon aux bus %s", name); - i2c_set_adapdata(&i2c->adapter, i2c); - i2c->adapter.algo_data = &i2c->algo.dp; - i2c->algo.dp.aux_ch = radeon_dp_i2c_aux_ch; - i2c->algo.dp.address = 0; - ret = i2c_dp_aux_add_bus(&i2c->adapter); - if (ret) { - DRM_INFO("Failed to register i2c %s\n", name); - goto out_free; - } - - return i2c; -out_free: - kfree(i2c); - return NULL; - -} - void radeon_i2c_destroy(struct radeon_i2c_chan *i2c) { if (!i2c) return; i2c_del_adapter(&i2c->adapter); + if (i2c->has_aux) + drm_dp_aux_unregister_i2c_bus(&i2c->aux); kfree(i2c); } diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 832d9fa1a4c..6ddf31a2d34 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -187,12 +187,10 @@ struct radeon_pll { struct radeon_i2c_chan { struct i2c_adapter adapter; struct drm_device *dev; - union { - struct i2c_algo_bit_data bit; - struct i2c_algo_dp_aux_data dp; - } algo; + struct i2c_algo_bit_data bit; struct radeon_i2c_bus_rec rec; struct drm_dp_aux aux; + bool has_aux; }; /* mostly for macs, but really any system without connector tables */ @@ -440,7 +438,6 @@ struct radeon_encoder { struct radeon_connector_atom_dig { uint32_t igp_lane_info; /* displayport */ - struct radeon_i2c_chan *dp_i2c_bus; u8 dpcd[DP_RECEIVER_CAP_SIZE]; u8 dp_sink_type; int dp_clock; @@ -702,8 +699,6 @@ extern void atombios_dig_transmitter_setup(struct drm_encoder *encoder, uint8_t lane_set); extern void radeon_atom_ext_encoder_setup_ddc(struct drm_encoder *encoder); extern struct drm_encoder *radeon_get_external_encoder(struct drm_encoder *encoder); -extern int radeon_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode, - u8 write_byte, u8 *read_byte); void radeon_atom_copy_swap(u8 *dst, u8 *src, u8 num_bytes, bool to_le); extern void radeon_i2c_init(struct radeon_device *rdev); @@ -715,9 +710,6 @@ extern void radeon_i2c_add(struct radeon_device *rdev, const char *name); extern struct radeon_i2c_chan *radeon_i2c_lookup(struct radeon_device *rdev, struct radeon_i2c_bus_rec *i2c_bus); -extern struct radeon_i2c_chan *radeon_i2c_create_dp(struct drm_device *dev, - struct radeon_i2c_bus_rec *rec, - const char *name); extern struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev, struct radeon_i2c_bus_rec *rec, const char *name); -- cgit v1.2.3-70-g09d2 From b10ebd34cccae1b431caf1be54919aede2be7cbe Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Tue, 8 Apr 2014 11:29:01 +0100 Subject: dm thin: fix rcu_read_lock being held in code that can sleep Commit c140e1c4e23 ("dm thin: use per thin device deferred bio lists") introduced the use of an rculist for all active thin devices. The use of rcu_read_lock() in process_deferred_bios() can result in a BUG if a dm_bio_prison_cell must be allocated as a side-effect of bio_detain(): BUG: sleeping function called from invalid context at mm/mempool.c:203 in_atomic(): 1, irqs_disabled(): 0, pid: 6, name: kworker/u8:0 3 locks held by kworker/u8:0/6: #0: ("dm-" "thin"){.+.+..}, at: [] process_one_work+0x192/0x550 #1: ((&pool->worker)){+.+...}, at: [] process_one_work+0x192/0x550 #2: (rcu_read_lock){.+.+..}, at: [] do_worker+0x5/0x4d0 We can't process deferred bios with the rcu lock held, since dm_bio_prison_cell allocation may block if the bio-prison's cell mempool is exhausted. To fix: - Introduce a refcount and completion field to each thin_c - Add thin_get/put methods for adjusting the refcount. If the refcount hits zero then the completion is triggered. - Initialise refcount to 1 when creating thin_c - When iterating the active_thins list we thin_get() whilst the rcu lock is held. - After the rcu lock is dropped we process the deferred bios for that thin. - When destroying a thin_c we thin_put() and then wait for the completion -- to avoid a race between the worker thread iterating from that thin_c and destroying the thin_c. Signed-off-by: Joe Thornber Signed-off-by: Mike Snitzer --- drivers/md/dm-thin.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 67 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c index ae5fd0b9c75..28fc282b61b 100644 --- a/drivers/md/dm-thin.c +++ b/drivers/md/dm-thin.c @@ -232,6 +232,13 @@ struct thin_c { struct bio_list deferred_bio_list; struct bio_list retry_on_resume_list; struct rb_root sort_bio_list; /* sorted list of deferred bios */ + + /* + * Ensures the thin is not destroyed until the worker has finished + * iterating the active_thins list. + */ + atomic_t refcount; + struct completion can_destroy; }; /*----------------------------------------------------------------*/ @@ -1486,6 +1493,45 @@ static void process_thin_deferred_bios(struct thin_c *tc) blk_finish_plug(&plug); } +static void thin_get(struct thin_c *tc); +static void thin_put(struct thin_c *tc); + +/* + * We can't hold rcu_read_lock() around code that can block. So we + * find a thin with the rcu lock held; bump a refcount; then drop + * the lock. + */ +static struct thin_c *get_first_thin(struct pool *pool) +{ + struct thin_c *tc = NULL; + + rcu_read_lock(); + if (!list_empty(&pool->active_thins)) { + tc = list_entry_rcu(pool->active_thins.next, struct thin_c, list); + thin_get(tc); + } + rcu_read_unlock(); + + return tc; +} + +static struct thin_c *get_next_thin(struct pool *pool, struct thin_c *tc) +{ + struct thin_c *old_tc = tc; + + rcu_read_lock(); + list_for_each_entry_continue_rcu(tc, &pool->active_thins, list) { + thin_get(tc); + thin_put(old_tc); + rcu_read_unlock(); + return tc; + } + thin_put(old_tc); + rcu_read_unlock(); + + return NULL; +} + static void process_deferred_bios(struct pool *pool) { unsigned long flags; @@ -1493,10 +1539,11 @@ static void process_deferred_bios(struct pool *pool) struct bio_list bios; struct thin_c *tc; - rcu_read_lock(); - list_for_each_entry_rcu(tc, &pool->active_thins, list) + tc = get_first_thin(pool); + while (tc) { process_thin_deferred_bios(tc); - rcu_read_unlock(); + tc = get_next_thin(pool, tc); + } /* * If there are any deferred flush bios, we must commit @@ -3061,11 +3108,25 @@ static struct target_type pool_target = { /*---------------------------------------------------------------- * Thin target methods *--------------------------------------------------------------*/ +static void thin_get(struct thin_c *tc) +{ + atomic_inc(&tc->refcount); +} + +static void thin_put(struct thin_c *tc) +{ + if (atomic_dec_and_test(&tc->refcount)) + complete(&tc->can_destroy); +} + static void thin_dtr(struct dm_target *ti) { struct thin_c *tc = ti->private; unsigned long flags; + thin_put(tc); + wait_for_completion(&tc->can_destroy); + spin_lock_irqsave(&tc->pool->lock, flags); list_del_rcu(&tc->list); spin_unlock_irqrestore(&tc->pool->lock, flags); @@ -3192,6 +3253,9 @@ static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv) mutex_unlock(&dm_thin_pool_table.mutex); + atomic_set(&tc->refcount, 1); + init_completion(&tc->can_destroy); + spin_lock_irqsave(&tc->pool->lock, flags); list_add_tail_rcu(&tc->list, &tc->pool->active_thins); spin_unlock_irqrestore(&tc->pool->lock, flags); -- cgit v1.2.3-70-g09d2 From be0949f5eb9c8133a05cf25f108f09e85e79cd32 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Tue, 8 Apr 2014 11:28:54 -0400 Subject: drm/radeon: fix audio pin counts for DCE6+ (v2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is actually quite a bit of variance based on the asic. v2: fix typo noticed by Jerome. Signed-off-by: Alex Deucher Signed-off-by: Christian König Cc: stable@vger.kernel.org --- drivers/gpu/drm/radeon/dce6_afmt.c | 14 ++++++++++---- drivers/gpu/drm/radeon/radeon.h | 5 ++++- 2 files changed, 14 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/dce6_afmt.c b/drivers/gpu/drm/radeon/dce6_afmt.c index 94e85875199..0a65dc7e93e 100644 --- a/drivers/gpu/drm/radeon/dce6_afmt.c +++ b/drivers/gpu/drm/radeon/dce6_afmt.c @@ -309,11 +309,17 @@ int dce6_audio_init(struct radeon_device *rdev) rdev->audio.enabled = true; - if (ASIC_IS_DCE8(rdev)) + if (ASIC_IS_DCE81(rdev)) /* KV: 4 streams, 7 endpoints */ + rdev->audio.num_pins = 7; + else if (ASIC_IS_DCE83(rdev)) /* KB: 2 streams, 3 endpoints */ + rdev->audio.num_pins = 3; + else if (ASIC_IS_DCE8(rdev)) /* BN/HW: 6 streams, 7 endpoints */ + rdev->audio.num_pins = 7; + else if (ASIC_IS_DCE61(rdev)) /* TN: 4 streams, 6 endpoints */ rdev->audio.num_pins = 6; - else if (ASIC_IS_DCE61(rdev)) - rdev->audio.num_pins = 4; - else + else if (ASIC_IS_DCE64(rdev)) /* OL: 2 streams, 2 endpoints */ + rdev->audio.num_pins = 2; + else /* SI: 6 streams, 6 endpoints */ rdev->audio.num_pins = 6; for (i = 0; i < rdev->audio.num_pins; i++) { diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index f21db7a0b34..05b08e16e1f 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -739,7 +739,7 @@ union radeon_irq_stat_regs { struct cik_irq_stat_regs cik; }; -#define RADEON_MAX_HPD_PINS 6 +#define RADEON_MAX_HPD_PINS 7 #define RADEON_MAX_CRTCS 6 #define RADEON_MAX_AFMT_BLOCKS 7 @@ -2631,6 +2631,9 @@ void r100_pll_errata_after_index(struct radeon_device *rdev); #define ASIC_IS_DCE64(rdev) ((rdev->family == CHIP_OLAND)) #define ASIC_IS_NODCE(rdev) ((rdev->family == CHIP_HAINAN)) #define ASIC_IS_DCE8(rdev) ((rdev->family >= CHIP_BONAIRE)) +#define ASIC_IS_DCE81(rdev) ((rdev->family == CHIP_KAVERI)) +#define ASIC_IS_DCE82(rdev) ((rdev->family == CHIP_BONAIRE)) +#define ASIC_IS_DCE83(rdev) ((rdev->family == CHIP_KABINI)) #define ASIC_IS_LOMBOK(rdev) ((rdev->ddev->pdev->device == 0x6849) || \ (rdev->ddev->pdev->device == 0x6850) || \ -- cgit v1.2.3-70-g09d2 From 8902e6f2b832e00e10c6f9e9532f6f63feb4972f Mon Sep 17 00:00:00 2001 From: Lauri Kasanen Date: Tue, 8 Apr 2014 13:39:36 +0300 Subject: drm/radeon: Improve vramlimit module param documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Lauri Kasanen Signed-off-by: Christian König Reviewed-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index d0eba48dd74..cf2721a9124 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -186,7 +186,7 @@ module_param_named(dynclks, radeon_dynclks, int, 0444); MODULE_PARM_DESC(r4xx_atom, "Enable ATOMBIOS modesetting for R4xx"); module_param_named(r4xx_atom, radeon_r4xx_atom, int, 0444); -MODULE_PARM_DESC(vramlimit, "Restrict VRAM for testing"); +MODULE_PARM_DESC(vramlimit, "Restrict VRAM for testing, in megabytes"); module_param_named(vramlimit, radeon_vram_limit, int, 0600); MODULE_PARM_DESC(agpmode, "AGP Mode (-1 == PCI)"); -- cgit v1.2.3-70-g09d2 From 004f388559a89ac17fa4c81fb8559a6599050a4e Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 7 Apr 2014 23:25:20 +0200 Subject: drm/mm: Don't WARN if drm_mm_reserve_node Jesse's BIOS fb reconstruction code actually relies on the -ENOSPC return value to detect overlapping framebuffers (which the bios uses always when lighting up more than one screen). All this fanciness happens in intel_alloc_plane_obj in intel_display.c. Since no one else uses this we can safely remove the WARN without repercussions. Reported-by: Ben Widawsky Tested-by: Ben Widawsky Cc: Jesse Barnes Cc: Dave Airlie Signed-off-by: Daniel Vetter Acked-by: Dave Airlie Signed-off-by: Jani Nikula --- drivers/gpu/drm/drm_mm.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c index 71e2d3fcd6e..04a209e2b66 100644 --- a/drivers/gpu/drm/drm_mm.c +++ b/drivers/gpu/drm/drm_mm.c @@ -207,8 +207,6 @@ int drm_mm_reserve_node(struct drm_mm *mm, struct drm_mm_node *node) return 0; } - WARN(1, "no hole found for node 0x%lx + 0x%lx\n", - node->start, node->size); return -ENOSPC; } EXPORT_SYMBOL(drm_mm_reserve_node); -- cgit v1.2.3-70-g09d2 From 2ab1bc9df01dbc19b55b2271100db7407fa6bfdc Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 7 Apr 2014 08:54:21 +0200 Subject: drm/i915: Disable self-refresh for untiled fbs on i915gm MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Apparently it doesn't work. X-tiled self-refresh works flawlessly otoh. Apparently X still works correctly with linear framebuffers, so might just be an issue with the initial modeset. It's unclear whether this just borked wm setup from our side or a hw restriction, but just disabling gets things going. Note that this regression was only brought to light with commit 3f2dc5ac05714711fc14f2bf0ee5e42d5c08c581 Author: Ville Syrjälä Date: Fri Jan 10 14:06:47 2014 +0200 drm/i915: Fix 915GM self-refresh enable/disable before that self-refresh for i915GM didn't work at all. Kudos to Ville for spotting a little bug in the original patch I've attached to the bug. Cc: Ville Syrjälä Cc: Chris Wilson Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=76103 Tested-by: Krzysztof Mazur Cc: Krzysztof Mazur Cc: stable@vger.kernel.org Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter [Jani: rebase on top of drm-next with primary plane support.] Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_pm.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 5874716774a..19e94c3edc1 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -1545,6 +1545,16 @@ static void i9xx_update_wm(struct drm_crtc *unused_crtc) DRM_DEBUG_KMS("FIFO watermarks - A: %d, B: %d\n", planea_wm, planeb_wm); + if (IS_I915GM(dev) && enabled) { + struct intel_framebuffer *fb; + + fb = to_intel_framebuffer(enabled->primary->fb); + + /* self-refresh seems busted with untiled */ + if (fb->obj->tiling_mode == I915_TILING_NONE) + enabled = NULL; + } + /* * Overlay gets an aggressive default since video jitter is bad. */ -- cgit v1.2.3-70-g09d2 From bf3f043e7bc2581475040348580f4acc786842e7 Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Tue, 18 Feb 2014 16:09:02 +0100 Subject: IB/qib: Use pci_enable_msix_range() instead of pci_enable_msix() As result of the deprecation of the MSI-X/MSI enablement functions pci_enable_msix() and pci_enable_msi_block(), all drivers using these two interfaces need to be updated to use the new pci_enable_msi_range() and pci_enable_msix_range() interfaces. Signed-off-by: Alexander Gordeev Acked-by: Mike Marciniszyn Signed-off-by: Roland Dreier --- drivers/infiniband/hw/qib/qib_pcie.c | 55 ++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/qib/qib_pcie.c b/drivers/infiniband/hw/qib/qib_pcie.c index c8d9c4ab142..61a0046efb7 100644 --- a/drivers/infiniband/hw/qib/qib_pcie.c +++ b/drivers/infiniband/hw/qib/qib_pcie.c @@ -197,46 +197,47 @@ static void qib_msix_setup(struct qib_devdata *dd, int pos, u32 *msixcnt, struct qib_msix_entry *qib_msix_entry) { int ret; - u32 tabsize = 0; - u16 msix_flags; + int nvec = *msixcnt; struct msix_entry *msix_entry; int i; + ret = pci_msix_vec_count(dd->pcidev); + if (ret < 0) + goto do_intx; + + nvec = min(nvec, ret); + /* We can't pass qib_msix_entry array to qib_msix_setup * so use a dummy msix_entry array and copy the allocated * irq back to the qib_msix_entry array. */ - msix_entry = kmalloc(*msixcnt * sizeof(*msix_entry), GFP_KERNEL); - if (!msix_entry) { - ret = -ENOMEM; + msix_entry = kmalloc(nvec * sizeof(*msix_entry), GFP_KERNEL); + if (!msix_entry) goto do_intx; - } - for (i = 0; i < *msixcnt; i++) + + for (i = 0; i < nvec; i++) msix_entry[i] = qib_msix_entry[i].msix; - pci_read_config_word(dd->pcidev, pos + PCI_MSIX_FLAGS, &msix_flags); - tabsize = 1 + (msix_flags & PCI_MSIX_FLAGS_QSIZE); - if (tabsize > *msixcnt) - tabsize = *msixcnt; - ret = pci_enable_msix(dd->pcidev, msix_entry, tabsize); - if (ret > 0) { - tabsize = ret; - ret = pci_enable_msix(dd->pcidev, msix_entry, tabsize); - } -do_intx: - if (ret) { - qib_dev_err(dd, - "pci_enable_msix %d vectors failed: %d, falling back to INTx\n", - tabsize, ret); - tabsize = 0; - } - for (i = 0; i < tabsize; i++) + ret = pci_enable_msix_range(dd->pcidev, msix_entry, 1, nvec); + if (ret < 0) + goto free_msix_entry; + else + nvec = ret; + + for (i = 0; i < nvec; i++) qib_msix_entry[i].msix = msix_entry[i]; + kfree(msix_entry); - *msixcnt = tabsize; + *msixcnt = nvec; + return; - if (ret) - qib_enable_intx(dd->pcidev); +free_msix_entry: + kfree(msix_entry); +do_intx: + qib_dev_err(dd, "pci_enable_msix_range %d vectors failed: %d, " + "falling back to INTx\n", nvec, ret); + *msixcnt = 0; + qib_enable_intx(dd->pcidev); } /** -- cgit v1.2.3-70-g09d2 From 9684c2ea6d1f5aab44119533530e4059b4c3e1ff Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Sun, 23 Feb 2014 07:57:05 +0100 Subject: IB/mthca: Use pci_enable_msix_exact() instead of pci_enable_msix() As result of the deprecation of the MSI-X/MSI enablement functions pci_enable_msix() and pci_enable_msi_block(), all drivers using these two interfaces need to be updated to use the new pci_enable_msi_range() or pci_enable_msi_exact() and pci_enable_msix_range() or pci_enable_msix_exact() interfaces. Signed-off-by: Alexander Gordeev Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mthca/mthca_main.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mthca/mthca_main.c b/drivers/infiniband/hw/mthca/mthca_main.c index 87897b95666..ded76c101dd 100644 --- a/drivers/infiniband/hw/mthca/mthca_main.c +++ b/drivers/infiniband/hw/mthca/mthca_main.c @@ -858,13 +858,9 @@ static int mthca_enable_msi_x(struct mthca_dev *mdev) entries[1].entry = 1; entries[2].entry = 2; - err = pci_enable_msix(mdev->pdev, entries, ARRAY_SIZE(entries)); - if (err) { - if (err > 0) - mthca_info(mdev, "Only %d MSI-X vectors available, " - "not using MSI-X\n", err); + err = pci_enable_msix_exact(mdev->pdev, entries, ARRAY_SIZE(entries)); + if (err) return err; - } mdev->eq_table.eq[MTHCA_EQ_COMP ].msi_x_vector = entries[0].vector; mdev->eq_table.eq[MTHCA_EQ_ASYNC].msi_x_vector = entries[1].vector; -- cgit v1.2.3-70-g09d2 From f360d88a2efddf2d2a2d01a8ac76fded34d624b4 Mon Sep 17 00:00:00 2001 From: Eli Cohen Date: Wed, 2 Apr 2014 00:10:16 +0300 Subject: IB/mlx5: Add block multicast loopback support Add support for the block multicast loopback QP creation flag along the proper firmware API for that. Signed-off-by: Eli Cohen Signed-off-by: Or Gerlitz Signed-off-by: Roland Dreier --- drivers/infiniband/hw/mlx5/main.c | 2 ++ drivers/infiniband/hw/mlx5/qp.c | 12 ++++++++++++ include/linux/mlx5/device.h | 1 + include/linux/mlx5/qp.h | 1 + 4 files changed, 16 insertions(+) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index fa6dc870ada..364d4b6937f 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -282,6 +282,8 @@ static int mlx5_ib_query_device(struct ib_device *ibdev, props->sig_guard_cap = IB_GUARD_T10DIF_CRC | IB_GUARD_T10DIF_CSUM; } + if (flags & MLX5_DEV_CAP_FLAG_BLOCK_MCAST) + props->device_cap_flags |= IB_DEVICE_BLOCK_MULTICAST_LOOPBACK; props->vendor_id = be32_to_cpup((__be32 *)(out_mad->data + 36)) & 0xffffff; diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index ae788d27b93..dc930ed21ec 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -807,6 +807,15 @@ static int create_qp_common(struct mlx5_ib_dev *dev, struct ib_pd *pd, spin_lock_init(&qp->sq.lock); spin_lock_init(&qp->rq.lock); + if (init_attr->create_flags & IB_QP_CREATE_BLOCK_MULTICAST_LOOPBACK) { + if (!(dev->mdev.caps.flags & MLX5_DEV_CAP_FLAG_BLOCK_MCAST)) { + mlx5_ib_dbg(dev, "block multicast loopback isn't supported\n"); + return -EINVAL; + } else { + qp->flags |= MLX5_IB_QP_BLOCK_MULTICAST_LOOPBACK; + } + } + if (init_attr->sq_sig_type == IB_SIGNAL_ALL_WR) qp->sq_signal_bits = MLX5_WQE_CTRL_CQ_UPDATE; @@ -878,6 +887,9 @@ static int create_qp_common(struct mlx5_ib_dev *dev, struct ib_pd *pd, if (qp->wq_sig) in->ctx.flags_pd |= cpu_to_be32(MLX5_QP_ENABLE_SIG); + if (qp->flags & MLX5_IB_QP_BLOCK_MULTICAST_LOOPBACK) + in->ctx.flags_pd |= cpu_to_be32(MLX5_QP_BLOCK_MCAST); + if (qp->scat_cqe && is_connected(init_attr->qp_type)) { int rcqe_sz; int scqe_sz; diff --git a/include/linux/mlx5/device.h b/include/linux/mlx5/device.h index 407bdb67fd4..3406cfb1267 100644 --- a/include/linux/mlx5/device.h +++ b/include/linux/mlx5/device.h @@ -179,6 +179,7 @@ enum { MLX5_DEV_CAP_FLAG_BAD_QKEY_CNTR = 1LL << 9, MLX5_DEV_CAP_FLAG_APM = 1LL << 17, MLX5_DEV_CAP_FLAG_ATOMIC = 1LL << 18, + MLX5_DEV_CAP_FLAG_BLOCK_MCAST = 1LL << 23, MLX5_DEV_CAP_FLAG_ON_DMND_PG = 1LL << 24, MLX5_DEV_CAP_FLAG_CQ_MODER = 1LL << 29, MLX5_DEV_CAP_FLAG_RESIZE_CQ = 1LL << 30, diff --git a/include/linux/mlx5/qp.h b/include/linux/mlx5/qp.h index f829ad80ff2..9709b30e2d6 100644 --- a/include/linux/mlx5/qp.h +++ b/include/linux/mlx5/qp.h @@ -146,6 +146,7 @@ enum { enum { MLX5_QP_LAT_SENSITIVE = 1 << 28, + MLX5_QP_BLOCK_MCAST = 1 << 30, MLX5_QP_ENABLE_SIG = 1 << 31, }; -- cgit v1.2.3-70-g09d2 From eb4a5346e777784f1b5ae9fd0c29b96344bdc3ae Mon Sep 17 00:00:00 2001 From: Matt Porter Date: Thu, 10 Apr 2014 15:22:10 -0400 Subject: hwrng: bcm2835 - fix oops when rng h/w is accessed during registration Commit "d9e7972 hwrng: add randomness to system from rng sources" exposed a bug in the bcm2835-rng driver resulting in boot failure on Raspberry Pi due to the following oops: [ 28.261523] BUG: soft lockup - CPU#0 stuck for 23s! [swapper:1] [ 28.271058] [ 28.275958] CPU: 0 PID: 1 Comm: swapper Not tainted 3.14.0+ #11 [ 28.285374] task: db480000 ti: db484000 task.ti: db484000 [ 28.294279] PC is at bcm2835_rng_read+0x28/0x48 [ 28.302276] LR is at hwrng_register+0x1a8/0x238 . . . The RNG h/w is not completely initialized and enabled before hwrng_register() is called and so the bcm2835_rng_read() fails. Fix this by making the warmup/enable writes before registering the RNG source with the hwrng core. Signed-off-by: Matt Porter Signed-off-by: Herbert Xu --- drivers/char/hw_random/bcm2835-rng.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/char/hw_random/bcm2835-rng.c b/drivers/char/hw_random/bcm2835-rng.c index 8c3b255e629..e900961cdd2 100644 --- a/drivers/char/hw_random/bcm2835-rng.c +++ b/drivers/char/hw_random/bcm2835-rng.c @@ -61,18 +61,18 @@ static int bcm2835_rng_probe(struct platform_device *pdev) } bcm2835_rng_ops.priv = (unsigned long)rng_base; + /* set warm-up count & enable */ + __raw_writel(RNG_WARMUP_COUNT, rng_base + RNG_STATUS); + __raw_writel(RNG_RBGEN, rng_base + RNG_CTRL); + /* register driver */ err = hwrng_register(&bcm2835_rng_ops); if (err) { dev_err(dev, "hwrng registration failed\n"); iounmap(rng_base); - } else { + } else dev_info(dev, "hwrng registered\n"); - /* set warm-up count & enable */ - __raw_writel(RNG_WARMUP_COUNT, rng_base + RNG_STATUS); - __raw_writel(RNG_RBGEN, rng_base + RNG_CTRL); - } return err; } -- cgit v1.2.3-70-g09d2 From 39fbc9c8f6765959b55e0b127dd5c57df5a47d67 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 9 Apr 2014 11:22:06 +0300 Subject: drm/i915: check VBT for supported backlight type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The only supported types are none and PWM. Other values are obsolete or reserved, don't add them. Tested-by: Kamal Mostafa Tested-by: Martin Tested-by: jrg.otte@gmail.com Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/intel_bios.c | 10 ++++++++++ drivers/gpu/drm/i915/intel_bios.h | 3 +++ 3 files changed, 14 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 0905cd91558..d24eba70ca9 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1308,6 +1308,7 @@ struct intel_vbt_data { struct { u16 pwm_freq_hz; + bool present; bool active_low_pwm; } backlight; diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 4867f4cc093..fa486c5fbb0 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -287,6 +287,9 @@ parse_lfp_backlight(struct drm_i915_private *dev_priv, struct bdb_header *bdb) const struct bdb_lfp_backlight_data *backlight_data; const struct bdb_lfp_backlight_data_entry *entry; + /* Err to enabling backlight if no backlight block. */ + dev_priv->vbt.backlight.present = true; + backlight_data = find_section(bdb, BDB_LVDS_BACKLIGHT); if (!backlight_data) return; @@ -299,6 +302,13 @@ parse_lfp_backlight(struct drm_i915_private *dev_priv, struct bdb_header *bdb) entry = &backlight_data->data[panel_type]; + dev_priv->vbt.backlight.present = entry->type == BDB_BACKLIGHT_TYPE_PWM; + if (!dev_priv->vbt.backlight.present) { + DRM_DEBUG_KMS("PWM backlight not present in VBT (type %u)\n", + entry->type); + return; + } + dev_priv->vbt.backlight.pwm_freq_hz = entry->pwm_freq_hz; dev_priv->vbt.backlight.active_low_pwm = entry->active_low_pwm; DRM_DEBUG_KMS("VBT backlight PWM modulation frequency %u Hz, " diff --git a/drivers/gpu/drm/i915/intel_bios.h b/drivers/gpu/drm/i915/intel_bios.h index 83b7629e436..f27f7b28246 100644 --- a/drivers/gpu/drm/i915/intel_bios.h +++ b/drivers/gpu/drm/i915/intel_bios.h @@ -374,6 +374,9 @@ struct bdb_lvds_lfp_data { struct bdb_lvds_lfp_data_entry data[16]; } __packed; +#define BDB_BACKLIGHT_TYPE_NONE 0 +#define BDB_BACKLIGHT_TYPE_PWM 2 + struct bdb_lfp_backlight_data_entry { u8 type:2; u8 active_low_pwm:1; -- cgit v1.2.3-70-g09d2 From c675949ec58ca50d5a3ae3c757892f1560f6e896 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 9 Apr 2014 11:31:37 +0300 Subject: drm/i915: do not setup backlight if not available according to VBT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some machines use an external EC for controlling the backlight. Info about this is present in the VBT. Do not setup native backlight control if no PWM backlight is available or supported according to VBT. The acpi_backlight interface appears to work for the EC control. In most cases there has been no harm done, but it looks like there are machines out there that have both an EC and our PWM line connected to the same wire. This, obviously, does not end well. This should fix the regression caused by commit bc0bb9fd1c7810407ab810d204bbaecb255fddde Author: Jani Nikula Date: Thu Nov 14 12:14:29 2013 +0200 drm/i915: remove QUIRK_NO_PCH_PWM_ENABLE AFAICT the quirk removed by the above commit effectively resulted in i915 not driving the backlight PWM output, thus not messing things up. Additionally this should fix the regression caused by commit fbc9fe1b4f222a7c575e3bd8e9defe59c6190a04 Author: Aaron Lu Date: Fri Oct 11 21:27:45 2013 +0800 ACPI / video: Do not register backlight if win8 and native interface exists which left some machines without a functioning backlight interface. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=76276 Reference: https://bugzilla.kernel.org/show_bug.cgi?id=47941 Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=62281 CC: Aaron Lu CC: Eric Griffith CC: Kent Baxley Tested-by: Kamal Mostafa Tested-by: Martin Tested-by: jrg.otte@gmail.com Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_panel.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index cb058408c70..0eead16aeda 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -1065,6 +1065,11 @@ int intel_panel_setup_backlight(struct drm_connector *connector) unsigned long flags; int ret; + if (!dev_priv->vbt.backlight.present) { + DRM_DEBUG_KMS("native backlight control not available per VBT\n"); + return 0; + } + /* set level and max in panel struct */ spin_lock_irqsave(&dev_priv->backlight_lock, flags); ret = dev_priv->display.setup_backlight(intel_connector); -- cgit v1.2.3-70-g09d2 From 691e6415c891b8b2b082a120b896b443531c4d45 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 9 Apr 2014 09:07:36 +0100 Subject: drm/i915: Always use kref tracking for all contexts. If we always initialize kref for the context, even if we are using fake contexts for hangstats when there is no hw support, we can forgo the dance to dereference the ctx->obj and inspect whether we are permitted to use kref inside i915_gem_context_reference() and _unreference(). My ulterior motive here is to improve the debugging of a use-after-free of ctx->obj. This patch avoids the dereference here and instead forces the assertion checks associated with kref. v2: Refactor the fake contexts to being even more like the real contexts, so that there is much less duplicated and special case code. v3: Tweaks. v4: Tweaks, minor. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=76671 Signed-off-by: Chris Wilson Tested-by: lu hua Cc: Ben Widawsky Cc: Mika Kuoppala Reviewed-by: Ben Widawsky [Jani: tiny change to backport to drm-intel-fixes.] Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_drv.h | 8 +- drivers/gpu/drm/i915/i915_gem.c | 2 +- drivers/gpu/drm/i915/i915_gem_context.c | 218 ++++++++++++----------------- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 2 +- 4 files changed, 93 insertions(+), 137 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index d24eba70ca9..ec82f6bff12 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2432,20 +2432,18 @@ int i915_gem_context_open(struct drm_device *dev, struct drm_file *file); int i915_gem_context_enable(struct drm_i915_private *dev_priv); void i915_gem_context_close(struct drm_device *dev, struct drm_file *file); int i915_switch_context(struct intel_ring_buffer *ring, - struct drm_file *file, struct i915_hw_context *to); + struct i915_hw_context *to); struct i915_hw_context * i915_gem_context_get(struct drm_i915_file_private *file_priv, u32 id); void i915_gem_context_free(struct kref *ctx_ref); static inline void i915_gem_context_reference(struct i915_hw_context *ctx) { - if (ctx->obj && HAS_HW_CONTEXTS(ctx->obj->base.dev)) - kref_get(&ctx->ref); + kref_get(&ctx->ref); } static inline void i915_gem_context_unreference(struct i915_hw_context *ctx) { - if (ctx->obj && HAS_HW_CONTEXTS(ctx->obj->base.dev)) - kref_put(&ctx->ref, i915_gem_context_free); + kref_put(&ctx->ref, i915_gem_context_free); } static inline bool i915_gem_context_is_default(const struct i915_hw_context *c) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 6370a761d13..2871ce75f43 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2790,7 +2790,7 @@ int i915_gpu_idle(struct drm_device *dev) /* Flush everything onto the inactive list. */ for_each_ring(ring, dev_priv, i) { - ret = i915_switch_context(ring, NULL, ring->default_context); + ret = i915_switch_context(ring, ring->default_context); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 6043062ffce..d72db15afa0 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -96,9 +96,6 @@ #define GEN6_CONTEXT_ALIGN (64<<10) #define GEN7_CONTEXT_ALIGN 4096 -static int do_switch(struct intel_ring_buffer *ring, - struct i915_hw_context *to); - static void do_ppgtt_cleanup(struct i915_hw_ppgtt *ppgtt) { struct drm_device *dev = ppgtt->base.dev; @@ -185,13 +182,15 @@ void i915_gem_context_free(struct kref *ctx_ref) typeof(*ctx), ref); struct i915_hw_ppgtt *ppgtt = NULL; - /* We refcount even the aliasing PPGTT to keep the code symmetric */ - if (USES_PPGTT(ctx->obj->base.dev)) - ppgtt = ctx_to_ppgtt(ctx); + if (ctx->obj) { + /* We refcount even the aliasing PPGTT to keep the code symmetric */ + if (USES_PPGTT(ctx->obj->base.dev)) + ppgtt = ctx_to_ppgtt(ctx); - /* XXX: Free up the object before tearing down the address space, in - * case we're bound in the PPGTT */ - drm_gem_object_unreference(&ctx->obj->base); + /* XXX: Free up the object before tearing down the address space, in + * case we're bound in the PPGTT */ + drm_gem_object_unreference(&ctx->obj->base); + } if (ppgtt) kref_put(&ppgtt->ref, ppgtt_release); @@ -232,32 +231,32 @@ __create_hw_context(struct drm_device *dev, return ERR_PTR(-ENOMEM); kref_init(&ctx->ref); - ctx->obj = i915_gem_alloc_object(dev, dev_priv->hw_context_size); - INIT_LIST_HEAD(&ctx->link); - if (ctx->obj == NULL) { - kfree(ctx); - DRM_DEBUG_DRIVER("Context object allocated failed\n"); - return ERR_PTR(-ENOMEM); - } + list_add_tail(&ctx->link, &dev_priv->context_list); - if (INTEL_INFO(dev)->gen >= 7) { - ret = i915_gem_object_set_cache_level(ctx->obj, - I915_CACHE_L3_LLC); - /* Failure shouldn't ever happen this early */ - if (WARN_ON(ret)) + if (dev_priv->hw_context_size) { + ctx->obj = i915_gem_alloc_object(dev, dev_priv->hw_context_size); + if (ctx->obj == NULL) { + ret = -ENOMEM; goto err_out; - } + } - list_add_tail(&ctx->link, &dev_priv->context_list); + if (INTEL_INFO(dev)->gen >= 7) { + ret = i915_gem_object_set_cache_level(ctx->obj, + I915_CACHE_L3_LLC); + /* Failure shouldn't ever happen this early */ + if (WARN_ON(ret)) + goto err_out; + } + } /* Default context will never have a file_priv */ - if (file_priv == NULL) - return ctx; - - ret = idr_alloc(&file_priv->context_idr, ctx, DEFAULT_CONTEXT_ID, 0, - GFP_KERNEL); - if (ret < 0) - goto err_out; + if (file_priv != NULL) { + ret = idr_alloc(&file_priv->context_idr, ctx, + DEFAULT_CONTEXT_ID, 0, GFP_KERNEL); + if (ret < 0) + goto err_out; + } else + ret = DEFAULT_CONTEXT_ID; ctx->file_priv = file_priv; ctx->id = ret; @@ -294,7 +293,7 @@ i915_gem_create_context(struct drm_device *dev, if (IS_ERR(ctx)) return ctx; - if (is_global_default_ctx) { + if (is_global_default_ctx && ctx->obj) { /* We may need to do things with the shrinker which * require us to immediately switch back to the default * context. This can cause a problem as pinning the @@ -342,7 +341,7 @@ i915_gem_create_context(struct drm_device *dev, return ctx; err_unpin: - if (is_global_default_ctx) + if (is_global_default_ctx && ctx->obj) i915_gem_object_ggtt_unpin(ctx->obj); err_destroy: i915_gem_context_unreference(ctx); @@ -352,32 +351,22 @@ err_destroy: void i915_gem_context_reset(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_ring_buffer *ring; int i; - if (!HAS_HW_CONTEXTS(dev)) - return; - /* Prevent the hardware from restoring the last context (which hung) on * the next switch */ for (i = 0; i < I915_NUM_RINGS; i++) { - struct i915_hw_context *dctx; - if (!(INTEL_INFO(dev)->ring_mask & (1<ring[i]; + struct i915_hw_context *dctx = ring->default_context; /* Do a fake switch to the default context */ - ring = &dev_priv->ring[i]; - dctx = ring->default_context; - if (WARN_ON(!dctx)) + if (ring->last_context == dctx) continue; if (!ring->last_context) continue; - if (ring->last_context == dctx) - continue; - - if (i == RCS) { + if (dctx->obj && i == RCS) { WARN_ON(i915_gem_obj_ggtt_pin(dctx->obj, get_context_alignment(dev), 0)); /* Fake a finish/inactive */ @@ -394,44 +383,35 @@ void i915_gem_context_reset(struct drm_device *dev) int i915_gem_context_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_ring_buffer *ring; + struct i915_hw_context *ctx; int i; - if (!HAS_HW_CONTEXTS(dev)) - return 0; - /* Init should only be called once per module load. Eventually the * restriction on the context_disabled check can be loosened. */ if (WARN_ON(dev_priv->ring[RCS].default_context)) return 0; - dev_priv->hw_context_size = round_up(get_context_size(dev), 4096); - - if (dev_priv->hw_context_size > (1<<20)) { - DRM_DEBUG_DRIVER("Disabling HW Contexts; invalid size\n"); - return -E2BIG; + if (HAS_HW_CONTEXTS(dev)) { + dev_priv->hw_context_size = round_up(get_context_size(dev), 4096); + if (dev_priv->hw_context_size > (1<<20)) { + DRM_DEBUG_DRIVER("Disabling HW Contexts; invalid size %d\n", + dev_priv->hw_context_size); + dev_priv->hw_context_size = 0; + } } - dev_priv->ring[RCS].default_context = - i915_gem_create_context(dev, NULL, USES_PPGTT(dev)); - - if (IS_ERR_OR_NULL(dev_priv->ring[RCS].default_context)) { - DRM_DEBUG_DRIVER("Disabling HW Contexts; create failed %ld\n", - PTR_ERR(dev_priv->ring[RCS].default_context)); - return PTR_ERR(dev_priv->ring[RCS].default_context); + ctx = i915_gem_create_context(dev, NULL, USES_PPGTT(dev)); + if (IS_ERR(ctx)) { + DRM_ERROR("Failed to create default global context (error %ld)\n", + PTR_ERR(ctx)); + return PTR_ERR(ctx); } - for (i = RCS + 1; i < I915_NUM_RINGS; i++) { - if (!(INTEL_INFO(dev)->ring_mask & (1<ring[i]; + /* NB: RCS will hold a ref for all rings */ + for (i = 0; i < I915_NUM_RINGS; i++) + dev_priv->ring[i].default_context = ctx; - /* NB: RCS will hold a ref for all rings */ - ring->default_context = dev_priv->ring[RCS].default_context; - } - - DRM_DEBUG_DRIVER("HW context support initialized\n"); + DRM_DEBUG_DRIVER("%s context support initialized\n", dev_priv->hw_context_size ? "HW" : "fake"); return 0; } @@ -441,33 +421,30 @@ void i915_gem_context_fini(struct drm_device *dev) struct i915_hw_context *dctx = dev_priv->ring[RCS].default_context; int i; - if (!HAS_HW_CONTEXTS(dev)) - return; - - /* The only known way to stop the gpu from accessing the hw context is - * to reset it. Do this as the very last operation to avoid confusing - * other code, leading to spurious errors. */ - intel_gpu_reset(dev); - - /* When default context is created and switched to, base object refcount - * will be 2 (+1 from object creation and +1 from do_switch()). - * i915_gem_context_fini() will be called after gpu_idle() has switched - * to default context. So we need to unreference the base object once - * to offset the do_switch part, so that i915_gem_context_unreference() - * can then free the base object correctly. */ - WARN_ON(!dev_priv->ring[RCS].last_context); - if (dev_priv->ring[RCS].last_context == dctx) { - /* Fake switch to NULL context */ - WARN_ON(dctx->obj->active); - i915_gem_object_ggtt_unpin(dctx->obj); - i915_gem_context_unreference(dctx); - dev_priv->ring[RCS].last_context = NULL; + if (dctx->obj) { + /* The only known way to stop the gpu from accessing the hw context is + * to reset it. Do this as the very last operation to avoid confusing + * other code, leading to spurious errors. */ + intel_gpu_reset(dev); + + /* When default context is created and switched to, base object refcount + * will be 2 (+1 from object creation and +1 from do_switch()). + * i915_gem_context_fini() will be called after gpu_idle() has switched + * to default context. So we need to unreference the base object once + * to offset the do_switch part, so that i915_gem_context_unreference() + * can then free the base object correctly. */ + WARN_ON(!dev_priv->ring[RCS].last_context); + if (dev_priv->ring[RCS].last_context == dctx) { + /* Fake switch to NULL context */ + WARN_ON(dctx->obj->active); + i915_gem_object_ggtt_unpin(dctx->obj); + i915_gem_context_unreference(dctx); + dev_priv->ring[RCS].last_context = NULL; + } } for (i = 0; i < I915_NUM_RINGS; i++) { struct intel_ring_buffer *ring = &dev_priv->ring[i]; - if (!(INTEL_INFO(dev)->ring_mask & (1<last_context) i915_gem_context_unreference(ring->last_context); @@ -478,7 +455,6 @@ void i915_gem_context_fini(struct drm_device *dev) i915_gem_object_ggtt_unpin(dctx->obj); i915_gem_context_unreference(dctx); - dev_priv->mm.aliasing_ppgtt = NULL; } int i915_gem_context_enable(struct drm_i915_private *dev_priv) @@ -486,9 +462,6 @@ int i915_gem_context_enable(struct drm_i915_private *dev_priv) struct intel_ring_buffer *ring; int ret, i; - if (!HAS_HW_CONTEXTS(dev_priv->dev)) - return 0; - /* This is the only place the aliasing PPGTT gets enabled, which means * it has to happen before we bail on reset */ if (dev_priv->mm.aliasing_ppgtt) { @@ -503,7 +476,7 @@ int i915_gem_context_enable(struct drm_i915_private *dev_priv) BUG_ON(!dev_priv->ring[RCS].default_context); for_each_ring(ring, dev_priv, i) { - ret = do_switch(ring, ring->default_context); + ret = i915_switch_context(ring, ring->default_context); if (ret) return ret; } @@ -526,19 +499,6 @@ static int context_idr_cleanup(int id, void *p, void *data) int i915_gem_context_open(struct drm_device *dev, struct drm_file *file) { struct drm_i915_file_private *file_priv = file->driver_priv; - struct drm_i915_private *dev_priv = dev->dev_private; - - if (!HAS_HW_CONTEXTS(dev)) { - /* Cheat for hang stats */ - file_priv->private_default_ctx = - kzalloc(sizeof(struct i915_hw_context), GFP_KERNEL); - - if (file_priv->private_default_ctx == NULL) - return -ENOMEM; - - file_priv->private_default_ctx->vm = &dev_priv->gtt.base; - return 0; - } idr_init(&file_priv->context_idr); @@ -559,14 +519,10 @@ void i915_gem_context_close(struct drm_device *dev, struct drm_file *file) { struct drm_i915_file_private *file_priv = file->driver_priv; - if (!HAS_HW_CONTEXTS(dev)) { - kfree(file_priv->private_default_ctx); - return; - } - idr_for_each(&file_priv->context_idr, context_idr_cleanup, NULL); - i915_gem_context_unreference(file_priv->private_default_ctx); idr_destroy(&file_priv->context_idr); + + i915_gem_context_unreference(file_priv->private_default_ctx); } struct i915_hw_context * @@ -574,9 +530,6 @@ i915_gem_context_get(struct drm_i915_file_private *file_priv, u32 id) { struct i915_hw_context *ctx; - if (!HAS_HW_CONTEXTS(file_priv->dev_priv->dev)) - return file_priv->private_default_ctx; - ctx = (struct i915_hw_context *)idr_find(&file_priv->context_idr, id); if (!ctx) return ERR_PTR(-ENOENT); @@ -758,7 +711,6 @@ unpin_out: /** * i915_switch_context() - perform a GPU context switch. * @ring: ring for which we'll execute the context switch - * @file_priv: file_priv associated with the context, may be NULL * @to: the context to switch to * * The context life cycle is simple. The context refcount is incremented and @@ -767,24 +719,30 @@ unpin_out: * object while letting the normal object tracking destroy the backing BO. */ int i915_switch_context(struct intel_ring_buffer *ring, - struct drm_file *file, struct i915_hw_context *to) { struct drm_i915_private *dev_priv = ring->dev->dev_private; WARN_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex)); - BUG_ON(file && to == NULL); - - /* We have the fake context */ - if (!HAS_HW_CONTEXTS(ring->dev)) { - ring->last_context = to; + if (to->obj == NULL) { /* We have the fake context */ + if (to != ring->last_context) { + i915_gem_context_reference(to); + if (ring->last_context) + i915_gem_context_unreference(ring->last_context); + ring->last_context = to; + } return 0; } return do_switch(ring, to); } +static bool hw_context_enabled(struct drm_device *dev) +{ + return to_i915(dev)->hw_context_size; +} + int i915_gem_context_create_ioctl(struct drm_device *dev, void *data, struct drm_file *file) { @@ -793,7 +751,7 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data, struct i915_hw_context *ctx; int ret; - if (!HAS_HW_CONTEXTS(dev)) + if (!hw_context_enabled(dev)) return -ENODEV; ret = i915_mutex_lock_interruptible(dev); diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 7447160155a..2c9d9cbaf65 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1221,7 +1221,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, if (ret) goto err; - ret = i915_switch_context(ring, file, ctx); + ret = i915_switch_context(ring, ctx); if (ret) goto err; -- cgit v1.2.3-70-g09d2 From e106e4ea44699cc940a919924f2834b91f426d9f Mon Sep 17 00:00:00 2001 From: Peter Oberparleiter Date: Wed, 9 Apr 2014 13:10:05 +0200 Subject: s390/sclp_vt220: Fix kernel panic due to early terminal input A kernel panic might occur when there is terminal input available via the SCLP VT220 interface at an early time during the boot process. The processing of terminal input requires prior initialization which is done via an early_initcall function (init_workqueues) while the SCLP VT220 driver registers for terminal input during a console_initcall function (sclp_vt220_con_init). When there is terminal input available via the SCLP interface between console_initcall and early_initcall, a null pointer dereference occurs (system_wq is null). Fix this problem by moving the registration for terminal input to a device_initcall function (sclp_vt220_tty_init). Reported-by: Christian Borntraeger Tested-by: Christian Borntraeger Signed-off-by: Peter Oberparleiter Signed-off-by: Martin Schwidefsky --- drivers/s390/char/sclp_vt220.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c index 4eed38cd0af..cd9c9190959 100644 --- a/drivers/s390/char/sclp_vt220.c +++ b/drivers/s390/char/sclp_vt220.c @@ -97,13 +97,16 @@ static void sclp_vt220_pm_event_fn(struct sclp_register *reg, static int __sclp_vt220_emit(struct sclp_vt220_request *request); static void sclp_vt220_emit_current(void); -/* Registration structure for our interest in SCLP event buffers */ +/* Registration structure for SCLP output event buffers */ static struct sclp_register sclp_vt220_register = { .send_mask = EVTYP_VT220MSG_MASK, + .pm_event_fn = sclp_vt220_pm_event_fn, +}; + +/* Registration structure for SCLP input event buffers */ +static struct sclp_register sclp_vt220_register_input = { .receive_mask = EVTYP_VT220MSG_MASK, - .state_change_fn = NULL, .receiver_fn = sclp_vt220_receiver_fn, - .pm_event_fn = sclp_vt220_pm_event_fn, }; @@ -715,9 +718,14 @@ static int __init sclp_vt220_tty_init(void) rc = tty_register_driver(driver); if (rc) goto out_init; + rc = sclp_register(&sclp_vt220_register_input); + if (rc) + goto out_reg; sclp_vt220_driver = driver; return 0; +out_reg: + tty_unregister_driver(driver); out_init: __sclp_vt220_cleanup(); out_driver: -- cgit v1.2.3-70-g09d2 From 83d8e2527641b0710834bceeae5a681ffa759e1e Mon Sep 17 00:00:00 2001 From: Duan Jiong Date: Fri, 11 Apr 2014 13:39:06 +0200 Subject: s390/sclp: replace PTR_RET with PTR_ERR_OR_ZERO PTR_RET is deprecated. Do not recommend its usage anymore. Use PTR_ERR_OR_ZERO instead. Signed-off-by: Duan Jiong Signed-off-by: Martin Schwidefsky --- drivers/s390/char/sclp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c index 1990285296c..c316051d9bd 100644 --- a/drivers/s390/char/sclp.c +++ b/drivers/s390/char/sclp.c @@ -1252,7 +1252,7 @@ static __init int sclp_initcall(void) return rc; sclp_pdev = platform_device_register_simple("sclp", -1, NULL, 0); - rc = PTR_RET(sclp_pdev); + rc = PTR_ERR_OR_ZERO(sclp_pdev); if (rc) goto fail_platform_driver_unregister; -- cgit v1.2.3-70-g09d2 From 5896f8fe491891f551bdc6574bbc4a07c054c30b Mon Sep 17 00:00:00 2001 From: Duan Jiong Date: Fri, 11 Apr 2014 13:41:54 +0200 Subject: s390/sclp_cmd: replace PTR_RET with PTR_ERR_OR_ZERO PTR_RET is deprecated. Do not recommend its usage anymore. Use PTR_ERR_OR_ZERO instead. Signed-off-by: Duan Jiong Signed-off-by: Martin Schwidefsky --- drivers/s390/char/sclp_cmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/s390/char/sclp_cmd.c b/drivers/s390/char/sclp_cmd.c index 6e8f90f84e4..6e14999f9e8 100644 --- a/drivers/s390/char/sclp_cmd.c +++ b/drivers/s390/char/sclp_cmd.c @@ -515,7 +515,7 @@ static int __init sclp_detect_standby_memory(void) if (rc) goto out; sclp_pdev = platform_device_register_simple("sclp_mem", -1, NULL, 0); - rc = PTR_RET(sclp_pdev); + rc = PTR_ERR_OR_ZERO(sclp_pdev); if (rc) goto out_driver; sclp_add_standby_memory(); -- cgit v1.2.3-70-g09d2 From fa658a98a2d08352c514758b3394caf91360aa44 Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Wed, 9 Apr 2014 09:38:25 -0500 Subject: RDMA/cxgb4: Use the BAR2/WC path for kernel QPs and T5 devices Signed-off-by: Steve Wise [ Fix cast from u64* to integer. - Roland ] Signed-off-by: Roland Dreier --- drivers/infiniband/hw/cxgb4/device.c | 41 ++++++++++++++++++----- drivers/infiniband/hw/cxgb4/iw_cxgb4.h | 2 ++ drivers/infiniband/hw/cxgb4/qp.c | 57 ++++++++++++++++++++------------ drivers/infiniband/hw/cxgb4/t4.h | 60 +++++++++++++++++++++++++++++++--- 4 files changed, 127 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/cxgb4/device.c b/drivers/infiniband/hw/cxgb4/device.c index 9489a388376..f4fa50a609e 100644 --- a/drivers/infiniband/hw/cxgb4/device.c +++ b/drivers/infiniband/hw/cxgb4/device.c @@ -682,7 +682,10 @@ static void c4iw_dealloc(struct uld_ctx *ctx) idr_destroy(&ctx->dev->hwtid_idr); idr_destroy(&ctx->dev->stid_idr); idr_destroy(&ctx->dev->atid_idr); - iounmap(ctx->dev->rdev.oc_mw_kva); + if (ctx->dev->rdev.bar2_kva) + iounmap(ctx->dev->rdev.bar2_kva); + if (ctx->dev->rdev.oc_mw_kva) + iounmap(ctx->dev->rdev.oc_mw_kva); ib_dealloc_device(&ctx->dev->ibdev); ctx->dev = NULL; } @@ -722,11 +725,31 @@ static struct c4iw_dev *c4iw_alloc(const struct cxgb4_lld_info *infop) } devp->rdev.lldi = *infop; - devp->rdev.oc_mw_pa = pci_resource_start(devp->rdev.lldi.pdev, 2) + - (pci_resource_len(devp->rdev.lldi.pdev, 2) - - roundup_pow_of_two(devp->rdev.lldi.vr->ocq.size)); - devp->rdev.oc_mw_kva = ioremap_wc(devp->rdev.oc_mw_pa, - devp->rdev.lldi.vr->ocq.size); + /* + * For T5 devices, we map all of BAR2 with WC. + * For T4 devices with onchip qp mem, we map only that part + * of BAR2 with WC. + */ + devp->rdev.bar2_pa = pci_resource_start(devp->rdev.lldi.pdev, 2); + if (is_t5(devp->rdev.lldi.adapter_type)) { + devp->rdev.bar2_kva = ioremap_wc(devp->rdev.bar2_pa, + pci_resource_len(devp->rdev.lldi.pdev, 2)); + if (!devp->rdev.bar2_kva) { + pr_err(MOD "Unable to ioremap BAR2\n"); + return ERR_PTR(-EINVAL); + } + } else if (ocqp_supported(infop)) { + devp->rdev.oc_mw_pa = + pci_resource_start(devp->rdev.lldi.pdev, 2) + + pci_resource_len(devp->rdev.lldi.pdev, 2) - + roundup_pow_of_two(devp->rdev.lldi.vr->ocq.size); + devp->rdev.oc_mw_kva = ioremap_wc(devp->rdev.oc_mw_pa, + devp->rdev.lldi.vr->ocq.size); + if (!devp->rdev.oc_mw_kva) { + pr_err(MOD "Unable to ioremap onchip mem\n"); + return ERR_PTR(-EINVAL); + } + } PDBG(KERN_INFO MOD "ocq memory: " "hw_start 0x%x size %u mw_pa 0x%lx mw_kva %p\n", @@ -1003,9 +1026,11 @@ static int enable_qp_db(int id, void *p, void *data) static void resume_rc_qp(struct c4iw_qp *qp) { spin_lock(&qp->lock); - t4_ring_sq_db(&qp->wq, qp->wq.sq.wq_pidx_inc); + t4_ring_sq_db(&qp->wq, qp->wq.sq.wq_pidx_inc, + is_t5(qp->rhp->rdev.lldi.adapter_type), NULL); qp->wq.sq.wq_pidx_inc = 0; - t4_ring_rq_db(&qp->wq, qp->wq.rq.wq_pidx_inc); + t4_ring_rq_db(&qp->wq, qp->wq.rq.wq_pidx_inc, + is_t5(qp->rhp->rdev.lldi.adapter_type), NULL); qp->wq.rq.wq_pidx_inc = 0; spin_unlock(&qp->lock); } diff --git a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h index e872203c542..7b8c5806a09 100644 --- a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h +++ b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h @@ -149,6 +149,8 @@ struct c4iw_rdev { struct gen_pool *ocqp_pool; u32 flags; struct cxgb4_lld_info lldi; + unsigned long bar2_pa; + void __iomem *bar2_kva; unsigned long oc_mw_pa; void __iomem *oc_mw_kva; struct c4iw_stats stats; diff --git a/drivers/infiniband/hw/cxgb4/qp.c b/drivers/infiniband/hw/cxgb4/qp.c index cb76eb5eee1..e2fcbf4814f 100644 --- a/drivers/infiniband/hw/cxgb4/qp.c +++ b/drivers/infiniband/hw/cxgb4/qp.c @@ -212,13 +212,23 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq, wq->db = rdev->lldi.db_reg; wq->gts = rdev->lldi.gts_reg; - if (user) { - wq->sq.udb = (u64)pci_resource_start(rdev->lldi.pdev, 2) + - (wq->sq.qid << rdev->qpshift); - wq->sq.udb &= PAGE_MASK; - wq->rq.udb = (u64)pci_resource_start(rdev->lldi.pdev, 2) + - (wq->rq.qid << rdev->qpshift); - wq->rq.udb &= PAGE_MASK; + if (user || is_t5(rdev->lldi.adapter_type)) { + u32 off; + + off = (wq->sq.qid << rdev->qpshift) & PAGE_MASK; + if (user) { + wq->sq.udb = (u64 __iomem *)(rdev->bar2_pa + off); + } else { + off += 128 * (wq->sq.qid & rdev->qpmask) + 8; + wq->sq.udb = (u64 __iomem *)(rdev->bar2_kva + off); + } + off = (wq->rq.qid << rdev->qpshift) & PAGE_MASK; + if (user) { + wq->rq.udb = (u64 __iomem *)(rdev->bar2_pa + off); + } else { + off += 128 * (wq->rq.qid & rdev->qpmask) + 8; + wq->rq.udb = (u64 __iomem *)(rdev->bar2_kva + off); + } } wq->rdev = rdev; wq->rq.msn = 1; @@ -299,9 +309,10 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq, if (ret) goto free_dma; - PDBG("%s sqid 0x%x rqid 0x%x kdb 0x%p squdb 0x%llx rqudb 0x%llx\n", + PDBG("%s sqid 0x%x rqid 0x%x kdb 0x%p squdb 0x%lx rqudb 0x%lx\n", __func__, wq->sq.qid, wq->rq.qid, wq->db, - (unsigned long long)wq->sq.udb, (unsigned long long)wq->rq.udb); + (__force unsigned long) wq->sq.udb, + (__force unsigned long) wq->rq.udb); return 0; free_dma: @@ -650,9 +661,10 @@ static int ring_kernel_sq_db(struct c4iw_qp *qhp, u16 inc) spin_lock_irqsave(&qhp->rhp->lock, flags); spin_lock(&qhp->lock); - if (qhp->rhp->db_state == NORMAL) { - t4_ring_sq_db(&qhp->wq, inc); - } else { + if (qhp->rhp->db_state == NORMAL) + t4_ring_sq_db(&qhp->wq, inc, + is_t5(qhp->rhp->rdev.lldi.adapter_type), NULL); + else { add_to_fc_list(&qhp->rhp->db_fc_list, &qhp->db_fc_entry); qhp->wq.sq.wq_pidx_inc += inc; } @@ -667,9 +679,10 @@ static int ring_kernel_rq_db(struct c4iw_qp *qhp, u16 inc) spin_lock_irqsave(&qhp->rhp->lock, flags); spin_lock(&qhp->lock); - if (qhp->rhp->db_state == NORMAL) { - t4_ring_rq_db(&qhp->wq, inc); - } else { + if (qhp->rhp->db_state == NORMAL) + t4_ring_rq_db(&qhp->wq, inc, + is_t5(qhp->rhp->rdev.lldi.adapter_type), NULL); + else { add_to_fc_list(&qhp->rhp->db_fc_list, &qhp->db_fc_entry); qhp->wq.rq.wq_pidx_inc += inc; } @@ -686,7 +699,7 @@ int c4iw_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, enum fw_wr_opcodes fw_opcode = 0; enum fw_ri_wr_flags fw_flags; struct c4iw_qp *qhp; - union t4_wr *wqe; + union t4_wr *wqe = NULL; u32 num_wrs; struct t4_swsqe *swsqe; unsigned long flag; @@ -792,7 +805,8 @@ int c4iw_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, idx += DIV_ROUND_UP(len16*16, T4_EQ_ENTRY_SIZE); } if (!qhp->rhp->rdev.status_page->db_off) { - t4_ring_sq_db(&qhp->wq, idx); + t4_ring_sq_db(&qhp->wq, idx, + is_t5(qhp->rhp->rdev.lldi.adapter_type), wqe); spin_unlock_irqrestore(&qhp->lock, flag); } else { spin_unlock_irqrestore(&qhp->lock, flag); @@ -806,7 +820,7 @@ int c4iw_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr, { int err = 0; struct c4iw_qp *qhp; - union t4_recv_wr *wqe; + union t4_recv_wr *wqe = NULL; u32 num_wrs; u8 len16 = 0; unsigned long flag; @@ -858,7 +872,8 @@ int c4iw_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr, num_wrs--; } if (!qhp->rhp->rdev.status_page->db_off) { - t4_ring_rq_db(&qhp->wq, idx); + t4_ring_rq_db(&qhp->wq, idx, + is_t5(qhp->rhp->rdev.lldi.adapter_type), wqe); spin_unlock_irqrestore(&qhp->lock, flag); } else { spin_unlock_irqrestore(&qhp->lock, flag); @@ -1677,11 +1692,11 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs, mm2->len = PAGE_ALIGN(qhp->wq.rq.memsize); insert_mmap(ucontext, mm2); mm3->key = uresp.sq_db_gts_key; - mm3->addr = qhp->wq.sq.udb; + mm3->addr = (__force unsigned long) qhp->wq.sq.udb; mm3->len = PAGE_SIZE; insert_mmap(ucontext, mm3); mm4->key = uresp.rq_db_gts_key; - mm4->addr = qhp->wq.rq.udb; + mm4->addr = (__force unsigned long) qhp->wq.rq.udb; mm4->len = PAGE_SIZE; insert_mmap(ucontext, mm4); if (mm5) { diff --git a/drivers/infiniband/hw/cxgb4/t4.h b/drivers/infiniband/hw/cxgb4/t4.h index eeca8b1e637..931bfd105c4 100644 --- a/drivers/infiniband/hw/cxgb4/t4.h +++ b/drivers/infiniband/hw/cxgb4/t4.h @@ -292,7 +292,7 @@ struct t4_sq { unsigned long phys_addr; struct t4_swsqe *sw_sq; struct t4_swsqe *oldest_read; - u64 udb; + u64 __iomem *udb; size_t memsize; u32 qid; u16 in_use; @@ -314,7 +314,7 @@ struct t4_rq { dma_addr_t dma_addr; DEFINE_DMA_UNMAP_ADDR(mapping); struct t4_swrqe *sw_rq; - u64 udb; + u64 __iomem *udb; size_t memsize; u32 qid; u32 msn; @@ -435,15 +435,67 @@ static inline u16 t4_sq_wq_size(struct t4_wq *wq) return wq->sq.size * T4_SQ_NUM_SLOTS; } -static inline void t4_ring_sq_db(struct t4_wq *wq, u16 inc) +/* This function copies 64 byte coalesced work request to memory + * mapped BAR2 space. For coalesced WRs, the SGE fetches data + * from the FIFO instead of from Host. + */ +static inline void pio_copy(u64 __iomem *dst, u64 *src) +{ + int count = 8; + + while (count) { + writeq(*src, dst); + src++; + dst++; + count--; + } +} + +static inline void t4_ring_sq_db(struct t4_wq *wq, u16 inc, u8 t5, + union t4_wr *wqe) { + + /* Flush host queue memory writes. */ wmb(); + if (t5) { + if (inc == 1 && wqe) { + PDBG("%s: WC wq->sq.pidx = %d\n", + __func__, wq->sq.pidx); + pio_copy(wq->sq.udb + 7, (void *)wqe); + } else { + PDBG("%s: DB wq->sq.pidx = %d\n", + __func__, wq->sq.pidx); + writel(PIDX_T5(inc), wq->sq.udb); + } + + /* Flush user doorbell area writes. */ + wmb(); + return; + } writel(QID(wq->sq.qid) | PIDX(inc), wq->db); } -static inline void t4_ring_rq_db(struct t4_wq *wq, u16 inc) +static inline void t4_ring_rq_db(struct t4_wq *wq, u16 inc, u8 t5, + union t4_recv_wr *wqe) { + + /* Flush host queue memory writes. */ wmb(); + if (t5) { + if (inc == 1 && wqe) { + PDBG("%s: WC wq->rq.pidx = %d\n", + __func__, wq->rq.pidx); + pio_copy(wq->rq.udb + 7, (void *)wqe); + } else { + PDBG("%s: DB wq->rq.pidx = %d\n", + __func__, wq->rq.pidx); + writel(PIDX_T5(inc), wq->rq.udb); + } + + /* Flush user doorbell area writes. */ + wmb(); + return; + } writel(QID(wq->rq.qid) | PIDX(inc), wq->db); } -- cgit v1.2.3-70-g09d2 From b33bd0cbfa102b8f87702338aa72742fe3c7f220 Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Wed, 9 Apr 2014 09:38:25 -0500 Subject: RDMA/cxgb4: Endpoint timeout fixes 1) timedout endpoint processing can be starved. If there are continual CPL messages flowing into the driver, the endpoint timeout processing can be starved. This condition exposed the other bugs below. Solution: In process_work(), call process_timedout_eps() after each CPL is processed. 2) Connection events can be processed even though the endpoint is on the timeout list. If the endpoint is scheduled for timeout processing, then we must ignore MPA Start Requests and Replies. Solution: Change stop_ep_timer() to return 1 if the ep has already been queued for timeout processing. All the callers of stop_ep_timer() need to check this and act accordingly. There are just a few cases where the caller needs to do something different if stop_ep_timer() returns 1: 1) in process_mpa_reply(), ignore the reply and process_timeout() will abort the connection. 2) in process_mpa_request, ignore the request and process_timeout() will abort the connection. It is ok for callers of stop_ep_timer() to abort the connection since that will leave the state in ABORTING or DEAD, and process_timeout() now ignores timeouts when the ep is in these states. 3) Double insertion on the timeout list. Since the endpoint timers are used for connection setup and teardown, we need to guard against the possibility that an endpoint is already on the timeout list. This is a rare condition and only seen under heavy load and in the presense of the above 2 bugs. Solution: In ep_timeout(), don't queue the endpoint if it is already on the queue. Signed-off-by: Steve Wise Signed-off-by: Roland Dreier --- drivers/infiniband/hw/cxgb4/cm.c | 89 +++++++++++++++++++++++++--------------- 1 file changed, 56 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c index 02436d5d0da..185452abf32 100644 --- a/drivers/infiniband/hw/cxgb4/cm.c +++ b/drivers/infiniband/hw/cxgb4/cm.c @@ -173,12 +173,15 @@ static void start_ep_timer(struct c4iw_ep *ep) add_timer(&ep->timer); } -static void stop_ep_timer(struct c4iw_ep *ep) +static int stop_ep_timer(struct c4iw_ep *ep) { PDBG("%s ep %p stopping\n", __func__, ep); del_timer_sync(&ep->timer); - if (!test_and_set_bit(TIMEOUT, &ep->com.flags)) + if (!test_and_set_bit(TIMEOUT, &ep->com.flags)) { c4iw_put_ep(&ep->com); + return 0; + } + return 1; } static int c4iw_l2t_send(struct c4iw_rdev *rdev, struct sk_buff *skb, @@ -1165,12 +1168,11 @@ static void process_mpa_reply(struct c4iw_ep *ep, struct sk_buff *skb) PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid); /* - * Stop mpa timer. If it expired, then the state has - * changed and we bail since ep_timeout already aborted - * the connection. + * Stop mpa timer. If it expired, then + * we ignore the MPA reply. process_timeout() + * will abort the connection. */ - stop_ep_timer(ep); - if (ep->com.state != MPA_REQ_SENT) + if (stop_ep_timer(ep)) return; /* @@ -1375,15 +1377,12 @@ static void process_mpa_request(struct c4iw_ep *ep, struct sk_buff *skb) PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid); - if (ep->com.state != MPA_REQ_WAIT) - return; - /* * If we get more than the supported amount of private data * then we must fail this connection. */ if (ep->mpa_pkt_len + skb->len > sizeof(ep->mpa_pkt)) { - stop_ep_timer(ep); + (void)stop_ep_timer(ep); abort_connection(ep, skb, GFP_KERNEL); return; } @@ -1413,13 +1412,13 @@ static void process_mpa_request(struct c4iw_ep *ep, struct sk_buff *skb) if (mpa->revision > mpa_rev) { printk(KERN_ERR MOD "%s MPA version mismatch. Local = %d," " Received = %d\n", __func__, mpa_rev, mpa->revision); - stop_ep_timer(ep); + (void)stop_ep_timer(ep); abort_connection(ep, skb, GFP_KERNEL); return; } if (memcmp(mpa->key, MPA_KEY_REQ, sizeof(mpa->key))) { - stop_ep_timer(ep); + (void)stop_ep_timer(ep); abort_connection(ep, skb, GFP_KERNEL); return; } @@ -1430,7 +1429,7 @@ static void process_mpa_request(struct c4iw_ep *ep, struct sk_buff *skb) * Fail if there's too much private data. */ if (plen > MPA_MAX_PRIVATE_DATA) { - stop_ep_timer(ep); + (void)stop_ep_timer(ep); abort_connection(ep, skb, GFP_KERNEL); return; } @@ -1439,7 +1438,7 @@ static void process_mpa_request(struct c4iw_ep *ep, struct sk_buff *skb) * If plen does not account for pkt size */ if (ep->mpa_pkt_len > (sizeof(*mpa) + plen)) { - stop_ep_timer(ep); + (void)stop_ep_timer(ep); abort_connection(ep, skb, GFP_KERNEL); return; } @@ -1496,18 +1495,24 @@ static void process_mpa_request(struct c4iw_ep *ep, struct sk_buff *skb) ep->mpa_attr.xmit_marker_enabled, ep->mpa_attr.version, ep->mpa_attr.p2p_type); - __state_set(&ep->com, MPA_REQ_RCVD); - stop_ep_timer(ep); - - /* drive upcall */ - mutex_lock(&ep->parent_ep->com.mutex); - if (ep->parent_ep->com.state != DEAD) { - if (connect_request_upcall(ep)) + /* + * If the endpoint timer already expired, then we ignore + * the start request. process_timeout() will abort + * the connection. + */ + if (!stop_ep_timer(ep)) { + __state_set(&ep->com, MPA_REQ_RCVD); + + /* drive upcall */ + mutex_lock(&ep->parent_ep->com.mutex); + if (ep->parent_ep->com.state != DEAD) { + if (connect_request_upcall(ep)) + abort_connection(ep, skb, GFP_KERNEL); + } else { abort_connection(ep, skb, GFP_KERNEL); - } else { - abort_connection(ep, skb, GFP_KERNEL); + } + mutex_unlock(&ep->parent_ep->com.mutex); } - mutex_unlock(&ep->parent_ep->com.mutex); return; } @@ -2265,7 +2270,7 @@ static int peer_close(struct c4iw_dev *dev, struct sk_buff *skb) disconnect = 0; break; case MORIBUND: - stop_ep_timer(ep); + (void)stop_ep_timer(ep); if (ep->com.cm_id && ep->com.qp) { attrs.next_state = C4IW_QP_STATE_IDLE; c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp, @@ -2325,10 +2330,10 @@ static int peer_abort(struct c4iw_dev *dev, struct sk_buff *skb) case CONNECTING: break; case MPA_REQ_WAIT: - stop_ep_timer(ep); + (void)stop_ep_timer(ep); break; case MPA_REQ_SENT: - stop_ep_timer(ep); + (void)stop_ep_timer(ep); if (mpa_rev == 1 || (mpa_rev == 2 && ep->tried_with_mpa_v1)) connect_reply_upcall(ep, -ECONNRESET); else { @@ -2433,7 +2438,7 @@ static int close_con_rpl(struct c4iw_dev *dev, struct sk_buff *skb) __state_set(&ep->com, MORIBUND); break; case MORIBUND: - stop_ep_timer(ep); + (void)stop_ep_timer(ep); if ((ep->com.cm_id) && (ep->com.qp)) { attrs.next_state = C4IW_QP_STATE_IDLE; c4iw_modify_qp(ep->com.qp->rhp, @@ -3028,7 +3033,7 @@ int c4iw_ep_disconnect(struct c4iw_ep *ep, int abrupt, gfp_t gfp) if (!test_and_set_bit(CLOSE_SENT, &ep->com.flags)) { close = 1; if (abrupt) { - stop_ep_timer(ep); + (void)stop_ep_timer(ep); ep->com.state = ABORTING; } else ep->com.state = MORIBUND; @@ -3462,6 +3467,16 @@ static void process_timeout(struct c4iw_ep *ep) __state_set(&ep->com, ABORTING); close_complete_upcall(ep, -ETIMEDOUT); break; + case ABORTING: + case DEAD: + + /* + * These states are expected if the ep timed out at the same + * time as another thread was calling stop_ep_timer(). + * So we silently do nothing for these states. + */ + abort = 0; + break; default: WARN(1, "%s unexpected state ep %p tid %u state %u\n", __func__, ep, ep->hwtid, ep->com.state); @@ -3483,6 +3498,8 @@ static void process_timedout_eps(void) tmp = timeout_list.next; list_del(tmp); + tmp->next = NULL; + tmp->prev = NULL; spin_unlock_irq(&timeout_lock); ep = list_entry(tmp, struct c4iw_ep, entry); process_timeout(ep); @@ -3499,6 +3516,7 @@ static void process_work(struct work_struct *work) unsigned int opcode; int ret; + process_timedout_eps(); while ((skb = skb_dequeue(&rxq))) { rpl = cplhdr(skb); dev = *((struct c4iw_dev **) (skb->cb + sizeof(void *))); @@ -3508,8 +3526,8 @@ static void process_work(struct work_struct *work) ret = work_handlers[opcode](dev, skb); if (!ret) kfree_skb(skb); + process_timedout_eps(); } - process_timedout_eps(); } static DECLARE_WORK(skb_work, process_work); @@ -3521,8 +3539,13 @@ static void ep_timeout(unsigned long arg) spin_lock(&timeout_lock); if (!test_and_set_bit(TIMEOUT, &ep->com.flags)) { - list_add_tail(&ep->entry, &timeout_list); - kickit = 1; + /* + * Only insert if it is not already on the list. + */ + if (!ep->entry.next) { + list_add_tail(&ep->entry, &timeout_list); + kickit = 1; + } } spin_unlock(&timeout_lock); if (kickit) -- cgit v1.2.3-70-g09d2 From def4771f4bf428d39c7fe6006a9e1a20ee380d1e Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Wed, 9 Apr 2014 09:38:26 -0500 Subject: RDMA/cxgb4: rmb() after reading valid gen bit Some HW platforms can reorder read operations, so we must rmb() after we see a valid gen bit in a CQE but before we read any other fields from the CQE. Signed-off-by: Steve Wise Signed-off-by: Roland Dreier --- drivers/infiniband/hw/cxgb4/t4.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/infiniband/hw/cxgb4/t4.h b/drivers/infiniband/hw/cxgb4/t4.h index 931bfd105c4..1f329fac980 100644 --- a/drivers/infiniband/hw/cxgb4/t4.h +++ b/drivers/infiniband/hw/cxgb4/t4.h @@ -620,6 +620,9 @@ static inline int t4_next_hw_cqe(struct t4_cq *cq, struct t4_cqe **cqe) printk(KERN_ERR MOD "cq overflow cqid %u\n", cq->cqid); BUG_ON(1); } else if (t4_valid_cqe(cq, &cq->queue[cq->cidx])) { + + /* Ensure CQE is flushed to memory */ + rmb(); *cqe = &cq->queue[cq->cidx]; ret = 0; } else -- cgit v1.2.3-70-g09d2 From b4e2901c52cc79f287e2b25804e029880e5e4b07 Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Wed, 9 Apr 2014 09:38:26 -0500 Subject: RDMA/cxgb4: SQ flush fix There is a race when moving a QP from RTS->CLOSING where a SQ work request could be posted after the FW receives the RDMA_RI/FINI WR. The SQ work request will never get processed, and should be completed with FLUSHED status. Function c4iw_flush_sq(), however was dropping the oldest SQ work request when in CLOSING or IDLE states, instead of completing the pending work request. If that oldest pending work request was actually complete and has a CQE in the CQ, then when that CQE is proceessed in poll_cq, we'll BUG_ON() due to the inconsistent SQ/CQ state. This is a very small timing hole and has only been hit once so far. The fix is two-fold: 1) c4iw_flush_sq() MUST always flush all non-completed WRs with FLUSHED status regardless of the QP state. 2) In c4iw_modify_rc_qp(), always set the "in error" bit on the queue before moving the state out of RTS. This ensures that the state transition will not happen while another thread is in post_rc_send(), because set_state() and post_rc_send() both aquire the qp spinlock. Also, once we transition the state out of RTS, subsequent calls to post_rc_send() will fail because the "in error" bit is set. I don't think this fully closes the race where the FW can get a FINI followed a SQ work request being posted (because they are posted to differente EQs), but the #1 fix will handle the issue by flushing the SQ work request. Signed-off-by: Steve Wise Signed-off-by: Roland Dreier --- drivers/infiniband/hw/cxgb4/cq.c | 22 ++++++++-------------- drivers/infiniband/hw/cxgb4/qp.c | 6 +++--- 2 files changed, 11 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/cxgb4/cq.c b/drivers/infiniband/hw/cxgb4/cq.c index ce468e54242..e17b155b375 100644 --- a/drivers/infiniband/hw/cxgb4/cq.c +++ b/drivers/infiniband/hw/cxgb4/cq.c @@ -235,27 +235,21 @@ int c4iw_flush_sq(struct c4iw_qp *qhp) struct t4_cq *cq = &chp->cq; int idx; struct t4_swsqe *swsqe; - int error = (qhp->attr.state != C4IW_QP_STATE_CLOSING && - qhp->attr.state != C4IW_QP_STATE_IDLE); if (wq->sq.flush_cidx == -1) wq->sq.flush_cidx = wq->sq.cidx; idx = wq->sq.flush_cidx; BUG_ON(idx >= wq->sq.size); while (idx != wq->sq.pidx) { - if (error) { - swsqe = &wq->sq.sw_sq[idx]; - BUG_ON(swsqe->flushed); - swsqe->flushed = 1; - insert_sq_cqe(wq, cq, swsqe); - if (wq->sq.oldest_read == swsqe) { - BUG_ON(swsqe->opcode != FW_RI_READ_REQ); - advance_oldest_read(wq); - } - flushed++; - } else { - t4_sq_consume(wq); + swsqe = &wq->sq.sw_sq[idx]; + BUG_ON(swsqe->flushed); + swsqe->flushed = 1; + insert_sq_cqe(wq, cq, swsqe); + if (wq->sq.oldest_read == swsqe) { + BUG_ON(swsqe->opcode != FW_RI_READ_REQ); + advance_oldest_read(wq); } + flushed++; if (++idx == wq->sq.size) idx = 0; } diff --git a/drivers/infiniband/hw/cxgb4/qp.c b/drivers/infiniband/hw/cxgb4/qp.c index e2fcbf4814f..9b4a8b88908 100644 --- a/drivers/infiniband/hw/cxgb4/qp.c +++ b/drivers/infiniband/hw/cxgb4/qp.c @@ -1367,6 +1367,7 @@ int c4iw_modify_qp(struct c4iw_dev *rhp, struct c4iw_qp *qhp, switch (attrs->next_state) { case C4IW_QP_STATE_CLOSING: BUG_ON(atomic_read(&qhp->ep->com.kref.refcount) < 2); + t4_set_wq_in_error(&qhp->wq); set_state(qhp, C4IW_QP_STATE_CLOSING); ep = qhp->ep; if (!internal) { @@ -1374,16 +1375,15 @@ int c4iw_modify_qp(struct c4iw_dev *rhp, struct c4iw_qp *qhp, disconnect = 1; c4iw_get_ep(&qhp->ep->com); } - t4_set_wq_in_error(&qhp->wq); ret = rdma_fini(rhp, qhp, ep); if (ret) goto err; break; case C4IW_QP_STATE_TERMINATE: + t4_set_wq_in_error(&qhp->wq); set_state(qhp, C4IW_QP_STATE_TERMINATE); qhp->attr.layer_etype = attrs->layer_etype; qhp->attr.ecode = attrs->ecode; - t4_set_wq_in_error(&qhp->wq); ep = qhp->ep; disconnect = 1; if (!internal) @@ -1396,8 +1396,8 @@ int c4iw_modify_qp(struct c4iw_dev *rhp, struct c4iw_qp *qhp, c4iw_get_ep(&qhp->ep->com); break; case C4IW_QP_STATE_ERROR: - set_state(qhp, C4IW_QP_STATE_ERROR); t4_set_wq_in_error(&qhp->wq); + set_state(qhp, C4IW_QP_STATE_ERROR); if (!internal) { abort = 1; disconnect = 1; -- cgit v1.2.3-70-g09d2 From a03d9f94cc54199bf681729b16ba649d7206369e Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Wed, 9 Apr 2014 09:38:27 -0500 Subject: RDMA/cxgb4: Max fastreg depth depends on DSGL support The max depth of a fastreg mr depends on whether the device supports DSGL or not. So compute it dynamically based on the device support and the module use_dsgl option. Signed-off-by: Steve Wise Signed-off-by: Roland Dreier --- drivers/infiniband/hw/cxgb4/provider.c | 2 +- drivers/infiniband/hw/cxgb4/qp.c | 3 ++- drivers/infiniband/hw/cxgb4/t4.h | 9 ++++++++- 3 files changed, 11 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/cxgb4/provider.c b/drivers/infiniband/hw/cxgb4/provider.c index 79429256023..a94a3e12c34 100644 --- a/drivers/infiniband/hw/cxgb4/provider.c +++ b/drivers/infiniband/hw/cxgb4/provider.c @@ -328,7 +328,7 @@ static int c4iw_query_device(struct ib_device *ibdev, props->max_mr = c4iw_num_stags(&dev->rdev); props->max_pd = T4_MAX_NUM_PD; props->local_ca_ack_delay = 0; - props->max_fast_reg_page_list_len = T4_MAX_FR_DEPTH; + props->max_fast_reg_page_list_len = t4_max_fr_depth(use_dsgl); return 0; } diff --git a/drivers/infiniband/hw/cxgb4/qp.c b/drivers/infiniband/hw/cxgb4/qp.c index 9b4a8b88908..2c037e1746d 100644 --- a/drivers/infiniband/hw/cxgb4/qp.c +++ b/drivers/infiniband/hw/cxgb4/qp.c @@ -566,7 +566,8 @@ static int build_fastreg(struct t4_sq *sq, union t4_wr *wqe, int pbllen = roundup(wr->wr.fast_reg.page_list_len * sizeof(u64), 32); int rem; - if (wr->wr.fast_reg.page_list_len > T4_MAX_FR_DEPTH) + if (wr->wr.fast_reg.page_list_len > + t4_max_fr_depth(use_dsgl)) return -EINVAL; wqe->fr.qpbinde_to_dcacpu = 0; diff --git a/drivers/infiniband/hw/cxgb4/t4.h b/drivers/infiniband/hw/cxgb4/t4.h index 1f329fac980..2178f319841 100644 --- a/drivers/infiniband/hw/cxgb4/t4.h +++ b/drivers/infiniband/hw/cxgb4/t4.h @@ -84,7 +84,14 @@ struct t4_status_page { sizeof(struct fw_ri_isgl)) / sizeof(struct fw_ri_sge)) #define T4_MAX_FR_IMMD ((T4_SQ_NUM_BYTES - sizeof(struct fw_ri_fr_nsmr_wr) - \ sizeof(struct fw_ri_immd)) & ~31UL) -#define T4_MAX_FR_DEPTH (1024 / sizeof(u64)) +#define T4_MAX_FR_IMMD_DEPTH (T4_MAX_FR_IMMD / sizeof(u64)) +#define T4_MAX_FR_DSGL 1024 +#define T4_MAX_FR_DSGL_DEPTH (T4_MAX_FR_DSGL / sizeof(u64)) + +static inline int t4_max_fr_depth(int use_dsgl) +{ + return use_dsgl ? T4_MAX_FR_DSGL_DEPTH : T4_MAX_FR_IMMD_DEPTH; +} #define T4_RQ_NUM_SLOTS 2 #define T4_RQ_NUM_BYTES (T4_EQ_ENTRY_SIZE * T4_RQ_NUM_SLOTS) -- cgit v1.2.3-70-g09d2 From aec844df104f1e45cafd10628481f256908554c4 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Wed, 9 Apr 2014 09:38:27 -0500 Subject: RDMA/cxgb4: Use pr_warn_ratelimited Signed-off-by: Hariprasad Shenai Signed-off-by: Roland Dreier --- drivers/infiniband/hw/cxgb4/resource.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/cxgb4/resource.c b/drivers/infiniband/hw/cxgb4/resource.c index cdef4d7fb6d..94b5fd9b937 100644 --- a/drivers/infiniband/hw/cxgb4/resource.c +++ b/drivers/infiniband/hw/cxgb4/resource.c @@ -322,8 +322,8 @@ u32 c4iw_rqtpool_alloc(struct c4iw_rdev *rdev, int size) unsigned long addr = gen_pool_alloc(rdev->rqt_pool, size << 6); PDBG("%s addr 0x%x size %d\n", __func__, (u32)addr, size << 6); if (!addr) - printk_ratelimited(KERN_WARNING MOD "%s: Out of RQT memory\n", - pci_name(rdev->lldi.pdev)); + pr_warn_ratelimited(MOD "%s: Out of RQT memory\n", + pci_name(rdev->lldi.pdev)); mutex_lock(&rdev->stats.lock); if (addr) { rdev->stats.rqt.cur += roundup(size << 6, 1 << MIN_RQT_SHIFT); -- cgit v1.2.3-70-g09d2 From c3f98fa29176753a759ade424f18b11f440b19f4 Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Wed, 9 Apr 2014 09:38:27 -0500 Subject: RDMA/cxgb4: Initialize reserved fields in a FW work request Signed-off-by: Steve Wise Signed-off-by: Roland Dreier --- drivers/infiniband/hw/cxgb4/qp.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/infiniband/hw/cxgb4/qp.c b/drivers/infiniband/hw/cxgb4/qp.c index 2c037e1746d..5a7d368aa47 100644 --- a/drivers/infiniband/hw/cxgb4/qp.c +++ b/drivers/infiniband/hw/cxgb4/qp.c @@ -436,6 +436,8 @@ static int build_rdma_send(struct t4_sq *sq, union t4_wr *wqe, default: return -EINVAL; } + wqe->send.r3 = 0; + wqe->send.r4 = 0; plen = 0; if (wr->num_sge) { -- cgit v1.2.3-70-g09d2 From 98a3e879907644c0b7e2f16436eb5cf24b9cd61f Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Wed, 9 Apr 2014 09:38:28 -0500 Subject: RDMA/cxgb4: Add missing debug stats Signed-off-by: Steve Wise Signed-off-by: Roland Dreier --- drivers/infiniband/hw/cxgb4/mem.c | 6 +++++- drivers/infiniband/hw/cxgb4/resource.c | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/cxgb4/mem.c b/drivers/infiniband/hw/cxgb4/mem.c index f9ca072a99e..ec7a2988a70 100644 --- a/drivers/infiniband/hw/cxgb4/mem.c +++ b/drivers/infiniband/hw/cxgb4/mem.c @@ -259,8 +259,12 @@ static int write_tpt_entry(struct c4iw_rdev *rdev, u32 reset_tpt_entry, if ((!reset_tpt_entry) && (*stag == T4_STAG_UNSET)) { stag_idx = c4iw_get_resource(&rdev->resource.tpt_table); - if (!stag_idx) + if (!stag_idx) { + mutex_lock(&rdev->stats.lock); + rdev->stats.stag.fail++; + mutex_unlock(&rdev->stats.lock); return -ENOMEM; + } mutex_lock(&rdev->stats.lock); rdev->stats.stag.cur += 32; if (rdev->stats.stag.cur > rdev->stats.stag.max) diff --git a/drivers/infiniband/hw/cxgb4/resource.c b/drivers/infiniband/hw/cxgb4/resource.c index 94b5fd9b937..67df71a7012 100644 --- a/drivers/infiniband/hw/cxgb4/resource.c +++ b/drivers/infiniband/hw/cxgb4/resource.c @@ -179,8 +179,12 @@ u32 c4iw_get_qpid(struct c4iw_rdev *rdev, struct c4iw_dev_ucontext *uctx) kfree(entry); } else { qid = c4iw_get_resource(&rdev->resource.qid_table); - if (!qid) + if (!qid) { + mutex_lock(&rdev->stats.lock); + rdev->stats.qid.fail++; + mutex_unlock(&rdev->stats.lock); goto out; + } mutex_lock(&rdev->stats.lock); rdev->stats.qid.cur += rdev->qpmask + 1; mutex_unlock(&rdev->stats.lock); -- cgit v1.2.3-70-g09d2 From 97df1c6736f660b58b408a60d0f7f65a64fb9d56 Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Wed, 9 Apr 2014 09:38:28 -0500 Subject: RDMA/cxgb4: Use uninitialized_var() Signed-off-by: Steve Wise Signed-off-by: Roland Dreier --- drivers/infiniband/hw/cxgb4/cq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/cxgb4/cq.c b/drivers/infiniband/hw/cxgb4/cq.c index e17b155b375..cfaa56ada18 100644 --- a/drivers/infiniband/hw/cxgb4/cq.c +++ b/drivers/infiniband/hw/cxgb4/cq.c @@ -672,7 +672,7 @@ skip_cqe: static int c4iw_poll_cq_one(struct c4iw_cq *chp, struct ib_wc *wc) { struct c4iw_qp *qhp = NULL; - struct t4_cqe cqe = {0, 0}, *rd_cqe; + struct t4_cqe uninitialized_var(cqe), *rd_cqe; struct t4_wq *wq; u32 credit = 0; u8 cqe_flushed; -- cgit v1.2.3-70-g09d2 From 1d1ca9b4fdde07325d263f7a75379527b1281f52 Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Wed, 9 Apr 2014 09:40:37 -0500 Subject: RDMA/cxgb4: Fix over-dereference when terminating Need to get the endpoint reference before calling rdma_fini(), which might fail causing us to not get the reference. Signed-off-by: Steve Wise Signed-off-by: Roland Dreier --- drivers/infiniband/hw/cxgb4/qp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/cxgb4/qp.c b/drivers/infiniband/hw/cxgb4/qp.c index 5a7d368aa47..7b5114cb486 100644 --- a/drivers/infiniband/hw/cxgb4/qp.c +++ b/drivers/infiniband/hw/cxgb4/qp.c @@ -1389,6 +1389,7 @@ int c4iw_modify_qp(struct c4iw_dev *rhp, struct c4iw_qp *qhp, qhp->attr.ecode = attrs->ecode; ep = qhp->ep; disconnect = 1; + c4iw_get_ep(&qhp->ep->com); if (!internal) terminate = 1; else { @@ -1396,7 +1397,6 @@ int c4iw_modify_qp(struct c4iw_dev *rhp, struct c4iw_qp *qhp, if (ret) goto err; } - c4iw_get_ep(&qhp->ep->com); break; case C4IW_QP_STATE_ERROR: t4_set_wq_in_error(&qhp->wq); -- cgit v1.2.3-70-g09d2 From 0229cdafb6f67064a217591d48b0f6abf14e8385 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 19 Mar 2014 18:36:39 +0100 Subject: iwlwifi: mvm: delay enabling smart FIFO until after beacon RX If we have no beacon data before association, delay smart FIFO enablement until after we have this data. Not doing so can cause association failures in extremely silent environments (usually only a shielded box/room) as beacon RX is not sent to the host immediately, and then the association time event ends without the host receiving any beacon even though it was on the air - it's just stuck on the FIFO. Cc: [3.14] Fixes: 1f3b0ff8ecce ("iwlwifi: mvm: Add Smart FIFO support") Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 1 + drivers/net/wireless/iwlwifi/mvm/sf.c | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 4dd9ff43b8b..f0cebf12c7b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -1332,6 +1332,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, */ iwl_mvm_remove_time_event(mvm, mvmvif, &mvmvif->time_event_data); + iwl_mvm_sf_update(mvm, vif, false); WARN_ON(iwl_mvm_enable_beacon_filter(mvm, vif, CMD_SYNC)); } else if (changes & (BSS_CHANGED_PS | BSS_CHANGED_P2P_PS | BSS_CHANGED_QOS)) { diff --git a/drivers/net/wireless/iwlwifi/mvm/sf.c b/drivers/net/wireless/iwlwifi/mvm/sf.c index 8401627c003..88809b2d165 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sf.c +++ b/drivers/net/wireless/iwlwifi/mvm/sf.c @@ -274,7 +274,8 @@ int iwl_mvm_sf_update(struct iwl_mvm *mvm, struct ieee80211_vif *changed_vif, return -EINVAL; if (changed_vif->type != NL80211_IFTYPE_STATION) { new_state = SF_UNINIT; - } else if (changed_vif->bss_conf.assoc) { + } else if (changed_vif->bss_conf.assoc && + changed_vif->bss_conf.dtim_period) { mvmvif = iwl_mvm_vif_from_mac80211(changed_vif); sta_id = mvmvif->ap_sta_id; new_state = SF_FULL_ON; -- cgit v1.2.3-70-g09d2 From d9088f60425e0acd8a8f05fdfcfdd288d3258641 Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Tue, 25 Mar 2014 10:25:44 +0200 Subject: iwlwifi: mvm: rs: fix mimo delimiter in LQ cmd mimo_delim was always set to 0 instead of pointing to the first SISO entry after MIMO rates. This can cause keep transmitting in MIMO even when we shouldn't. For example when the peer is requesting static SMPS. Cc: [3.14] Signed-off-by: Eyal Shapira Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/rs.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 568abd61b14..dd13629d018 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -2547,6 +2547,7 @@ static void rs_build_rates_table(struct iwl_mvm *mvm, if (is_siso(&rate)) { num_rates = RS_SECONDARY_SISO_NUM_RATES; num_retries = RS_SECONDARY_SISO_RETRIES; + lq_cmd->mimo_delim = index; } else if (is_legacy(&rate)) { num_rates = RS_SECONDARY_LEGACY_NUM_RATES; num_retries = RS_LEGACY_RETRIES_PER_RATE; -- cgit v1.2.3-70-g09d2 From fff47eb05a287e1a47836126573a750ff9ed22dd Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 2 Apr 2014 15:29:07 +0300 Subject: iwlwifi: mvm: BT Coex - send the new LUT upon antenna coupling change I forgot to send the new Look Up Table to the firmware and I also forgot to free the command which is kzalloc'ed. This code is relevant for 7265 device only. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/coex.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/mvm/coex.c b/drivers/net/wireless/iwlwifi/mvm/coex.c index 685f7e8e694..f9c7b302e3d 100644 --- a/drivers/net/wireless/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/iwlwifi/mvm/coex.c @@ -1262,6 +1262,7 @@ int iwl_mvm_rx_ant_coupling_notif(struct iwl_mvm *mvm, struct iwl_rx_packet *pkt = rxb_addr(rxb); u32 ant_isolation = le32_to_cpup((void *)pkt->data); u8 __maybe_unused lower_bound, upper_bound; + int ret; u8 lut; struct iwl_bt_coex_cmd *bt_cmd; @@ -1318,5 +1319,8 @@ int iwl_mvm_rx_ant_coupling_notif(struct iwl_mvm *mvm, memcpy(bt_cmd->bt4_corun_lut40, antenna_coupling_ranges[lut].lut20, sizeof(bt_cmd->bt4_corun_lut40)); - return 0; + ret = iwl_mvm_send_cmd(mvm, &cmd); + + kfree(bt_cmd); + return ret; } -- cgit v1.2.3-70-g09d2 From 80f2679e589503bd6cbaaa1f9c1cd9dd7dfae032 Mon Sep 17 00:00:00 2001 From: Oren Givon Date: Wed, 2 Apr 2014 14:04:20 +0300 Subject: iwlwifi: add new 7265 HW IDs Add 2 new HW IDs for the 7265 series. Cc: [3.13+] Signed-off-by: Oren Givon Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/pcie/drv.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c index edb015c9904..3d1d57f9f5b 100644 --- a/drivers/net/wireless/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/iwlwifi/pcie/drv.c @@ -373,12 +373,14 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = { {IWL_PCI_DEVICE(0x095A, 0x500A, iwl7265_2n_cfg)}, {IWL_PCI_DEVICE(0x095B, 0x5200, iwl7265_2n_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x5002, iwl7265_n_cfg)}, + {IWL_PCI_DEVICE(0x095A, 0x5102, iwl7265_n_cfg)}, {IWL_PCI_DEVICE(0x095B, 0x5202, iwl7265_n_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x9010, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x9012, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x9110, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x9112, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x9210, iwl7265_2ac_cfg)}, + {IWL_PCI_DEVICE(0x095A, 0x9200, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x9510, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x9310, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x9410, iwl7265_2ac_cfg)}, -- cgit v1.2.3-70-g09d2 From 431031851ea72a25abb9ad4df56a0f3b997e3026 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Wed, 9 Apr 2014 19:27:25 +0300 Subject: iwlwifi: 7000: bump API to 9 This will allow to load the new firmware. Cc: [3.14] Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-7000.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-7000.c b/drivers/net/wireless/iwlwifi/iwl-7000.c index 003a546571d..8425130273f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-7000.c +++ b/drivers/net/wireless/iwlwifi/iwl-7000.c @@ -67,8 +67,8 @@ #include "iwl-agn-hw.h" /* Highest firmware API version supported */ -#define IWL7260_UCODE_API_MAX 8 -#define IWL3160_UCODE_API_MAX 8 +#define IWL7260_UCODE_API_MAX 9 +#define IWL3160_UCODE_API_MAX 9 /* Oldest version we won't warn about */ #define IWL7260_UCODE_API_OK 8 -- cgit v1.2.3-70-g09d2 From adeb25905c644350baf1f446bcd856517e58060e Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Wed, 9 Apr 2014 10:20:39 +0800 Subject: iommu/vt-d: fix memory leakage caused by commit ea8ea46 Commit ea8ea46 "iommu/vt-d: Clean up and fix page table clear/free behaviour" introduces possible leakage of DMA page tables due to: for (pte = page_address(pg); !first_pte_in_page(pte); pte++) { if (dma_pte_present(pte) && !dma_pte_superpage(pte)) freelist = dma_pte_list_pagetables(domain, level - 1, pte, freelist); } For the first pte in a page, first_pte_in_page(pte) will always be true, thus dma_pte_list_pagetables() will never be called and leak DMA page tables if level is bigger than 1. Signed-off-by: Jiang Liu Signed-off-by: David Woodhouse --- drivers/iommu/intel-iommu.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index 69fa7da5e48..13dc2318e17 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -1009,11 +1009,13 @@ static struct page *dma_pte_list_pagetables(struct dmar_domain *domain, if (level == 1) return freelist; - for (pte = page_address(pg); !first_pte_in_page(pte); pte++) { + pte = page_address(pg); + do { if (dma_pte_present(pte) && !dma_pte_superpage(pte)) freelist = dma_pte_list_pagetables(domain, level - 1, pte, freelist); - } + pte++; + } while (!first_pte_in_page(pte)); return freelist; } -- cgit v1.2.3-70-g09d2 From 08a732f4e4a842f0101e5ea03d79e9d613ffadbe Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 24 Mar 2014 22:17:15 +0200 Subject: iwlwifi: add MODULE_FIRMWARE for 7265 It was missing. Cc: [3.13+] Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-7000.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/iwl-7000.c b/drivers/net/wireless/iwlwifi/iwl-7000.c index 8425130273f..4c2d4ef28b2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-7000.c +++ b/drivers/net/wireless/iwlwifi/iwl-7000.c @@ -244,3 +244,4 @@ const struct iwl_cfg iwl7265_n_cfg = { MODULE_FIRMWARE(IWL7260_MODULE_FIRMWARE(IWL7260_UCODE_API_OK)); MODULE_FIRMWARE(IWL3160_MODULE_FIRMWARE(IWL3160_UCODE_API_OK)); +MODULE_FIRMWARE(IWL7265_MODULE_FIRMWARE(IWL7260_UCODE_API_OK)); -- cgit v1.2.3-70-g09d2 From 198266a3c110e8a68895a24e937003f5da0c5f60 Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Mon, 31 Mar 2014 22:37:39 +0300 Subject: iwlwifi: mvm: rs: use correct max expected throughput figures The selection of the max expected throughput for a column didn't take into account the maximal allowed rate for the current peer. This can cause unnecessary switches during the search cycle to columns which have no chance of beating the current throughput. Signed-off-by: Eyal Shapira Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/rs.c | 55 ++++++++++++++++++++++++++--------- drivers/net/wireless/iwlwifi/mvm/rs.h | 12 ++++++-- 2 files changed, 51 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index dd13629d018..cd32ad54384 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -1186,9 +1186,26 @@ static void rs_set_stay_in_table(struct iwl_mvm *mvm, u8 is_legacy, lq_sta->visited_columns = 0; } +static int rs_get_max_allowed_rate(struct iwl_lq_sta *lq_sta, + const struct rs_tx_column *column) +{ + switch (column->mode) { + case RS_LEGACY: + return lq_sta->max_legacy_rate_idx; + case RS_SISO: + return lq_sta->max_siso_rate_idx; + case RS_MIMO2: + return lq_sta->max_mimo2_rate_idx; + default: + WARN_ON_ONCE(1); + } + + return lq_sta->max_legacy_rate_idx; +} + static const u16 *rs_get_expected_tpt_table(struct iwl_lq_sta *lq_sta, - const struct rs_tx_column *column, - u32 bw) + const struct rs_tx_column *column, + u32 bw) { /* Used to choose among HT tables */ const u16 (*ht_tbl_pointer)[IWL_RATE_COUNT]; @@ -1485,14 +1502,14 @@ static enum rs_column rs_get_next_column(struct iwl_mvm *mvm, struct ieee80211_sta *sta, struct iwl_scale_tbl_info *tbl) { - int i, j, n; + int i, j, max_rate; enum rs_column next_col_id; const struct rs_tx_column *curr_col = &rs_tx_columns[tbl->column]; const struct rs_tx_column *next_col; allow_column_func_t allow_func; u8 valid_ants = mvm->fw->valid_tx_ant; const u16 *expected_tpt_tbl; - s32 tpt, max_expected_tpt; + u16 tpt, max_expected_tpt; for (i = 0; i < MAX_NEXT_COLUMNS; i++) { next_col_id = curr_col->next_columns[i]; @@ -1535,11 +1552,11 @@ static enum rs_column rs_get_next_column(struct iwl_mvm *mvm, if (WARN_ON_ONCE(!expected_tpt_tbl)) continue; - max_expected_tpt = 0; - for (n = 0; n < IWL_RATE_COUNT; n++) - if (expected_tpt_tbl[n] > max_expected_tpt) - max_expected_tpt = expected_tpt_tbl[n]; + max_rate = rs_get_max_allowed_rate(lq_sta, next_col); + if (WARN_ON_ONCE(max_rate == IWL_RATE_INVALID)) + continue; + max_expected_tpt = expected_tpt_tbl[max_rate]; if (tpt >= max_expected_tpt) { IWL_DEBUG_RATE(mvm, "Skip column %d: can't beat current TPT. Max expected %d current %d\n", @@ -1547,14 +1564,15 @@ static enum rs_column rs_get_next_column(struct iwl_mvm *mvm, continue; } + IWL_DEBUG_RATE(mvm, + "Found potential column %d. Max expected %d current %d\n", + next_col_id, max_expected_tpt, tpt); break; } if (i == MAX_NEXT_COLUMNS) return RS_COLUMN_INVALID; - IWL_DEBUG_RATE(mvm, "Found potential column %d\n", next_col_id); - return next_col_id; } @@ -2388,11 +2406,22 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, lq_sta->is_vht = true; } - IWL_DEBUG_RATE(mvm, - "SISO-RATE=%X MIMO2-RATE=%X VHT=%d\n", + lq_sta->max_legacy_rate_idx = find_last_bit(&lq_sta->active_legacy_rate, + BITS_PER_LONG); + lq_sta->max_siso_rate_idx = find_last_bit(&lq_sta->active_siso_rate, + BITS_PER_LONG); + lq_sta->max_mimo2_rate_idx = find_last_bit(&lq_sta->active_mimo2_rate, + BITS_PER_LONG); + + IWL_DEBUG_RATE(mvm, "RATE MASK: LEGACY=%lX SISO=%lX MIMO2=%lX VHT=%d\n", + lq_sta->active_legacy_rate, lq_sta->active_siso_rate, lq_sta->active_mimo2_rate, lq_sta->is_vht); + IWL_DEBUG_RATE(mvm, "MAX RATE: LEGACY=%d SISO=%d MIMO2=%d\n", + lq_sta->max_legacy_rate_idx, + lq_sta->max_siso_rate_idx, + lq_sta->max_mimo2_rate_idx); /* These values will be overridden later */ lq_sta->lq.single_stream_ant_msk = @@ -2750,7 +2779,7 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file, return -ENOMEM; desc += sprintf(buff+desc, "sta_id %d\n", lq_sta->lq.sta_id); - desc += sprintf(buff+desc, "failed=%d success=%d rate=0%X\n", + desc += sprintf(buff+desc, "failed=%d success=%d rate=0%lX\n", lq_sta->total_failed, lq_sta->total_success, lq_sta->active_legacy_rate); desc += sprintf(buff+desc, "fixed rate 0x%X\n", diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.h b/drivers/net/wireless/iwlwifi/mvm/rs.h index 3332b396011..9892d92d590 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.h +++ b/drivers/net/wireless/iwlwifi/mvm/rs.h @@ -314,9 +314,15 @@ struct iwl_lq_sta { enum ieee80211_band band; /* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */ - u16 active_legacy_rate; - u16 active_siso_rate; - u16 active_mimo2_rate; + unsigned long active_legacy_rate; + unsigned long active_siso_rate; + unsigned long active_mimo2_rate; + + /* Highest rate per Tx mode */ + u8 max_legacy_rate_idx; + u8 max_siso_rate_idx; + u8 max_mimo2_rate_idx; + s8 max_rate_idx; /* Max rate set by user */ u8 missed_rate_counter; -- cgit v1.2.3-70-g09d2 From e53839eb9882c99d3781eab0fe1b2d4369a6a2cc Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Sun, 6 Apr 2014 02:42:18 +0300 Subject: iwlwifi: mvm: rs: fix and cleanup rs_get_rate_action Change the down/upscale decision logic a bit to be based on different success ratio thresholds. This fixes the implementation compared to the rate scale algorithm which was planned to yield optimal results. Also fix a case where a lower rate wasn't explored despite being a potential for better throughput. While at it rewrite rs_get_rate_action to be more clear and clean. Cc: [3.14] Signed-off-by: Eyal Shapira Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/rs.c | 127 ++++++++++++++++------------------ drivers/net/wireless/iwlwifi/mvm/rs.h | 1 + 2 files changed, 60 insertions(+), 68 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index cd32ad54384..97b8fac214a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -1658,85 +1658,76 @@ static enum rs_action rs_get_rate_action(struct iwl_mvm *mvm, { enum rs_action action = RS_ACTION_STAY; - /* Too many failures, decrease rate */ if ((sr <= RS_SR_FORCE_DECREASE) || (current_tpt == 0)) { IWL_DEBUG_RATE(mvm, - "decrease rate because of low SR\n"); - action = RS_ACTION_DOWNSCALE; - /* No throughput measured yet for adjacent rates; try increase. */ - } else if ((low_tpt == IWL_INVALID_VALUE) && - (high_tpt == IWL_INVALID_VALUE)) { - if (high != IWL_RATE_INVALID && sr >= IWL_RATE_INCREASE_TH) { - IWL_DEBUG_RATE(mvm, - "Good SR and no high rate measurement. " - "Increase rate\n"); - action = RS_ACTION_UPSCALE; - } else if (low != IWL_RATE_INVALID) { - IWL_DEBUG_RATE(mvm, - "Remain in current rate\n"); - action = RS_ACTION_STAY; - } + "Decrease rate because of low SR\n"); + return RS_ACTION_DOWNSCALE; } - /* Both adjacent throughputs are measured, but neither one has better - * throughput; we're using the best rate, don't change it! - */ - else if ((low_tpt != IWL_INVALID_VALUE) && - (high_tpt != IWL_INVALID_VALUE) && - (low_tpt < current_tpt) && - (high_tpt < current_tpt)) { + if ((low_tpt == IWL_INVALID_VALUE) && + (high_tpt == IWL_INVALID_VALUE) && + (high != IWL_RATE_INVALID)) { IWL_DEBUG_RATE(mvm, - "Both high and low are worse. " - "Maintain rate\n"); - action = RS_ACTION_STAY; + "No data about high/low rates. Increase rate\n"); + return RS_ACTION_UPSCALE; } - /* At least one adjacent rate's throughput is measured, - * and may have better performance. - */ - else { - /* Higher adjacent rate's throughput is measured */ - if (high_tpt != IWL_INVALID_VALUE) { - /* Higher rate has better throughput */ - if (high_tpt > current_tpt && - sr >= IWL_RATE_INCREASE_TH) { - IWL_DEBUG_RATE(mvm, - "Higher rate is better and good " - "SR. Increate rate\n"); - action = RS_ACTION_UPSCALE; - } else { - IWL_DEBUG_RATE(mvm, - "Higher rate isn't better OR " - "no good SR. Maintain rate\n"); - action = RS_ACTION_STAY; - } + if ((high_tpt == IWL_INVALID_VALUE) && + (high != IWL_RATE_INVALID) && + (low_tpt != IWL_INVALID_VALUE) && + (low_tpt < current_tpt)) { + IWL_DEBUG_RATE(mvm, + "No data about high rate and low rate is worse. Increase rate\n"); + return RS_ACTION_UPSCALE; + } - /* Lower adjacent rate's throughput is measured */ - } else if (low_tpt != IWL_INVALID_VALUE) { - /* Lower rate has better throughput */ - if (low_tpt > current_tpt) { - IWL_DEBUG_RATE(mvm, - "Lower rate is better. " - "Decrease rate\n"); - action = RS_ACTION_DOWNSCALE; - } else if (sr >= IWL_RATE_INCREASE_TH) { - IWL_DEBUG_RATE(mvm, - "Lower rate isn't better and " - "good SR. Increase rate\n"); - action = RS_ACTION_UPSCALE; - } - } + if ((high_tpt != IWL_INVALID_VALUE) && + (high_tpt > current_tpt)) { + IWL_DEBUG_RATE(mvm, + "Higher rate is better. Increate rate\n"); + return RS_ACTION_UPSCALE; } - /* Sanity check; asked for decrease, but success rate or throughput - * has been good at old rate. Don't change it. - */ - if ((action == RS_ACTION_DOWNSCALE) && (low != IWL_RATE_INVALID) && - ((sr > IWL_RATE_HIGH_TH) || - (current_tpt > (100 * tbl->expected_tpt[low])))) { + if ((low_tpt != IWL_INVALID_VALUE) && + (high_tpt != IWL_INVALID_VALUE) && + (low_tpt < current_tpt) && + (high_tpt < current_tpt)) { IWL_DEBUG_RATE(mvm, - "Sanity check failed. Maintain rate\n"); - action = RS_ACTION_STAY; + "Both high and low are worse. Maintain rate\n"); + return RS_ACTION_STAY; + } + + if ((low_tpt != IWL_INVALID_VALUE) && + (low_tpt > current_tpt)) { + IWL_DEBUG_RATE(mvm, + "Lower rate is better\n"); + action = RS_ACTION_DOWNSCALE; + goto out; + } + + if ((low_tpt == IWL_INVALID_VALUE) && + (low != IWL_RATE_INVALID)) { + IWL_DEBUG_RATE(mvm, + "No data about lower rate\n"); + action = RS_ACTION_DOWNSCALE; + goto out; + } + + IWL_DEBUG_RATE(mvm, "Maintain rate\n"); + +out: + if ((action == RS_ACTION_DOWNSCALE) && (low != IWL_RATE_INVALID)) { + if (sr >= RS_SR_NO_DECREASE) { + IWL_DEBUG_RATE(mvm, + "SR is above NO DECREASE. Avoid downscale\n"); + action = RS_ACTION_STAY; + } else if (current_tpt > (100 * tbl->expected_tpt[low])) { + IWL_DEBUG_RATE(mvm, + "Current TPT is higher than max expected in low rate. Avoid downscale\n"); + action = RS_ACTION_STAY; + } else { + IWL_DEBUG_RATE(mvm, "Decrease rate\n"); + } } return action; diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.h b/drivers/net/wireless/iwlwifi/mvm/rs.h index 9892d92d590..fbb476aadb2 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.h +++ b/drivers/net/wireless/iwlwifi/mvm/rs.h @@ -156,6 +156,7 @@ enum { #define IWL_RATE_HIGH_TH 10880 /* 85% */ #define IWL_RATE_INCREASE_TH 6400 /* 50% */ #define RS_SR_FORCE_DECREASE 1920 /* 15% */ +#define RS_SR_NO_DECREASE 10880 /* 85% */ #define LINK_QUAL_AGG_TIME_LIMIT_DEF (4000) /* 4 milliseconds */ #define LINK_QUAL_AGG_TIME_LIMIT_MAX (8000) -- cgit v1.2.3-70-g09d2 From 87d5e4155c0088e6766b4f0193b63fa0eab71220 Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Sun, 6 Apr 2014 18:13:22 +0300 Subject: iwlwifi: mvm: rs: reinit rs if no tx for a long time After being idle for a long time (>5sec) the rs statistics will be stale so we prefer to reset rs and start from legacy rates again. This gives better results when the attenuation increased signficantly (e.g. we got further from the AP) and after a while we start Tx Note that the first Tx after the idle period will still go out in the old modulation and rate but this seemed a simpler approach compared to adding a timer or modifying mac80211 for this. The negative impact is negligble as we'll recover quickly. Cc: [3.14] Signed-off-by: Eyal Shapira Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/rs.c | 22 +++++++++++++++++++++- drivers/net/wireless/iwlwifi/mvm/rs.h | 1 + 2 files changed, 22 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 97b8fac214a..0d03dcd2fc3 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -59,7 +59,7 @@ /* max allowed rate miss before sync LQ cmd */ #define IWL_MISSED_RATE_MAX 15 #define RS_STAY_IN_COLUMN_TIMEOUT (5*HZ) - +#define RS_IDLE_TIMEOUT (5*HZ) static u8 rs_ht_to_legacy[] = { [IWL_RATE_MCS_0_INDEX] = IWL_RATE_6M_INDEX, @@ -992,6 +992,13 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband, return; } +#ifdef CPTCFG_MAC80211_DEBUGFS + /* Disable last tx check if we are debugging with fixed rate */ + if (lq_sta->dbg_fixed_rate) { + IWL_DEBUG_RATE(mvm, "Fixed rate. avoid rate scaling\n"); + return; + } +#endif if (!ieee80211_is_data(hdr->frame_control) || info->flags & IEEE80211_TX_CTL_NO_ACK) return; @@ -1034,6 +1041,18 @@ static void rs_tx_status(void *mvm_r, struct ieee80211_supported_band *sband, mac_index++; } + if (time_after(jiffies, + (unsigned long)(lq_sta->last_tx + RS_IDLE_TIMEOUT))) { + int tid; + IWL_DEBUG_RATE(mvm, "Tx idle for too long. reinit rs\n"); + for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++) + ieee80211_stop_tx_ba_session(sta, tid); + + iwl_mvm_rs_rate_init(mvm, sta, sband->band, false); + return; + } + lq_sta->last_tx = jiffies; + /* Here we actually compare this rate to the latest LQ command */ if ((mac_index < 0) || (rate.sgi != !!(mac_flags & IEEE80211_TX_RC_SHORT_GI)) || @@ -2354,6 +2373,7 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, rs_rate_scale_clear_tbl_windows(&lq_sta->lq_info[j]); lq_sta->flush_timer = 0; + lq_sta->last_tx = jiffies; IWL_DEBUG_RATE(mvm, "LQ: *** rate scale station global init for station %d ***\n", diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.h b/drivers/net/wireless/iwlwifi/mvm/rs.h index fbb476aadb2..0acfac96a56 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.h +++ b/drivers/net/wireless/iwlwifi/mvm/rs.h @@ -311,6 +311,7 @@ struct iwl_lq_sta { u32 visited_columns; /* Bitmask marking which Tx columns were * explored during a search cycle */ + u64 last_tx; bool is_vht; enum ieee80211_band band; -- cgit v1.2.3-70-g09d2 From fd7dbee51b3d98402edb11fec0c93d96476e0ae1 Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Sun, 6 Apr 2014 04:39:23 +0300 Subject: iwlwifi: mvm: rs: fallback to legacy Tx columns Allow switching back to legacy Tx columns so we'll stop doing HT/VHT in case we're far from the AP. Stop active aggregation when making a deciding to stay in a legacy column. Despite having low legacy rates in the LQ table lower entries it doesn't help much in case we're doing aggregations as the aggregation was being transmitted in the initial rate of the table. This should help traffic stalls when far from the AP. Cc: [3.14] Signed-off-by: Eyal Shapira Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/rs.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 0d03dcd2fc3..b007db9cf3a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -142,7 +142,7 @@ enum rs_column_mode { RS_MIMO2, }; -#define MAX_NEXT_COLUMNS 5 +#define MAX_NEXT_COLUMNS 7 #define MAX_COLUMN_CHECKS 3 typedef bool (*allow_column_func_t) (struct iwl_mvm *mvm, @@ -214,6 +214,8 @@ static const struct rs_tx_column rs_tx_columns[] = { RS_COLUMN_SISO_ANT_B, RS_COLUMN_MIMO2, RS_COLUMN_MIMO2_SGI, + RS_COLUMN_INVALID, + RS_COLUMN_INVALID, }, }, [RS_COLUMN_LEGACY_ANT_B] = { @@ -225,6 +227,8 @@ static const struct rs_tx_column rs_tx_columns[] = { RS_COLUMN_SISO_ANT_B, RS_COLUMN_MIMO2, RS_COLUMN_MIMO2_SGI, + RS_COLUMN_INVALID, + RS_COLUMN_INVALID, }, }, [RS_COLUMN_SISO_ANT_A] = { @@ -236,6 +240,8 @@ static const struct rs_tx_column rs_tx_columns[] = { RS_COLUMN_SISO_ANT_A_SGI, RS_COLUMN_SISO_ANT_B_SGI, RS_COLUMN_MIMO2_SGI, + RS_COLUMN_LEGACY_ANT_A, + RS_COLUMN_LEGACY_ANT_B, }, .checks = { rs_siso_allow, @@ -250,6 +256,8 @@ static const struct rs_tx_column rs_tx_columns[] = { RS_COLUMN_SISO_ANT_B_SGI, RS_COLUMN_SISO_ANT_A_SGI, RS_COLUMN_MIMO2_SGI, + RS_COLUMN_LEGACY_ANT_A, + RS_COLUMN_LEGACY_ANT_B, }, .checks = { rs_siso_allow, @@ -265,6 +273,8 @@ static const struct rs_tx_column rs_tx_columns[] = { RS_COLUMN_SISO_ANT_A, RS_COLUMN_SISO_ANT_B, RS_COLUMN_MIMO2, + RS_COLUMN_LEGACY_ANT_A, + RS_COLUMN_LEGACY_ANT_B, }, .checks = { rs_siso_allow, @@ -281,6 +291,8 @@ static const struct rs_tx_column rs_tx_columns[] = { RS_COLUMN_SISO_ANT_B, RS_COLUMN_SISO_ANT_A, RS_COLUMN_MIMO2, + RS_COLUMN_LEGACY_ANT_A, + RS_COLUMN_LEGACY_ANT_B, }, .checks = { rs_siso_allow, @@ -296,6 +308,8 @@ static const struct rs_tx_column rs_tx_columns[] = { RS_COLUMN_SISO_ANT_A_SGI, RS_COLUMN_SISO_ANT_B_SGI, RS_COLUMN_MIMO2_SGI, + RS_COLUMN_LEGACY_ANT_A, + RS_COLUMN_LEGACY_ANT_B, }, .checks = { rs_mimo_allow, @@ -311,6 +325,8 @@ static const struct rs_tx_column rs_tx_columns[] = { RS_COLUMN_SISO_ANT_A, RS_COLUMN_SISO_ANT_B, RS_COLUMN_MIMO2, + RS_COLUMN_LEGACY_ANT_A, + RS_COLUMN_LEGACY_ANT_B, }, .checks = { rs_mimo_allow, @@ -2070,8 +2086,18 @@ lq_update: * stay with best antenna legacy modulation for a while * before next round of mode comparisons. */ tbl1 = &(lq_sta->lq_info[lq_sta->active_tbl]); - if (is_legacy(&tbl1->rate) && !sta->ht_cap.ht_supported) { + if (is_legacy(&tbl1->rate)) { IWL_DEBUG_RATE(mvm, "LQ: STAY in legacy table\n"); + + if (tid != IWL_MAX_TID_COUNT) { + tid_data = &sta_priv->tid_data[tid]; + if (tid_data->state != IWL_AGG_OFF) { + IWL_DEBUG_RATE(mvm, + "Stop aggregation on tid %d\n", + tid); + ieee80211_stop_tx_ba_session(sta, tid); + } + } rs_set_stay_in_table(mvm, 1, lq_sta); } else { /* If we're in an HT mode, and all 3 mode switch actions -- cgit v1.2.3-70-g09d2 From d8fff919ecd7820084675c2814913445e95640ac Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Sun, 6 Apr 2014 05:27:36 +0300 Subject: iwlwifi: mvm: avoid searching unnecessary columns Don't search columns which are unlikely to succeed as previous columns searched with less aggressive modulation failed. Cc: [3.14] Signed-off-by: Eyal Shapira Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/rs.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index b007db9cf3a..5cab26ecc17 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -212,8 +212,8 @@ static const struct rs_tx_column rs_tx_columns[] = { RS_COLUMN_LEGACY_ANT_B, RS_COLUMN_SISO_ANT_A, RS_COLUMN_SISO_ANT_B, - RS_COLUMN_MIMO2, - RS_COLUMN_MIMO2_SGI, + RS_COLUMN_INVALID, + RS_COLUMN_INVALID, RS_COLUMN_INVALID, RS_COLUMN_INVALID, }, @@ -225,8 +225,8 @@ static const struct rs_tx_column rs_tx_columns[] = { RS_COLUMN_LEGACY_ANT_A, RS_COLUMN_SISO_ANT_A, RS_COLUMN_SISO_ANT_B, - RS_COLUMN_MIMO2, - RS_COLUMN_MIMO2_SGI, + RS_COLUMN_INVALID, + RS_COLUMN_INVALID, RS_COLUMN_INVALID, RS_COLUMN_INVALID, }, @@ -239,9 +239,9 @@ static const struct rs_tx_column rs_tx_columns[] = { RS_COLUMN_MIMO2, RS_COLUMN_SISO_ANT_A_SGI, RS_COLUMN_SISO_ANT_B_SGI, - RS_COLUMN_MIMO2_SGI, RS_COLUMN_LEGACY_ANT_A, RS_COLUMN_LEGACY_ANT_B, + RS_COLUMN_INVALID, }, .checks = { rs_siso_allow, @@ -255,9 +255,9 @@ static const struct rs_tx_column rs_tx_columns[] = { RS_COLUMN_MIMO2, RS_COLUMN_SISO_ANT_B_SGI, RS_COLUMN_SISO_ANT_A_SGI, - RS_COLUMN_MIMO2_SGI, RS_COLUMN_LEGACY_ANT_A, RS_COLUMN_LEGACY_ANT_B, + RS_COLUMN_INVALID, }, .checks = { rs_siso_allow, -- cgit v1.2.3-70-g09d2 From b804eeb6649d75caeccbeae9f5623fc7b8bdfdfa Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Sun, 6 Apr 2014 04:27:06 +0300 Subject: iwlwifi: mvm: rs: clear per rate stats when aggregation changes The per rate stats should be cleared when aggregation state changes to avoid making rate scale decisions based on throughput figures which were collected prior to the aggregation state change and are now stale. While at it make sure any clearing of the per rate stats will get logged. Cc: [3.14] Signed-off-by: Eyal Shapira Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/rs.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index 5cab26ecc17..9f52c5b3f0e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -519,10 +519,12 @@ static void rs_rate_scale_clear_window(struct iwl_rate_scale_data *window) window->average_tpt = IWL_INVALID_VALUE; } -static void rs_rate_scale_clear_tbl_windows(struct iwl_scale_tbl_info *tbl) +static void rs_rate_scale_clear_tbl_windows(struct iwl_mvm *mvm, + struct iwl_scale_tbl_info *tbl) { int i; + IWL_DEBUG_RATE(mvm, "Clearing up window stats\n"); for (i = 0; i < IWL_RATE_COUNT; i++) rs_rate_scale_clear_window(&tbl->win[i]); } @@ -1490,7 +1492,7 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search) IWL_DEBUG_RATE(mvm, "LQ: stay in table clear win\n"); - rs_rate_scale_clear_tbl_windows(tbl); + rs_rate_scale_clear_tbl_windows(mvm, tbl); } } @@ -1498,8 +1500,7 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search) * bitmaps and stats in active table (this will become the new * "search" table). */ if (lq_sta->rs_state == RS_STATE_SEARCH_CYCLE_STARTED) { - IWL_DEBUG_RATE(mvm, "Clearing up window stats\n"); - rs_rate_scale_clear_tbl_windows(tbl); + rs_rate_scale_clear_tbl_windows(mvm, tbl); } } } @@ -1836,6 +1837,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm, "Aggregation changed: prev %d current %d. Update expected TPT table\n", prev_agg, lq_sta->is_agg); rs_set_expected_tpt_table(lq_sta, tbl); + rs_rate_scale_clear_tbl_windows(mvm, tbl); } /* current tx rate */ @@ -2065,7 +2067,7 @@ lq_update: if (lq_sta->search_better_tbl) { /* Access the "search" table, clear its history. */ tbl = &(lq_sta->lq_info[(1 - lq_sta->active_tbl)]); - rs_rate_scale_clear_tbl_windows(tbl); + rs_rate_scale_clear_tbl_windows(mvm, tbl); /* Use new "search" start rate */ index = tbl->rate.index; @@ -2396,7 +2398,7 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, lq_sta->lq.sta_id = sta_priv->sta_id; for (j = 0; j < LQ_SIZE; j++) - rs_rate_scale_clear_tbl_windows(&lq_sta->lq_info[j]); + rs_rate_scale_clear_tbl_windows(mvm, &lq_sta->lq_info[j]); lq_sta->flush_timer = 0; lq_sta->last_tx = jiffies; -- cgit v1.2.3-70-g09d2 From a6bc92803e7f765e02c923cf37c8e280e729642a Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Sun, 13 Apr 2014 15:51:41 +0300 Subject: iwlwifi: mvm: BT Coex - fix Look Up Table A few entries were wrong and this caused throughput issues. Cc: [3.13+] Fixes: dac94da8dba3 ("iwlwifi: mvm: new BT Coex API") Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/coex.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/iwlwifi/mvm/coex.c b/drivers/net/wireless/iwlwifi/mvm/coex.c index f9c7b302e3d..fa858d548d1 100644 --- a/drivers/net/wireless/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/iwlwifi/mvm/coex.c @@ -190,7 +190,7 @@ static const __le32 iwl_combined_lookup[BT_COEX_MAX_LUT][BT_COEX_LUT_SIZE] = { cpu_to_le32(0xcc00aaaa), cpu_to_le32(0x0000aaaa), cpu_to_le32(0xc0004000), - cpu_to_le32(0x00000000), + cpu_to_le32(0x00004000), cpu_to_le32(0xf0005000), cpu_to_le32(0xf0005000), }, @@ -213,16 +213,16 @@ static const __le32 iwl_combined_lookup[BT_COEX_MAX_LUT][BT_COEX_LUT_SIZE] = { /* Tx Tx disabled */ cpu_to_le32(0xaaaaaaaa), cpu_to_le32(0xaaaaaaaa), - cpu_to_le32(0xaaaaaaaa), + cpu_to_le32(0xeeaaaaaa), cpu_to_le32(0xaaaaaaaa), cpu_to_le32(0xcc00ff28), cpu_to_le32(0x0000aaaa), cpu_to_le32(0xcc00aaaa), cpu_to_le32(0x0000aaaa), - cpu_to_le32(0xC0004000), - cpu_to_le32(0xC0004000), - cpu_to_le32(0xF0005000), - cpu_to_le32(0xF0005000), + cpu_to_le32(0xc0004000), + cpu_to_le32(0xc0004000), + cpu_to_le32(0xf0005000), + cpu_to_le32(0xf0005000), }, }; -- cgit v1.2.3-70-g09d2 From befdf8978accecac2e0739e6b5075afc62db37fe Mon Sep 17 00:00:00 2001 From: Wei Yang Date: Mon, 14 Apr 2014 09:51:19 +0800 Subject: net/mlx4_core: Preserve pci_dev_data after __mlx4_remove_one() pci_match_id() just match the static pci_device_id, which may return NULL if someone binds the driver to a device manually using /sys/bus/pci/drivers/.../new_id. This patch wrap up a helper function __mlx4_remove_one() which does the tear down function but preserve the drv_data. Functions like mlx4_pci_err_detected() and mlx4_restart_one() will call this one with out releasing drvdata. Fixes: 97a5221 "net/mlx4_core: pass pci_device_id.driver_data to __mlx4_init_one during reset". CC: Bjorn Helgaas CC: Amir Vadai CC: Jack Morgenstein CC: Or Gerlitz Signed-off-by: Wei Yang Acked-by: Jack Morgenstein Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/main.c | 172 +++++++++++++++++------------- drivers/net/ethernet/mellanox/mlx4/mlx4.h | 1 + 2 files changed, 96 insertions(+), 77 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index f0ae95f66ce..4b86c7af2a7 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -2301,13 +2301,8 @@ static int __mlx4_init_one(struct pci_dev *pdev, int pci_dev_data) /* Allow large DMA segments, up to the firmware limit of 1 GB */ dma_set_max_seg_size(&pdev->dev, 1024 * 1024 * 1024); - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) { - err = -ENOMEM; - goto err_release_regions; - } - - dev = &priv->dev; + dev = pci_get_drvdata(pdev); + priv = mlx4_priv(dev); dev->pdev = pdev; INIT_LIST_HEAD(&priv->ctx_list); spin_lock_init(&priv->ctx_lock); @@ -2535,8 +2530,7 @@ slave_start: mlx4_sense_init(dev); mlx4_start_sense(dev); - priv->pci_dev_data = pci_dev_data; - pci_set_drvdata(pdev, dev); + priv->removed = 0; return 0; @@ -2604,85 +2598,109 @@ err_disable_pdev: static int mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id) { + struct mlx4_priv *priv; + struct mlx4_dev *dev; + printk_once(KERN_INFO "%s", mlx4_version); + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + dev = &priv->dev; + pci_set_drvdata(pdev, dev); + priv->pci_dev_data = id->driver_data; + return __mlx4_init_one(pdev, id->driver_data); } -static void mlx4_remove_one(struct pci_dev *pdev) +static void __mlx4_remove_one(struct pci_dev *pdev) { struct mlx4_dev *dev = pci_get_drvdata(pdev); struct mlx4_priv *priv = mlx4_priv(dev); + int pci_dev_data; int p; - if (dev) { - /* in SRIOV it is not allowed to unload the pf's - * driver while there are alive vf's */ - if (mlx4_is_master(dev)) { - if (mlx4_how_many_lives_vf(dev)) - printk(KERN_ERR "Removing PF when there are assigned VF's !!!\n"); - } - mlx4_stop_sense(dev); - mlx4_unregister_device(dev); + if (priv->removed) + return; - for (p = 1; p <= dev->caps.num_ports; p++) { - mlx4_cleanup_port_info(&priv->port[p]); - mlx4_CLOSE_PORT(dev, p); - } + pci_dev_data = priv->pci_dev_data; - if (mlx4_is_master(dev)) - mlx4_free_resource_tracker(dev, - RES_TR_FREE_SLAVES_ONLY); - - mlx4_cleanup_counters_table(dev); - mlx4_cleanup_qp_table(dev); - mlx4_cleanup_srq_table(dev); - mlx4_cleanup_cq_table(dev); - mlx4_cmd_use_polling(dev); - mlx4_cleanup_eq_table(dev); - mlx4_cleanup_mcg_table(dev); - mlx4_cleanup_mr_table(dev); - mlx4_cleanup_xrcd_table(dev); - mlx4_cleanup_pd_table(dev); + /* in SRIOV it is not allowed to unload the pf's + * driver while there are alive vf's */ + if (mlx4_is_master(dev) && mlx4_how_many_lives_vf(dev)) + printk(KERN_ERR "Removing PF when there are assigned VF's !!!\n"); + mlx4_stop_sense(dev); + mlx4_unregister_device(dev); - if (mlx4_is_master(dev)) - mlx4_free_resource_tracker(dev, - RES_TR_FREE_STRUCTS_ONLY); - - iounmap(priv->kar); - mlx4_uar_free(dev, &priv->driver_uar); - mlx4_cleanup_uar_table(dev); - if (!mlx4_is_slave(dev)) - mlx4_clear_steering(dev); - mlx4_free_eq_table(dev); - if (mlx4_is_master(dev)) - mlx4_multi_func_cleanup(dev); - mlx4_close_hca(dev); - if (mlx4_is_slave(dev)) - mlx4_multi_func_cleanup(dev); - mlx4_cmd_cleanup(dev); - - if (dev->flags & MLX4_FLAG_MSI_X) - pci_disable_msix(pdev); - if (dev->flags & MLX4_FLAG_SRIOV) { - mlx4_warn(dev, "Disabling SR-IOV\n"); - pci_disable_sriov(pdev); - } + for (p = 1; p <= dev->caps.num_ports; p++) { + mlx4_cleanup_port_info(&priv->port[p]); + mlx4_CLOSE_PORT(dev, p); + } - if (!mlx4_is_slave(dev)) - mlx4_free_ownership(dev); + if (mlx4_is_master(dev)) + mlx4_free_resource_tracker(dev, + RES_TR_FREE_SLAVES_ONLY); + + mlx4_cleanup_counters_table(dev); + mlx4_cleanup_qp_table(dev); + mlx4_cleanup_srq_table(dev); + mlx4_cleanup_cq_table(dev); + mlx4_cmd_use_polling(dev); + mlx4_cleanup_eq_table(dev); + mlx4_cleanup_mcg_table(dev); + mlx4_cleanup_mr_table(dev); + mlx4_cleanup_xrcd_table(dev); + mlx4_cleanup_pd_table(dev); - kfree(dev->caps.qp0_tunnel); - kfree(dev->caps.qp0_proxy); - kfree(dev->caps.qp1_tunnel); - kfree(dev->caps.qp1_proxy); - kfree(dev->dev_vfs); + if (mlx4_is_master(dev)) + mlx4_free_resource_tracker(dev, + RES_TR_FREE_STRUCTS_ONLY); - kfree(priv); - pci_release_regions(pdev); - pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); + iounmap(priv->kar); + mlx4_uar_free(dev, &priv->driver_uar); + mlx4_cleanup_uar_table(dev); + if (!mlx4_is_slave(dev)) + mlx4_clear_steering(dev); + mlx4_free_eq_table(dev); + if (mlx4_is_master(dev)) + mlx4_multi_func_cleanup(dev); + mlx4_close_hca(dev); + if (mlx4_is_slave(dev)) + mlx4_multi_func_cleanup(dev); + mlx4_cmd_cleanup(dev); + + if (dev->flags & MLX4_FLAG_MSI_X) + pci_disable_msix(pdev); + if (dev->flags & MLX4_FLAG_SRIOV) { + mlx4_warn(dev, "Disabling SR-IOV\n"); + pci_disable_sriov(pdev); } + + if (!mlx4_is_slave(dev)) + mlx4_free_ownership(dev); + + kfree(dev->caps.qp0_tunnel); + kfree(dev->caps.qp0_proxy); + kfree(dev->caps.qp1_tunnel); + kfree(dev->caps.qp1_proxy); + kfree(dev->dev_vfs); + + pci_release_regions(pdev); + pci_disable_device(pdev); + memset(priv, 0, sizeof(*priv)); + priv->pci_dev_data = pci_dev_data; + priv->removed = 1; +} + +static void mlx4_remove_one(struct pci_dev *pdev) +{ + struct mlx4_dev *dev = pci_get_drvdata(pdev); + struct mlx4_priv *priv = mlx4_priv(dev); + + __mlx4_remove_one(pdev); + kfree(priv); + pci_set_drvdata(pdev, NULL); } int mlx4_restart_one(struct pci_dev *pdev) @@ -2692,7 +2710,7 @@ int mlx4_restart_one(struct pci_dev *pdev) int pci_dev_data; pci_dev_data = priv->pci_dev_data; - mlx4_remove_one(pdev); + __mlx4_remove_one(pdev); return __mlx4_init_one(pdev, pci_dev_data); } @@ -2747,7 +2765,7 @@ MODULE_DEVICE_TABLE(pci, mlx4_pci_table); static pci_ers_result_t mlx4_pci_err_detected(struct pci_dev *pdev, pci_channel_state_t state) { - mlx4_remove_one(pdev); + __mlx4_remove_one(pdev); return state == pci_channel_io_perm_failure ? PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_NEED_RESET; @@ -2755,11 +2773,11 @@ static pci_ers_result_t mlx4_pci_err_detected(struct pci_dev *pdev, static pci_ers_result_t mlx4_pci_slot_reset(struct pci_dev *pdev) { - const struct pci_device_id *id; - int ret; + struct mlx4_dev *dev = pci_get_drvdata(pdev); + struct mlx4_priv *priv = mlx4_priv(dev); + int ret; - id = pci_match_id(mlx4_pci_table, pdev); - ret = __mlx4_init_one(pdev, id->driver_data); + ret = __mlx4_init_one(pdev, priv->pci_dev_data); return ret ? PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_RECOVERED; } diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4.h b/drivers/net/ethernet/mellanox/mlx4/mlx4.h index cf8be41abb3..f9c46510196 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4.h @@ -800,6 +800,7 @@ struct mlx4_priv { spinlock_t ctx_lock; int pci_dev_data; + int removed; struct list_head pgdir_list; struct mutex pgdir_mutex; -- cgit v1.2.3-70-g09d2 From cc6ca3023f2c2bbcd062e9d4cf6afc2ba2821ada Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Sun, 13 Apr 2014 11:15:33 +0200 Subject: Revert "net: mvneta: fix usage as a module on RGMII configurations" This reverts commit e3a8786c10e75903f1269474e21fe8cb49c3a670. While this commit allows to use the mvneta driver as a module on some configurations, it breaks other configurations even if mvneta is used built-in. This breakage is due to the fact that on some RGMII platforms, the PCS bit has to be set, and on some other platforms, it has to be cleared. At the moment, we lack informations to know exactly the significance of this bit (the datasheet only says "enables PCS"), and so we can't produce a patch that will work on all platforms at this point. And since this change is breaking the network completely for many users, it's much better to revert it for now. We'll come back later with a proper fix that takes into account all platforms. Basically: * Armada XP GP is configured as RGMII-ID, and needs the PCS bit to be set. * Armada 370 Mirabox is configured as RGMII-ID, and needs the PCS bit to be cleared. And at the moment, we don't know how to make the distinction between those two cases. One hint is that the Armada XP GP appears in fact to be using a QSGMII connection with the PHY (Quad-SGMII), but configuring it as SGMII doesn't work, while RGMII-ID works. This needs more investigation, but in the mean time, let's unbreak the network for all those users. Signed-off-by: Thomas Petazzoni Reported-by: Arnaud Ebalard Reported-by: Alexander Reuter Fixes: https://bugzilla.kernel.org/show_bug.cgi?id=73401 Cc: stable@vger.kernel.org Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvneta.c | 41 ++++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index d04b1c3c9b8..b248bcbdae6 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -89,9 +89,8 @@ #define MVNETA_TX_IN_PRGRS BIT(1) #define MVNETA_TX_FIFO_EMPTY BIT(8) #define MVNETA_RX_MIN_FRAME_SIZE 0x247c -#define MVNETA_SERDES_CFG 0x24A0 +#define MVNETA_SGMII_SERDES_CFG 0x24A0 #define MVNETA_SGMII_SERDES_PROTO 0x0cc7 -#define MVNETA_RGMII_SERDES_PROTO 0x0667 #define MVNETA_TYPE_PRIO 0x24bc #define MVNETA_FORCE_UNI BIT(21) #define MVNETA_TXQ_CMD_1 0x24e4 @@ -712,6 +711,35 @@ static void mvneta_rxq_bm_disable(struct mvneta_port *pp, mvreg_write(pp, MVNETA_RXQ_CONFIG_REG(rxq->id), val); } + + +/* Sets the RGMII Enable bit (RGMIIEn) in port MAC control register */ +static void mvneta_gmac_rgmii_set(struct mvneta_port *pp, int enable) +{ + u32 val; + + val = mvreg_read(pp, MVNETA_GMAC_CTRL_2); + + if (enable) + val |= MVNETA_GMAC2_PORT_RGMII; + else + val &= ~MVNETA_GMAC2_PORT_RGMII; + + mvreg_write(pp, MVNETA_GMAC_CTRL_2, val); +} + +/* Config SGMII port */ +static void mvneta_port_sgmii_config(struct mvneta_port *pp) +{ + u32 val; + + val = mvreg_read(pp, MVNETA_GMAC_CTRL_2); + val |= MVNETA_GMAC2_PCS_ENABLE; + mvreg_write(pp, MVNETA_GMAC_CTRL_2, val); + + mvreg_write(pp, MVNETA_SGMII_SERDES_CFG, MVNETA_SGMII_SERDES_PROTO); +} + /* Start the Ethernet port RX and TX activity */ static void mvneta_port_up(struct mvneta_port *pp) { @@ -2729,15 +2757,12 @@ static void mvneta_port_power_up(struct mvneta_port *pp, int phy_mode) mvreg_write(pp, MVNETA_UNIT_INTR_CAUSE, 0); if (phy_mode == PHY_INTERFACE_MODE_SGMII) - mvreg_write(pp, MVNETA_SERDES_CFG, MVNETA_SGMII_SERDES_PROTO); - else - mvreg_write(pp, MVNETA_SERDES_CFG, MVNETA_RGMII_SERDES_PROTO); + mvneta_port_sgmii_config(pp); - val = mvreg_read(pp, MVNETA_GMAC_CTRL_2); - - val |= MVNETA_GMAC2_PCS_ENABLE | MVNETA_GMAC2_PORT_RGMII; + mvneta_gmac_rgmii_set(pp, 1); /* Cancel Port Reset */ + val = mvreg_read(pp, MVNETA_GMAC_CTRL_2); val &= ~MVNETA_GMAC2_PORT_RESET; mvreg_write(pp, MVNETA_GMAC_CTRL_2, val); -- cgit v1.2.3-70-g09d2 From 5fc68a6cad658e45dca3e0a6607df3a8e5df4ef9 Mon Sep 17 00:00:00 2001 From: Sekhar Nori Date: Wed, 19 Mar 2014 11:25:50 +0530 Subject: dma: edma: fix incorrect SG list handling The code to handle any length SG lists calls edma_resume() even before edma_start() is called. This is incorrect because edma_resume() enables edma events on the channel after which CPU (in edma_start) cannot clear posted events by writing to ECR (per the EDMA user's guide). Because of this EDMA transfers fail to start if due to some reason there is a pending EDMA event registered even before EDMA transfers are started. This can happen if an EDMA event is a byproduct of device initialization. Fix this by calling edma_resume() only if it is not the first batch of MAX_NR_SG elements. Without this patch, MMC/SD fails to function on DA850 EVM with DMA. The behaviour is triggered by specific IP and this can explain why the issue was not reported before (example with MMC/SD on AM335x). Tested on DA850 EVM and AM335x EVM-SK using MMC/SD card. Cc: stable@vger.kernel.org # v3.12.x+ Cc: Joel Fernandes Acked-by: Joel Fernandes Tested-by: Jon Ringle Tested-by: Alexander Holler Reported-by: Jon Ringle Signed-off-by: Sekhar Nori Signed-off-by: Vinod Koul --- drivers/dma/edma.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/edma.c b/drivers/dma/edma.c index cd04eb7b182..926360c2db6 100644 --- a/drivers/dma/edma.c +++ b/drivers/dma/edma.c @@ -182,11 +182,13 @@ static void edma_execute(struct edma_chan *echan) echan->ecc->dummy_slot); } - edma_resume(echan->ch_num); - if (edesc->processed <= MAX_NR_SG) { dev_dbg(dev, "first transfer starting %d\n", echan->ch_num); edma_start(echan->ch_num); + } else { + dev_dbg(dev, "chan: %d: completed %d elements, resuming\n", + echan->ch_num, edesc->processed); + edma_resume(echan->ch_num); } /* -- cgit v1.2.3-70-g09d2 From 22c0d7e36f74352f7b80679003bf7edf85736b2b Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Mon, 24 Mar 2014 23:36:01 +0100 Subject: pinctrl: rockchip: fix offset of mux registers for rk3188 The correct value of .mux_offset for rk3188 seems to be 0x60 instead of 0x68. Heiko adds: GPIO0 only has the second two IOMUX registers: - GRF_GPIO0C_IOMUX at 0x68 - GRF_GPIO0D_IOMUX at 0x6c which I guess is where my mistake comes from. It looks like there does no iomux register exist at all for the first 16 pins. In any case, the current number is wrong, and the 0x60 offset is the correct one, but I guess we need to determine what the affected pins do - do they always have a gpio mux or such? Signed-off-by: Beniamino Galvani Reviewed-by: Heiko Stuebner Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-rockchip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c index 46dddc15928..23e8812d311 100644 --- a/drivers/pinctrl/pinctrl-rockchip.c +++ b/drivers/pinctrl/pinctrl-rockchip.c @@ -1534,7 +1534,7 @@ static struct rockchip_pin_ctrl rk3188_pin_ctrl = { .nr_banks = ARRAY_SIZE(rk3188_pin_banks), .label = "RK3188-GPIO", .type = RK3188, - .mux_offset = 0x68, + .mux_offset = 0x60, .pull_calc_reg = rk3188_calc_pull_reg_and_bit, }; -- cgit v1.2.3-70-g09d2 From 14797189b35e9ec4344eeb75bdca4120cba88b69 Mon Sep 17 00:00:00 2001 From: Heiko Stübner Date: Wed, 26 Mar 2014 00:57:00 +0100 Subject: pinctrl: rockchip: add return value to rockchip_set_mux In a following change, rockchip_set_mux gets the possibility to fail. Therefore add a return value to it and honor error codes in functions using rockchip_set_mux. Signed-off-by: Heiko Stuebner Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-rockchip.c | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c index 23e8812d311..2ac194370b7 100644 --- a/drivers/pinctrl/pinctrl-rockchip.c +++ b/drivers/pinctrl/pinctrl-rockchip.c @@ -342,7 +342,7 @@ static const struct pinctrl_ops rockchip_pctrl_ops = { * @pin: pin to change * @mux: new mux function to set */ -static void rockchip_set_mux(struct rockchip_pin_bank *bank, int pin, int mux) +static int rockchip_set_mux(struct rockchip_pin_bank *bank, int pin, int mux) { struct rockchip_pinctrl *info = bank->drvdata; void __iomem *reg = info->reg_base + info->ctrl->mux_offset; @@ -365,6 +365,8 @@ static void rockchip_set_mux(struct rockchip_pin_bank *bank, int pin, int mux) writel(data, reg); spin_unlock_irqrestore(&bank->slock, flags); + + return 0; } #define RK2928_PULL_OFFSET 0x118 @@ -560,7 +562,7 @@ static int rockchip_pmx_enable(struct pinctrl_dev *pctldev, unsigned selector, const unsigned int *pins = info->groups[group].pins; const struct rockchip_pin_config *data = info->groups[group].data; struct rockchip_pin_bank *bank; - int cnt; + int cnt, ret = 0; dev_dbg(info->dev, "enable function %s group %s\n", info->functions[selector].name, info->groups[group].name); @@ -571,8 +573,18 @@ static int rockchip_pmx_enable(struct pinctrl_dev *pctldev, unsigned selector, */ for (cnt = 0; cnt < info->groups[group].npins; cnt++) { bank = pin_to_bank(info, pins[cnt]); - rockchip_set_mux(bank, pins[cnt] - bank->pin_base, - data[cnt].func); + ret = rockchip_set_mux(bank, pins[cnt] - bank->pin_base, + data[cnt].func); + if (ret) + break; + } + + if (ret) { + /* revert the already done pin settings */ + for (cnt--; cnt >= 0; cnt--) + rockchip_set_mux(bank, pins[cnt] - bank->pin_base, 0); + + return ret; } return 0; @@ -607,7 +619,7 @@ static int rockchip_pmx_gpio_set_direction(struct pinctrl_dev *pctldev, struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev); struct rockchip_pin_bank *bank; struct gpio_chip *chip; - int pin; + int pin, ret; u32 data; chip = range->gc; @@ -617,7 +629,9 @@ static int rockchip_pmx_gpio_set_direction(struct pinctrl_dev *pctldev, dev_dbg(info->dev, "gpio_direction for pin %u as %s-%d to %s\n", offset, range->name, pin, input ? "input" : "output"); - rockchip_set_mux(bank, pin, RK_FUNC_GPIO); + ret = rockchip_set_mux(bank, pin, RK_FUNC_GPIO); + if (ret < 0) + return ret; data = readl_relaxed(bank->reg_base + GPIO_SWPORT_DDR); /* set bit to 1 for output, 0 for input */ @@ -1144,9 +1158,13 @@ static int rockchip_irq_set_type(struct irq_data *d, unsigned int type) u32 polarity; u32 level; u32 data; + int ret; /* make sure the pin is configured as gpio input */ - rockchip_set_mux(bank, d->hwirq, RK_FUNC_GPIO); + ret = rockchip_set_mux(bank, d->hwirq, RK_FUNC_GPIO); + if (ret < 0) + return ret; + data = readl_relaxed(bank->reg_base + GPIO_SWPORT_DDR); data &= ~mask; writel_relaxed(data, bank->reg_base + GPIO_SWPORT_DDR); -- cgit v1.2.3-70-g09d2 From c4a532dee6b6e433d267d76d643e62ab90ca9eb9 Mon Sep 17 00:00:00 2001 From: Heiko Stübner Date: Wed, 26 Mar 2014 00:57:52 +0100 Subject: pinctrl: rockchip: handle first half of rk3188-bank0 correctly The first half of pinbank 0 only has one muxing function (as gpios) and does not have a special mux-register. Therefore ensure that no other mux function can be selected and also do not write to a non-existent register. Signed-off-by: Heiko Stuebner Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-rockchip.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c index 2ac194370b7..96c60d230c1 100644 --- a/drivers/pinctrl/pinctrl-rockchip.c +++ b/drivers/pinctrl/pinctrl-rockchip.c @@ -350,6 +350,20 @@ static int rockchip_set_mux(struct rockchip_pin_bank *bank, int pin, int mux) u8 bit; u32 data; + /* + * The first 16 pins of rk3188_bank0 are always gpios and do not have + * a mux register at all. + */ + if (bank->bank_type == RK3188_BANK0 && pin < 16) { + if (mux != RK_FUNC_GPIO) { + dev_err(info->dev, + "pin %d only supports a gpio mux\n", pin); + return -ENOTSUPP; + } else { + return 0; + } + } + dev_dbg(info->dev, "setting mux of GPIO%d-%d to %d\n", bank->bank_num, pin, mux); -- cgit v1.2.3-70-g09d2 From 6888c75b243307e616f95159a917b80121c426c7 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 9 Apr 2014 09:18:18 +0200 Subject: pinctrl: nomadik: delete stray debug print I left this in by mistake, get rid of it. Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-nomadik.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-nomadik.c b/drivers/pinctrl/pinctrl-nomadik.c index 208341fd57d..8f6f16ef73f 100644 --- a/drivers/pinctrl/pinctrl-nomadik.c +++ b/drivers/pinctrl/pinctrl-nomadik.c @@ -877,7 +877,6 @@ static void nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) struct nmk_gpio_chip *nmk_chip = container_of(chip, struct nmk_gpio_chip, chip); u32 status; - pr_err("PLONK IRQ %d\n", irq); clk_enable(nmk_chip->clk); status = readl(nmk_chip->addr + NMK_GPIO_IS); clk_disable(nmk_chip->clk); -- cgit v1.2.3-70-g09d2 From 48f15e94f5a30bf335c3c972d592bc9212aca9ff Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Mon, 31 Mar 2014 14:49:54 -0700 Subject: pinctrl: msm: Correct interrupt code for TLMM v2 Acking interrupts are done differently between on v2 and v3, so add an extra attribute to the pingroup struct to let the platform definitions control this. Also make sure to start dual edge detection by detecting the rising edge. Signed-off-by: Bjorn Andersson Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-msm.c | 6 +++++- drivers/pinctrl/pinctrl-msm.h | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pinctrl/pinctrl-msm.c b/drivers/pinctrl/pinctrl-msm.c index 38d579b47f3..e43fbce5659 100644 --- a/drivers/pinctrl/pinctrl-msm.c +++ b/drivers/pinctrl/pinctrl-msm.c @@ -665,7 +665,10 @@ static void msm_gpio_irq_ack(struct irq_data *d) spin_lock_irqsave(&pctrl->lock, flags); val = readl(pctrl->regs + g->intr_status_reg); - val &= ~BIT(g->intr_status_bit); + if (g->intr_ack_high) + val |= BIT(g->intr_status_bit); + else + val &= ~BIT(g->intr_status_bit); writel(val, pctrl->regs + g->intr_status_reg); if (test_bit(d->hwirq, pctrl->dual_edge_irqs)) @@ -744,6 +747,7 @@ static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type) break; case IRQ_TYPE_EDGE_BOTH: val |= BIT(g->intr_detection_bit); + val |= BIT(g->intr_polarity_bit); break; case IRQ_TYPE_LEVEL_LOW: break; diff --git a/drivers/pinctrl/pinctrl-msm.h b/drivers/pinctrl/pinctrl-msm.h index 8fbe9fb19f3..6e26f1b676d 100644 --- a/drivers/pinctrl/pinctrl-msm.h +++ b/drivers/pinctrl/pinctrl-msm.h @@ -84,6 +84,7 @@ struct msm_pingroup { unsigned intr_enable_bit:5; unsigned intr_status_bit:5; + unsigned intr_ack_high:1; unsigned intr_target_bit:5; unsigned intr_raw_status_bit:5; -- cgit v1.2.3-70-g09d2 From 7418b5cc81185e4ae1fec66156c464eb0b8d8f5a Mon Sep 17 00:00:00 2001 From: Sherman Yin Date: Wed, 2 Apr 2014 15:40:37 -0700 Subject: pinctrl: Rename Broadcom Capri pinctrl driver To be consistent with other Broadcom drivers, the Broadcom Capri pinctrl driver and its related CONFIG option are renamed to bcm281xx. Devicetree compatible string and binding documentation use "brcm,bcm11351-pinctrl" to match the machine binding here: Documentation/devicetree/bindings/arm/bcm/bcm11351.txt This driver supports pinctrl on BCM11130, BCM11140, BCM11351, BCM28145 and BCM28155 SoCs. Signed-off-by: Sherman Yin Reviewed-by: Matt Porter Acked-by: Linus Walleij Signed-off-by: Linus Walleij --- drivers/pinctrl/Kconfig | 8 +- drivers/pinctrl/Makefile | 2 +- drivers/pinctrl/pinctrl-bcm281xx.c | 1461 ++++++++++++++++++++++++++++++++++++ drivers/pinctrl/pinctrl-capri.c | 1454 ----------------------------------- 4 files changed, 1466 insertions(+), 1459 deletions(-) create mode 100644 drivers/pinctrl/pinctrl-bcm281xx.c delete mode 100644 drivers/pinctrl/pinctrl-capri.c (limited to 'drivers') diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index e4932403261..e00c02d0a09 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -104,16 +104,16 @@ config PINCTRL_BCM2835 select PINMUX select PINCONF -config PINCTRL_CAPRI - bool "Broadcom Capri pinctrl driver" +config PINCTRL_BCM281XX + bool "Broadcom BCM281xx pinctrl driver" depends on OF select PINMUX select PINCONF select GENERIC_PINCONF select REGMAP_MMIO help - Say Y here to support Broadcom Capri pinctrl driver, which is used for - the BCM281xx SoC family, including BCM11130, BCM11140, BCM11351, + Say Y here to support Broadcom BCM281xx pinctrl driver, which is used + for the BCM281xx SoC family, including BCM11130, BCM11140, BCM11351, BCM28145, and BCM28155 SoCs. This driver requires the pinctrl framework. GPIO is provided by a separate GPIO driver. diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index 4b835880cf8..6d3fd62b9ae 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -21,7 +21,7 @@ obj-$(CONFIG_PINCTRL_BF60x) += pinctrl-adi2-bf60x.o obj-$(CONFIG_PINCTRL_AT91) += pinctrl-at91.o obj-$(CONFIG_PINCTRL_BCM2835) += pinctrl-bcm2835.o obj-$(CONFIG_PINCTRL_BAYTRAIL) += pinctrl-baytrail.o -obj-$(CONFIG_PINCTRL_CAPRI) += pinctrl-capri.o +obj-$(CONFIG_PINCTRL_BCM281XX) += pinctrl-bcm281xx.o obj-$(CONFIG_PINCTRL_IMX) += pinctrl-imx.o obj-$(CONFIG_PINCTRL_IMX1_CORE) += pinctrl-imx1-core.o obj-$(CONFIG_PINCTRL_IMX27) += pinctrl-imx27.o diff --git a/drivers/pinctrl/pinctrl-bcm281xx.c b/drivers/pinctrl/pinctrl-bcm281xx.c new file mode 100644 index 00000000000..3bed792b2c0 --- /dev/null +++ b/drivers/pinctrl/pinctrl-bcm281xx.c @@ -0,0 +1,1461 @@ +/* + * Copyright (C) 2013 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "core.h" +#include "pinctrl-utils.h" + +/* BCM281XX Pin Control Registers Definitions */ + +/* Function Select bits are the same for all pin control registers */ +#define BCM281XX_PIN_REG_F_SEL_MASK 0x0700 +#define BCM281XX_PIN_REG_F_SEL_SHIFT 8 + +/* Standard pin register */ +#define BCM281XX_STD_PIN_REG_DRV_STR_MASK 0x0007 +#define BCM281XX_STD_PIN_REG_DRV_STR_SHIFT 0 +#define BCM281XX_STD_PIN_REG_INPUT_DIS_MASK 0x0008 +#define BCM281XX_STD_PIN_REG_INPUT_DIS_SHIFT 3 +#define BCM281XX_STD_PIN_REG_SLEW_MASK 0x0010 +#define BCM281XX_STD_PIN_REG_SLEW_SHIFT 4 +#define BCM281XX_STD_PIN_REG_PULL_UP_MASK 0x0020 +#define BCM281XX_STD_PIN_REG_PULL_UP_SHIFT 5 +#define BCM281XX_STD_PIN_REG_PULL_DN_MASK 0x0040 +#define BCM281XX_STD_PIN_REG_PULL_DN_SHIFT 6 +#define BCM281XX_STD_PIN_REG_HYST_MASK 0x0080 +#define BCM281XX_STD_PIN_REG_HYST_SHIFT 7 + +/* I2C pin register */ +#define BCM281XX_I2C_PIN_REG_INPUT_DIS_MASK 0x0004 +#define BCM281XX_I2C_PIN_REG_INPUT_DIS_SHIFT 2 +#define BCM281XX_I2C_PIN_REG_SLEW_MASK 0x0008 +#define BCM281XX_I2C_PIN_REG_SLEW_SHIFT 3 +#define BCM281XX_I2C_PIN_REG_PULL_UP_STR_MASK 0x0070 +#define BCM281XX_I2C_PIN_REG_PULL_UP_STR_SHIFT 4 + +/* HDMI pin register */ +#define BCM281XX_HDMI_PIN_REG_INPUT_DIS_MASK 0x0008 +#define BCM281XX_HDMI_PIN_REG_INPUT_DIS_SHIFT 3 +#define BCM281XX_HDMI_PIN_REG_MODE_MASK 0x0010 +#define BCM281XX_HDMI_PIN_REG_MODE_SHIFT 4 + +/** + * bcm281xx_pin_type - types of pin register + */ +enum bcm281xx_pin_type { + BCM281XX_PIN_TYPE_UNKNOWN = 0, + BCM281XX_PIN_TYPE_STD, + BCM281XX_PIN_TYPE_I2C, + BCM281XX_PIN_TYPE_HDMI, +}; + +static enum bcm281xx_pin_type std_pin = BCM281XX_PIN_TYPE_STD; +static enum bcm281xx_pin_type i2c_pin = BCM281XX_PIN_TYPE_I2C; +static enum bcm281xx_pin_type hdmi_pin = BCM281XX_PIN_TYPE_HDMI; + +/** + * bcm281xx_pin_function- define pin function + */ +struct bcm281xx_pin_function { + const char *name; + const char * const *groups; + const unsigned ngroups; +}; + +/** + * bcm281xx_pinctrl_data - Broadcom-specific pinctrl data + * @reg_base - base of pinctrl registers + */ +struct bcm281xx_pinctrl_data { + void __iomem *reg_base; + + /* List of all pins */ + const struct pinctrl_pin_desc *pins; + const unsigned npins; + + const struct bcm281xx_pin_function *functions; + const unsigned nfunctions; + + struct regmap *regmap; +}; + +/* + * Pin number definition. The order here must be the same as defined in the + * PADCTRLREG block in the RDB. + */ +#define BCM281XX_PIN_ADCSYNC 0 +#define BCM281XX_PIN_BAT_RM 1 +#define BCM281XX_PIN_BSC1_SCL 2 +#define BCM281XX_PIN_BSC1_SDA 3 +#define BCM281XX_PIN_BSC2_SCL 4 +#define BCM281XX_PIN_BSC2_SDA 5 +#define BCM281XX_PIN_CLASSGPWR 6 +#define BCM281XX_PIN_CLK_CX8 7 +#define BCM281XX_PIN_CLKOUT_0 8 +#define BCM281XX_PIN_CLKOUT_1 9 +#define BCM281XX_PIN_CLKOUT_2 10 +#define BCM281XX_PIN_CLKOUT_3 11 +#define BCM281XX_PIN_CLKREQ_IN_0 12 +#define BCM281XX_PIN_CLKREQ_IN_1 13 +#define BCM281XX_PIN_CWS_SYS_REQ1 14 +#define BCM281XX_PIN_CWS_SYS_REQ2 15 +#define BCM281XX_PIN_CWS_SYS_REQ3 16 +#define BCM281XX_PIN_DIGMIC1_CLK 17 +#define BCM281XX_PIN_DIGMIC1_DQ 18 +#define BCM281XX_PIN_DIGMIC2_CLK 19 +#define BCM281XX_PIN_DIGMIC2_DQ 20 +#define BCM281XX_PIN_GPEN13 21 +#define BCM281XX_PIN_GPEN14 22 +#define BCM281XX_PIN_GPEN15 23 +#define BCM281XX_PIN_GPIO00 24 +#define BCM281XX_PIN_GPIO01 25 +#define BCM281XX_PIN_GPIO02 26 +#define BCM281XX_PIN_GPIO03 27 +#define BCM281XX_PIN_GPIO04 28 +#define BCM281XX_PIN_GPIO05 29 +#define BCM281XX_PIN_GPIO06 30 +#define BCM281XX_PIN_GPIO07 31 +#define BCM281XX_PIN_GPIO08 32 +#define BCM281XX_PIN_GPIO09 33 +#define BCM281XX_PIN_GPIO10 34 +#define BCM281XX_PIN_GPIO11 35 +#define BCM281XX_PIN_GPIO12 36 +#define BCM281XX_PIN_GPIO13 37 +#define BCM281XX_PIN_GPIO14 38 +#define BCM281XX_PIN_GPS_PABLANK 39 +#define BCM281XX_PIN_GPS_TMARK 40 +#define BCM281XX_PIN_HDMI_SCL 41 +#define BCM281XX_PIN_HDMI_SDA 42 +#define BCM281XX_PIN_IC_DM 43 +#define BCM281XX_PIN_IC_DP 44 +#define BCM281XX_PIN_KP_COL_IP_0 45 +#define BCM281XX_PIN_KP_COL_IP_1 46 +#define BCM281XX_PIN_KP_COL_IP_2 47 +#define BCM281XX_PIN_KP_COL_IP_3 48 +#define BCM281XX_PIN_KP_ROW_OP_0 49 +#define BCM281XX_PIN_KP_ROW_OP_1 50 +#define BCM281XX_PIN_KP_ROW_OP_2 51 +#define BCM281XX_PIN_KP_ROW_OP_3 52 +#define BCM281XX_PIN_LCD_B_0 53 +#define BCM281XX_PIN_LCD_B_1 54 +#define BCM281XX_PIN_LCD_B_2 55 +#define BCM281XX_PIN_LCD_B_3 56 +#define BCM281XX_PIN_LCD_B_4 57 +#define BCM281XX_PIN_LCD_B_5 58 +#define BCM281XX_PIN_LCD_B_6 59 +#define BCM281XX_PIN_LCD_B_7 60 +#define BCM281XX_PIN_LCD_G_0 61 +#define BCM281XX_PIN_LCD_G_1 62 +#define BCM281XX_PIN_LCD_G_2 63 +#define BCM281XX_PIN_LCD_G_3 64 +#define BCM281XX_PIN_LCD_G_4 65 +#define BCM281XX_PIN_LCD_G_5 66 +#define BCM281XX_PIN_LCD_G_6 67 +#define BCM281XX_PIN_LCD_G_7 68 +#define BCM281XX_PIN_LCD_HSYNC 69 +#define BCM281XX_PIN_LCD_OE 70 +#define BCM281XX_PIN_LCD_PCLK 71 +#define BCM281XX_PIN_LCD_R_0 72 +#define BCM281XX_PIN_LCD_R_1 73 +#define BCM281XX_PIN_LCD_R_2 74 +#define BCM281XX_PIN_LCD_R_3 75 +#define BCM281XX_PIN_LCD_R_4 76 +#define BCM281XX_PIN_LCD_R_5 77 +#define BCM281XX_PIN_LCD_R_6 78 +#define BCM281XX_PIN_LCD_R_7 79 +#define BCM281XX_PIN_LCD_VSYNC 80 +#define BCM281XX_PIN_MDMGPIO0 81 +#define BCM281XX_PIN_MDMGPIO1 82 +#define BCM281XX_PIN_MDMGPIO2 83 +#define BCM281XX_PIN_MDMGPIO3 84 +#define BCM281XX_PIN_MDMGPIO4 85 +#define BCM281XX_PIN_MDMGPIO5 86 +#define BCM281XX_PIN_MDMGPIO6 87 +#define BCM281XX_PIN_MDMGPIO7 88 +#define BCM281XX_PIN_MDMGPIO8 89 +#define BCM281XX_PIN_MPHI_DATA_0 90 +#define BCM281XX_PIN_MPHI_DATA_1 91 +#define BCM281XX_PIN_MPHI_DATA_2 92 +#define BCM281XX_PIN_MPHI_DATA_3 93 +#define BCM281XX_PIN_MPHI_DATA_4 94 +#define BCM281XX_PIN_MPHI_DATA_5 95 +#define BCM281XX_PIN_MPHI_DATA_6 96 +#define BCM281XX_PIN_MPHI_DATA_7 97 +#define BCM281XX_PIN_MPHI_DATA_8 98 +#define BCM281XX_PIN_MPHI_DATA_9 99 +#define BCM281XX_PIN_MPHI_DATA_10 100 +#define BCM281XX_PIN_MPHI_DATA_11 101 +#define BCM281XX_PIN_MPHI_DATA_12 102 +#define BCM281XX_PIN_MPHI_DATA_13 103 +#define BCM281XX_PIN_MPHI_DATA_14 104 +#define BCM281XX_PIN_MPHI_DATA_15 105 +#define BCM281XX_PIN_MPHI_HA0 106 +#define BCM281XX_PIN_MPHI_HAT0 107 +#define BCM281XX_PIN_MPHI_HAT1 108 +#define BCM281XX_PIN_MPHI_HCE0_N 109 +#define BCM281XX_PIN_MPHI_HCE1_N 110 +#define BCM281XX_PIN_MPHI_HRD_N 111 +#define BCM281XX_PIN_MPHI_HWR_N 112 +#define BCM281XX_PIN_MPHI_RUN0 113 +#define BCM281XX_PIN_MPHI_RUN1 114 +#define BCM281XX_PIN_MTX_SCAN_CLK 115 +#define BCM281XX_PIN_MTX_SCAN_DATA 116 +#define BCM281XX_PIN_NAND_AD_0 117 +#define BCM281XX_PIN_NAND_AD_1 118 +#define BCM281XX_PIN_NAND_AD_2 119 +#define BCM281XX_PIN_NAND_AD_3 120 +#define BCM281XX_PIN_NAND_AD_4 121 +#define BCM281XX_PIN_NAND_AD_5 122 +#define BCM281XX_PIN_NAND_AD_6 123 +#define BCM281XX_PIN_NAND_AD_7 124 +#define BCM281XX_PIN_NAND_ALE 125 +#define BCM281XX_PIN_NAND_CEN_0 126 +#define BCM281XX_PIN_NAND_CEN_1 127 +#define BCM281XX_PIN_NAND_CLE 128 +#define BCM281XX_PIN_NAND_OEN 129 +#define BCM281XX_PIN_NAND_RDY_0 130 +#define BCM281XX_PIN_NAND_RDY_1 131 +#define BCM281XX_PIN_NAND_WEN 132 +#define BCM281XX_PIN_NAND_WP 133 +#define BCM281XX_PIN_PC1 134 +#define BCM281XX_PIN_PC2 135 +#define BCM281XX_PIN_PMU_INT 136 +#define BCM281XX_PIN_PMU_SCL 137 +#define BCM281XX_PIN_PMU_SDA 138 +#define BCM281XX_PIN_RFST2G_MTSLOTEN3G 139 +#define BCM281XX_PIN_RGMII_0_RX_CTL 140 +#define BCM281XX_PIN_RGMII_0_RXC 141 +#define BCM281XX_PIN_RGMII_0_RXD_0 142 +#define BCM281XX_PIN_RGMII_0_RXD_1 143 +#define BCM281XX_PIN_RGMII_0_RXD_2 144 +#define BCM281XX_PIN_RGMII_0_RXD_3 145 +#define BCM281XX_PIN_RGMII_0_TX_CTL 146 +#define BCM281XX_PIN_RGMII_0_TXC 147 +#define BCM281XX_PIN_RGMII_0_TXD_0 148 +#define BCM281XX_PIN_RGMII_0_TXD_1 149 +#define BCM281XX_PIN_RGMII_0_TXD_2 150 +#define BCM281XX_PIN_RGMII_0_TXD_3 151 +#define BCM281XX_PIN_RGMII_1_RX_CTL 152 +#define BCM281XX_PIN_RGMII_1_RXC 153 +#define BCM281XX_PIN_RGMII_1_RXD_0 154 +#define BCM281XX_PIN_RGMII_1_RXD_1 155 +#define BCM281XX_PIN_RGMII_1_RXD_2 156 +#define BCM281XX_PIN_RGMII_1_RXD_3 157 +#define BCM281XX_PIN_RGMII_1_TX_CTL 158 +#define BCM281XX_PIN_RGMII_1_TXC 159 +#define BCM281XX_PIN_RGMII_1_TXD_0 160 +#define BCM281XX_PIN_RGMII_1_TXD_1 161 +#define BCM281XX_PIN_RGMII_1_TXD_2 162 +#define BCM281XX_PIN_RGMII_1_TXD_3 163 +#define BCM281XX_PIN_RGMII_GPIO_0 164 +#define BCM281XX_PIN_RGMII_GPIO_1 165 +#define BCM281XX_PIN_RGMII_GPIO_2 166 +#define BCM281XX_PIN_RGMII_GPIO_3 167 +#define BCM281XX_PIN_RTXDATA2G_TXDATA3G1 168 +#define BCM281XX_PIN_RTXEN2G_TXDATA3G2 169 +#define BCM281XX_PIN_RXDATA3G0 170 +#define BCM281XX_PIN_RXDATA3G1 171 +#define BCM281XX_PIN_RXDATA3G2 172 +#define BCM281XX_PIN_SDIO1_CLK 173 +#define BCM281XX_PIN_SDIO1_CMD 174 +#define BCM281XX_PIN_SDIO1_DATA_0 175 +#define BCM281XX_PIN_SDIO1_DATA_1 176 +#define BCM281XX_PIN_SDIO1_DATA_2 177 +#define BCM281XX_PIN_SDIO1_DATA_3 178 +#define BCM281XX_PIN_SDIO4_CLK 179 +#define BCM281XX_PIN_SDIO4_CMD 180 +#define BCM281XX_PIN_SDIO4_DATA_0 181 +#define BCM281XX_PIN_SDIO4_DATA_1 182 +#define BCM281XX_PIN_SDIO4_DATA_2 183 +#define BCM281XX_PIN_SDIO4_DATA_3 184 +#define BCM281XX_PIN_SIM_CLK 185 +#define BCM281XX_PIN_SIM_DATA 186 +#define BCM281XX_PIN_SIM_DET 187 +#define BCM281XX_PIN_SIM_RESETN 188 +#define BCM281XX_PIN_SIM2_CLK 189 +#define BCM281XX_PIN_SIM2_DATA 190 +#define BCM281XX_PIN_SIM2_DET 191 +#define BCM281XX_PIN_SIM2_RESETN 192 +#define BCM281XX_PIN_SRI_C 193 +#define BCM281XX_PIN_SRI_D 194 +#define BCM281XX_PIN_SRI_E 195 +#define BCM281XX_PIN_SSP_EXTCLK 196 +#define BCM281XX_PIN_SSP0_CLK 197 +#define BCM281XX_PIN_SSP0_FS 198 +#define BCM281XX_PIN_SSP0_RXD 199 +#define BCM281XX_PIN_SSP0_TXD 200 +#define BCM281XX_PIN_SSP2_CLK 201 +#define BCM281XX_PIN_SSP2_FS_0 202 +#define BCM281XX_PIN_SSP2_FS_1 203 +#define BCM281XX_PIN_SSP2_FS_2 204 +#define BCM281XX_PIN_SSP2_FS_3 205 +#define BCM281XX_PIN_SSP2_RXD_0 206 +#define BCM281XX_PIN_SSP2_RXD_1 207 +#define BCM281XX_PIN_SSP2_TXD_0 208 +#define BCM281XX_PIN_SSP2_TXD_1 209 +#define BCM281XX_PIN_SSP3_CLK 210 +#define BCM281XX_PIN_SSP3_FS 211 +#define BCM281XX_PIN_SSP3_RXD 212 +#define BCM281XX_PIN_SSP3_TXD 213 +#define BCM281XX_PIN_SSP4_CLK 214 +#define BCM281XX_PIN_SSP4_FS 215 +#define BCM281XX_PIN_SSP4_RXD 216 +#define BCM281XX_PIN_SSP4_TXD 217 +#define BCM281XX_PIN_SSP5_CLK 218 +#define BCM281XX_PIN_SSP5_FS 219 +#define BCM281XX_PIN_SSP5_RXD 220 +#define BCM281XX_PIN_SSP5_TXD 221 +#define BCM281XX_PIN_SSP6_CLK 222 +#define BCM281XX_PIN_SSP6_FS 223 +#define BCM281XX_PIN_SSP6_RXD 224 +#define BCM281XX_PIN_SSP6_TXD 225 +#define BCM281XX_PIN_STAT_1 226 +#define BCM281XX_PIN_STAT_2 227 +#define BCM281XX_PIN_SYSCLKEN 228 +#define BCM281XX_PIN_TRACECLK 229 +#define BCM281XX_PIN_TRACEDT00 230 +#define BCM281XX_PIN_TRACEDT01 231 +#define BCM281XX_PIN_TRACEDT02 232 +#define BCM281XX_PIN_TRACEDT03 233 +#define BCM281XX_PIN_TRACEDT04 234 +#define BCM281XX_PIN_TRACEDT05 235 +#define BCM281XX_PIN_TRACEDT06 236 +#define BCM281XX_PIN_TRACEDT07 237 +#define BCM281XX_PIN_TRACEDT08 238 +#define BCM281XX_PIN_TRACEDT09 239 +#define BCM281XX_PIN_TRACEDT10 240 +#define BCM281XX_PIN_TRACEDT11 241 +#define BCM281XX_PIN_TRACEDT12 242 +#define BCM281XX_PIN_TRACEDT13 243 +#define BCM281XX_PIN_TRACEDT14 244 +#define BCM281XX_PIN_TRACEDT15 245 +#define BCM281XX_PIN_TXDATA3G0 246 +#define BCM281XX_PIN_TXPWRIND 247 +#define BCM281XX_PIN_UARTB1_UCTS 248 +#define BCM281XX_PIN_UARTB1_URTS 249 +#define BCM281XX_PIN_UARTB1_URXD 250 +#define BCM281XX_PIN_UARTB1_UTXD 251 +#define BCM281XX_PIN_UARTB2_URXD 252 +#define BCM281XX_PIN_UARTB2_UTXD 253 +#define BCM281XX_PIN_UARTB3_UCTS 254 +#define BCM281XX_PIN_UARTB3_URTS 255 +#define BCM281XX_PIN_UARTB3_URXD 256 +#define BCM281XX_PIN_UARTB3_UTXD 257 +#define BCM281XX_PIN_UARTB4_UCTS 258 +#define BCM281XX_PIN_UARTB4_URTS 259 +#define BCM281XX_PIN_UARTB4_URXD 260 +#define BCM281XX_PIN_UARTB4_UTXD 261 +#define BCM281XX_PIN_VC_CAM1_SCL 262 +#define BCM281XX_PIN_VC_CAM1_SDA 263 +#define BCM281XX_PIN_VC_CAM2_SCL 264 +#define BCM281XX_PIN_VC_CAM2_SDA 265 +#define BCM281XX_PIN_VC_CAM3_SCL 266 +#define BCM281XX_PIN_VC_CAM3_SDA 267 + +#define BCM281XX_PIN_DESC(a, b, c) \ + { .number = a, .name = b, .drv_data = &c##_pin } + +/* + * Pin description definition. The order here must be the same as defined in + * the PADCTRLREG block in the RDB, since the pin number is used as an index + * into this array. + */ +static const struct pinctrl_pin_desc bcm281xx_pinctrl_pins[] = { + BCM281XX_PIN_DESC(BCM281XX_PIN_ADCSYNC, "adcsync", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_BAT_RM, "bat_rm", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_BSC1_SCL, "bsc1_scl", i2c), + BCM281XX_PIN_DESC(BCM281XX_PIN_BSC1_SDA, "bsc1_sda", i2c), + BCM281XX_PIN_DESC(BCM281XX_PIN_BSC2_SCL, "bsc2_scl", i2c), + BCM281XX_PIN_DESC(BCM281XX_PIN_BSC2_SDA, "bsc2_sda", i2c), + BCM281XX_PIN_DESC(BCM281XX_PIN_CLASSGPWR, "classgpwr", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_CLK_CX8, "clk_cx8", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_CLKOUT_0, "clkout_0", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_CLKOUT_1, "clkout_1", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_CLKOUT_2, "clkout_2", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_CLKOUT_3, "clkout_3", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_CLKREQ_IN_0, "clkreq_in_0", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_CLKREQ_IN_1, "clkreq_in_1", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_CWS_SYS_REQ1, "cws_sys_req1", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_CWS_SYS_REQ2, "cws_sys_req2", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_CWS_SYS_REQ3, "cws_sys_req3", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_DIGMIC1_CLK, "digmic1_clk", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_DIGMIC1_DQ, "digmic1_dq", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_DIGMIC2_CLK, "digmic2_clk", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_DIGMIC2_DQ, "digmic2_dq", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_GPEN13, "gpen13", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_GPEN14, "gpen14", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_GPEN15, "gpen15", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_GPIO00, "gpio00", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_GPIO01, "gpio01", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_GPIO02, "gpio02", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_GPIO03, "gpio03", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_GPIO04, "gpio04", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_GPIO05, "gpio05", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_GPIO06, "gpio06", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_GPIO07, "gpio07", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_GPIO08, "gpio08", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_GPIO09, "gpio09", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_GPIO10, "gpio10", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_GPIO11, "gpio11", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_GPIO12, "gpio12", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_GPIO13, "gpio13", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_GPIO14, "gpio14", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_GPS_PABLANK, "gps_pablank", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_GPS_TMARK, "gps_tmark", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_HDMI_SCL, "hdmi_scl", hdmi), + BCM281XX_PIN_DESC(BCM281XX_PIN_HDMI_SDA, "hdmi_sda", hdmi), + BCM281XX_PIN_DESC(BCM281XX_PIN_IC_DM, "ic_dm", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_IC_DP, "ic_dp", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_KP_COL_IP_0, "kp_col_ip_0", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_KP_COL_IP_1, "kp_col_ip_1", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_KP_COL_IP_2, "kp_col_ip_2", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_KP_COL_IP_3, "kp_col_ip_3", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_KP_ROW_OP_0, "kp_row_op_0", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_KP_ROW_OP_1, "kp_row_op_1", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_KP_ROW_OP_2, "kp_row_op_2", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_KP_ROW_OP_3, "kp_row_op_3", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_LCD_B_0, "lcd_b_0", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_LCD_B_1, "lcd_b_1", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_LCD_B_2, "lcd_b_2", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_LCD_B_3, "lcd_b_3", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_LCD_B_4, "lcd_b_4", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_LCD_B_5, "lcd_b_5", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_LCD_B_6, "lcd_b_6", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_LCD_B_7, "lcd_b_7", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_LCD_G_0, "lcd_g_0", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_LCD_G_1, "lcd_g_1", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_LCD_G_2, "lcd_g_2", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_LCD_G_3, "lcd_g_3", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_LCD_G_4, "lcd_g_4", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_LCD_G_5, "lcd_g_5", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_LCD_G_6, "lcd_g_6", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_LCD_G_7, "lcd_g_7", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_LCD_HSYNC, "lcd_hsync", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_LCD_OE, "lcd_oe", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_LCD_PCLK, "lcd_pclk", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_LCD_R_0, "lcd_r_0", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_LCD_R_1, "lcd_r_1", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_LCD_R_2, "lcd_r_2", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_LCD_R_3, "lcd_r_3", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_LCD_R_4, "lcd_r_4", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_LCD_R_5, "lcd_r_5", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_LCD_R_6, "lcd_r_6", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_LCD_R_7, "lcd_r_7", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_LCD_VSYNC, "lcd_vsync", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_MDMGPIO0, "mdmgpio0", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_MDMGPIO1, "mdmgpio1", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_MDMGPIO2, "mdmgpio2", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_MDMGPIO3, "mdmgpio3", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_MDMGPIO4, "mdmgpio4", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_MDMGPIO5, "mdmgpio5", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_MDMGPIO6, "mdmgpio6", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_MDMGPIO7, "mdmgpio7", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_MDMGPIO8, "mdmgpio8", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_MPHI_DATA_0, "mphi_data_0", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_MPHI_DATA_1, "mphi_data_1", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_MPHI_DATA_2, "mphi_data_2", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_MPHI_DATA_3, "mphi_data_3", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_MPHI_DATA_4, "mphi_data_4", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_MPHI_DATA_5, "mphi_data_5", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_MPHI_DATA_6, "mphi_data_6", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_MPHI_DATA_7, "mphi_data_7", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_MPHI_DATA_8, "mphi_data_8", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_MPHI_DATA_9, "mphi_data_9", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_MPHI_DATA_10, "mphi_data_10", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_MPHI_DATA_11, "mphi_data_11", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_MPHI_DATA_12, "mphi_data_12", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_MPHI_DATA_13, "mphi_data_13", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_MPHI_DATA_14, "mphi_data_14", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_MPHI_DATA_15, "mphi_data_15", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_MPHI_HA0, "mphi_ha0", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_MPHI_HAT0, "mphi_hat0", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_MPHI_HAT1, "mphi_hat1", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_MPHI_HCE0_N, "mphi_hce0_n", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_MPHI_HCE1_N, "mphi_hce1_n", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_MPHI_HRD_N, "mphi_hrd_n", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_MPHI_HWR_N, "mphi_hwr_n", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_MPHI_RUN0, "mphi_run0", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_MPHI_RUN1, "mphi_run1", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_MTX_SCAN_CLK, "mtx_scan_clk", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_MTX_SCAN_DATA, "mtx_scan_data", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_NAND_AD_0, "nand_ad_0", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_NAND_AD_1, "nand_ad_1", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_NAND_AD_2, "nand_ad_2", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_NAND_AD_3, "nand_ad_3", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_NAND_AD_4, "nand_ad_4", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_NAND_AD_5, "nand_ad_5", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_NAND_AD_6, "nand_ad_6", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_NAND_AD_7, "nand_ad_7", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_NAND_ALE, "nand_ale", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_NAND_CEN_0, "nand_cen_0", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_NAND_CEN_1, "nand_cen_1", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_NAND_CLE, "nand_cle", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_NAND_OEN, "nand_oen", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_NAND_RDY_0, "nand_rdy_0", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_NAND_RDY_1, "nand_rdy_1", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_NAND_WEN, "nand_wen", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_NAND_WP, "nand_wp", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_PC1, "pc1", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_PC2, "pc2", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_PMU_INT, "pmu_int", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_PMU_SCL, "pmu_scl", i2c), + BCM281XX_PIN_DESC(BCM281XX_PIN_PMU_SDA, "pmu_sda", i2c), + BCM281XX_PIN_DESC(BCM281XX_PIN_RFST2G_MTSLOTEN3G, "rfst2g_mtsloten3g", + std), + BCM281XX_PIN_DESC(BCM281XX_PIN_RGMII_0_RX_CTL, "rgmii_0_rx_ctl", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_RGMII_0_RXC, "rgmii_0_rxc", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_RGMII_0_RXD_0, "rgmii_0_rxd_0", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_RGMII_0_RXD_1, "rgmii_0_rxd_1", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_RGMII_0_RXD_2, "rgmii_0_rxd_2", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_RGMII_0_RXD_3, "rgmii_0_rxd_3", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_RGMII_0_TX_CTL, "rgmii_0_tx_ctl", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_RGMII_0_TXC, "rgmii_0_txc", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_RGMII_0_TXD_0, "rgmii_0_txd_0", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_RGMII_0_TXD_1, "rgmii_0_txd_1", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_RGMII_0_TXD_2, "rgmii_0_txd_2", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_RGMII_0_TXD_3, "rgmii_0_txd_3", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_RGMII_1_RX_CTL, "rgmii_1_rx_ctl", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_RGMII_1_RXC, "rgmii_1_rxc", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_RGMII_1_RXD_0, "rgmii_1_rxd_0", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_RGMII_1_RXD_1, "rgmii_1_rxd_1", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_RGMII_1_RXD_2, "rgmii_1_rxd_2", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_RGMII_1_RXD_3, "rgmii_1_rxd_3", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_RGMII_1_TX_CTL, "rgmii_1_tx_ctl", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_RGMII_1_TXC, "rgmii_1_txc", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_RGMII_1_TXD_0, "rgmii_1_txd_0", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_RGMII_1_TXD_1, "rgmii_1_txd_1", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_RGMII_1_TXD_2, "rgmii_1_txd_2", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_RGMII_1_TXD_3, "rgmii_1_txd_3", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_RGMII_GPIO_0, "rgmii_gpio_0", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_RGMII_GPIO_1, "rgmii_gpio_1", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_RGMII_GPIO_2, "rgmii_gpio_2", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_RGMII_GPIO_3, "rgmii_gpio_3", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_RTXDATA2G_TXDATA3G1, + "rtxdata2g_txdata3g1", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_RTXEN2G_TXDATA3G2, "rtxen2g_txdata3g2", + std), + BCM281XX_PIN_DESC(BCM281XX_PIN_RXDATA3G0, "rxdata3g0", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_RXDATA3G1, "rxdata3g1", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_RXDATA3G2, "rxdata3g2", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_SDIO1_CLK, "sdio1_clk", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_SDIO1_CMD, "sdio1_cmd", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_SDIO1_DATA_0, "sdio1_data_0", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_SDIO1_DATA_1, "sdio1_data_1", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_SDIO1_DATA_2, "sdio1_data_2", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_SDIO1_DATA_3, "sdio1_data_3", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_SDIO4_CLK, "sdio4_clk", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_SDIO4_CMD, "sdio4_cmd", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_SDIO4_DATA_0, "sdio4_data_0", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_SDIO4_DATA_1, "sdio4_data_1", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_SDIO4_DATA_2, "sdio4_data_2", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_SDIO4_DATA_3, "sdio4_data_3", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_SIM_CLK, "sim_clk", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_SIM_DATA, "sim_data", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_SIM_DET, "sim_det", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_SIM_RESETN, "sim_resetn", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_SIM2_CLK, "sim2_clk", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_SIM2_DATA, "sim2_data", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_SIM2_DET, "sim2_det", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_SIM2_RESETN, "sim2_resetn", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_SRI_C, "sri_c", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_SRI_D, "sri_d", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_SRI_E, "sri_e", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_SSP_EXTCLK, "ssp_extclk", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_SSP0_CLK, "ssp0_clk", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_SSP0_FS, "ssp0_fs", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_SSP0_RXD, "ssp0_rxd", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_SSP0_TXD, "ssp0_txd", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_SSP2_CLK, "ssp2_clk", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_SSP2_FS_0, "ssp2_fs_0", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_SSP2_FS_1, "ssp2_fs_1", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_SSP2_FS_2, "ssp2_fs_2", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_SSP2_FS_3, "ssp2_fs_3", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_SSP2_RXD_0, "ssp2_rxd_0", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_SSP2_RXD_1, "ssp2_rxd_1", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_SSP2_TXD_0, "ssp2_txd_0", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_SSP2_TXD_1, "ssp2_txd_1", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_SSP3_CLK, "ssp3_clk", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_SSP3_FS, "ssp3_fs", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_SSP3_RXD, "ssp3_rxd", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_SSP3_TXD, "ssp3_txd", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_SSP4_CLK, "ssp4_clk", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_SSP4_FS, "ssp4_fs", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_SSP4_RXD, "ssp4_rxd", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_SSP4_TXD, "ssp4_txd", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_SSP5_CLK, "ssp5_clk", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_SSP5_FS, "ssp5_fs", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_SSP5_RXD, "ssp5_rxd", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_SSP5_TXD, "ssp5_txd", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_SSP6_CLK, "ssp6_clk", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_SSP6_FS, "ssp6_fs", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_SSP6_RXD, "ssp6_rxd", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_SSP6_TXD, "ssp6_txd", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_STAT_1, "stat_1", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_STAT_2, "stat_2", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_SYSCLKEN, "sysclken", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_TRACECLK, "traceclk", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_TRACEDT00, "tracedt00", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_TRACEDT01, "tracedt01", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_TRACEDT02, "tracedt02", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_TRACEDT03, "tracedt03", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_TRACEDT04, "tracedt04", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_TRACEDT05, "tracedt05", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_TRACEDT06, "tracedt06", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_TRACEDT07, "tracedt07", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_TRACEDT08, "tracedt08", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_TRACEDT09, "tracedt09", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_TRACEDT10, "tracedt10", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_TRACEDT11, "tracedt11", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_TRACEDT12, "tracedt12", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_TRACEDT13, "tracedt13", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_TRACEDT14, "tracedt14", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_TRACEDT15, "tracedt15", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_TXDATA3G0, "txdata3g0", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_TXPWRIND, "txpwrind", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_UARTB1_UCTS, "uartb1_ucts", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_UARTB1_URTS, "uartb1_urts", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_UARTB1_URXD, "uartb1_urxd", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_UARTB1_UTXD, "uartb1_utxd", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_UARTB2_URXD, "uartb2_urxd", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_UARTB2_UTXD, "uartb2_utxd", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_UARTB3_UCTS, "uartb3_ucts", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_UARTB3_URTS, "uartb3_urts", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_UARTB3_URXD, "uartb3_urxd", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_UARTB3_UTXD, "uartb3_utxd", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_UARTB4_UCTS, "uartb4_ucts", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_UARTB4_URTS, "uartb4_urts", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_UARTB4_URXD, "uartb4_urxd", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_UARTB4_UTXD, "uartb4_utxd", std), + BCM281XX_PIN_DESC(BCM281XX_PIN_VC_CAM1_SCL, "vc_cam1_scl", i2c), + BCM281XX_PIN_DESC(BCM281XX_PIN_VC_CAM1_SDA, "vc_cam1_sda", i2c), + BCM281XX_PIN_DESC(BCM281XX_PIN_VC_CAM2_SCL, "vc_cam2_scl", i2c), + BCM281XX_PIN_DESC(BCM281XX_PIN_VC_CAM2_SDA, "vc_cam2_sda", i2c), + BCM281XX_PIN_DESC(BCM281XX_PIN_VC_CAM3_SCL, "vc_cam3_scl", i2c), + BCM281XX_PIN_DESC(BCM281XX_PIN_VC_CAM3_SDA, "vc_cam3_sda", i2c), +}; + +static const char * const bcm281xx_alt_groups[] = { + "adcsync", + "bat_rm", + "bsc1_scl", + "bsc1_sda", + "bsc2_scl", + "bsc2_sda", + "classgpwr", + "clk_cx8", + "clkout_0", + "clkout_1", + "clkout_2", + "clkout_3", + "clkreq_in_0", + "clkreq_in_1", + "cws_sys_req1", + "cws_sys_req2", + "cws_sys_req3", + "digmic1_clk", + "digmic1_dq", + "digmic2_clk", + "digmic2_dq", + "gpen13", + "gpen14", + "gpen15", + "gpio00", + "gpio01", + "gpio02", + "gpio03", + "gpio04", + "gpio05", + "gpio06", + "gpio07", + "gpio08", + "gpio09", + "gpio10", + "gpio11", + "gpio12", + "gpio13", + "gpio14", + "gps_pablank", + "gps_tmark", + "hdmi_scl", + "hdmi_sda", + "ic_dm", + "ic_dp", + "kp_col_ip_0", + "kp_col_ip_1", + "kp_col_ip_2", + "kp_col_ip_3", + "kp_row_op_0", + "kp_row_op_1", + "kp_row_op_2", + "kp_row_op_3", + "lcd_b_0", + "lcd_b_1", + "lcd_b_2", + "lcd_b_3", + "lcd_b_4", + "lcd_b_5", + "lcd_b_6", + "lcd_b_7", + "lcd_g_0", + "lcd_g_1", + "lcd_g_2", + "lcd_g_3", + "lcd_g_4", + "lcd_g_5", + "lcd_g_6", + "lcd_g_7", + "lcd_hsync", + "lcd_oe", + "lcd_pclk", + "lcd_r_0", + "lcd_r_1", + "lcd_r_2", + "lcd_r_3", + "lcd_r_4", + "lcd_r_5", + "lcd_r_6", + "lcd_r_7", + "lcd_vsync", + "mdmgpio0", + "mdmgpio1", + "mdmgpio2", + "mdmgpio3", + "mdmgpio4", + "mdmgpio5", + "mdmgpio6", + "mdmgpio7", + "mdmgpio8", + "mphi_data_0", + "mphi_data_1", + "mphi_data_2", + "mphi_data_3", + "mphi_data_4", + "mphi_data_5", + "mphi_data_6", + "mphi_data_7", + "mphi_data_8", + "mphi_data_9", + "mphi_data_10", + "mphi_data_11", + "mphi_data_12", + "mphi_data_13", + "mphi_data_14", + "mphi_data_15", + "mphi_ha0", + "mphi_hat0", + "mphi_hat1", + "mphi_hce0_n", + "mphi_hce1_n", + "mphi_hrd_n", + "mphi_hwr_n", + "mphi_run0", + "mphi_run1", + "mtx_scan_clk", + "mtx_scan_data", + "nand_ad_0", + "nand_ad_1", + "nand_ad_2", + "nand_ad_3", + "nand_ad_4", + "nand_ad_5", + "nand_ad_6", + "nand_ad_7", + "nand_ale", + "nand_cen_0", + "nand_cen_1", + "nand_cle", + "nand_oen", + "nand_rdy_0", + "nand_rdy_1", + "nand_wen", + "nand_wp", + "pc1", + "pc2", + "pmu_int", + "pmu_scl", + "pmu_sda", + "rfst2g_mtsloten3g", + "rgmii_0_rx_ctl", + "rgmii_0_rxc", + "rgmii_0_rxd_0", + "rgmii_0_rxd_1", + "rgmii_0_rxd_2", + "rgmii_0_rxd_3", + "rgmii_0_tx_ctl", + "rgmii_0_txc", + "rgmii_0_txd_0", + "rgmii_0_txd_1", + "rgmii_0_txd_2", + "rgmii_0_txd_3", + "rgmii_1_rx_ctl", + "rgmii_1_rxc", + "rgmii_1_rxd_0", + "rgmii_1_rxd_1", + "rgmii_1_rxd_2", + "rgmii_1_rxd_3", + "rgmii_1_tx_ctl", + "rgmii_1_txc", + "rgmii_1_txd_0", + "rgmii_1_txd_1", + "rgmii_1_txd_2", + "rgmii_1_txd_3", + "rgmii_gpio_0", + "rgmii_gpio_1", + "rgmii_gpio_2", + "rgmii_gpio_3", + "rtxdata2g_txdata3g1", + "rtxen2g_txdata3g2", + "rxdata3g0", + "rxdata3g1", + "rxdata3g2", + "sdio1_clk", + "sdio1_cmd", + "sdio1_data_0", + "sdio1_data_1", + "sdio1_data_2", + "sdio1_data_3", + "sdio4_clk", + "sdio4_cmd", + "sdio4_data_0", + "sdio4_data_1", + "sdio4_data_2", + "sdio4_data_3", + "sim_clk", + "sim_data", + "sim_det", + "sim_resetn", + "sim2_clk", + "sim2_data", + "sim2_det", + "sim2_resetn", + "sri_c", + "sri_d", + "sri_e", + "ssp_extclk", + "ssp0_clk", + "ssp0_fs", + "ssp0_rxd", + "ssp0_txd", + "ssp2_clk", + "ssp2_fs_0", + "ssp2_fs_1", + "ssp2_fs_2", + "ssp2_fs_3", + "ssp2_rxd_0", + "ssp2_rxd_1", + "ssp2_txd_0", + "ssp2_txd_1", + "ssp3_clk", + "ssp3_fs", + "ssp3_rxd", + "ssp3_txd", + "ssp4_clk", + "ssp4_fs", + "ssp4_rxd", + "ssp4_txd", + "ssp5_clk", + "ssp5_fs", + "ssp5_rxd", + "ssp5_txd", + "ssp6_clk", + "ssp6_fs", + "ssp6_rxd", + "ssp6_txd", + "stat_1", + "stat_2", + "sysclken", + "traceclk", + "tracedt00", + "tracedt01", + "tracedt02", + "tracedt03", + "tracedt04", + "tracedt05", + "tracedt06", + "tracedt07", + "tracedt08", + "tracedt09", + "tracedt10", + "tracedt11", + "tracedt12", + "tracedt13", + "tracedt14", + "tracedt15", + "txdata3g0", + "txpwrind", + "uartb1_ucts", + "uartb1_urts", + "uartb1_urxd", + "uartb1_utxd", + "uartb2_urxd", + "uartb2_utxd", + "uartb3_ucts", + "uartb3_urts", + "uartb3_urxd", + "uartb3_utxd", + "uartb4_ucts", + "uartb4_urts", + "uartb4_urxd", + "uartb4_utxd", + "vc_cam1_scl", + "vc_cam1_sda", + "vc_cam2_scl", + "vc_cam2_sda", + "vc_cam3_scl", + "vc_cam3_sda", +}; + +/* Every pin can implement all ALT1-ALT4 functions */ +#define BCM281XX_PIN_FUNCTION(fcn_name) \ +{ \ + .name = #fcn_name, \ + .groups = bcm281xx_alt_groups, \ + .ngroups = ARRAY_SIZE(bcm281xx_alt_groups), \ +} + +static const struct bcm281xx_pin_function bcm281xx_functions[] = { + BCM281XX_PIN_FUNCTION(alt1), + BCM281XX_PIN_FUNCTION(alt2), + BCM281XX_PIN_FUNCTION(alt3), + BCM281XX_PIN_FUNCTION(alt4), +}; + +static struct bcm281xx_pinctrl_data bcm281xx_pinctrl = { + .pins = bcm281xx_pinctrl_pins, + .npins = ARRAY_SIZE(bcm281xx_pinctrl_pins), + .functions = bcm281xx_functions, + .nfunctions = ARRAY_SIZE(bcm281xx_functions), +}; + +static inline enum bcm281xx_pin_type pin_type_get(struct pinctrl_dev *pctldev, + unsigned pin) +{ + struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); + + if (pin >= pdata->npins) + return BCM281XX_PIN_TYPE_UNKNOWN; + + return *(enum bcm281xx_pin_type *)(pdata->pins[pin].drv_data); +} + +#define BCM281XX_PIN_SHIFT(type, param) \ + (BCM281XX_ ## type ## _PIN_REG_ ## param ## _SHIFT) + +#define BCM281XX_PIN_MASK(type, param) \ + (BCM281XX_ ## type ## _PIN_REG_ ## param ## _MASK) + +/* + * This helper function is used to build up the value and mask used to write to + * a pin register, but does not actually write to the register. + */ +static inline void bcm281xx_pin_update(u32 *reg_val, u32 *reg_mask, + u32 param_val, u32 param_shift, + u32 param_mask) +{ + *reg_val &= ~param_mask; + *reg_val |= (param_val << param_shift) & param_mask; + *reg_mask |= param_mask; +} + +static struct regmap_config bcm281xx_pinctrl_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = BCM281XX_PIN_VC_CAM3_SDA, +}; + +static int bcm281xx_pinctrl_get_groups_count(struct pinctrl_dev *pctldev) +{ + struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); + + return pdata->npins; +} + +static const char *bcm281xx_pinctrl_get_group_name(struct pinctrl_dev *pctldev, + unsigned group) +{ + struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); + + return pdata->pins[group].name; +} + +static int bcm281xx_pinctrl_get_group_pins(struct pinctrl_dev *pctldev, + unsigned group, + const unsigned **pins, + unsigned *num_pins) +{ + struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); + + *pins = &pdata->pins[group].number; + *num_pins = 1; + + return 0; +} + +static void bcm281xx_pinctrl_pin_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *s, + unsigned offset) +{ + seq_printf(s, " %s", dev_name(pctldev->dev)); +} + +static struct pinctrl_ops bcm281xx_pinctrl_ops = { + .get_groups_count = bcm281xx_pinctrl_get_groups_count, + .get_group_name = bcm281xx_pinctrl_get_group_name, + .get_group_pins = bcm281xx_pinctrl_get_group_pins, + .pin_dbg_show = bcm281xx_pinctrl_pin_dbg_show, + .dt_node_to_map = pinconf_generic_dt_node_to_map_pin, + .dt_free_map = pinctrl_utils_dt_free_map, +}; + +static int bcm281xx_pinctrl_get_fcns_count(struct pinctrl_dev *pctldev) +{ + struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); + + return pdata->nfunctions; +} + +static const char *bcm281xx_pinctrl_get_fcn_name(struct pinctrl_dev *pctldev, + unsigned function) +{ + struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); + + return pdata->functions[function].name; +} + +static int bcm281xx_pinctrl_get_fcn_groups(struct pinctrl_dev *pctldev, + unsigned function, + const char * const **groups, + unsigned * const num_groups) +{ + struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); + + *groups = pdata->functions[function].groups; + *num_groups = pdata->functions[function].ngroups; + + return 0; +} + +static int bcm281xx_pinmux_enable(struct pinctrl_dev *pctldev, + unsigned function, + unsigned group) +{ + struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); + const struct bcm281xx_pin_function *f = &pdata->functions[function]; + u32 offset = 4 * pdata->pins[group].number; + int rc = 0; + + dev_dbg(pctldev->dev, + "%s(): Enable function %s (%d) of pin %s (%d) @offset 0x%x.\n", + __func__, f->name, function, pdata->pins[group].name, + pdata->pins[group].number, offset); + + rc = regmap_update_bits(pdata->regmap, offset, + BCM281XX_PIN_REG_F_SEL_MASK, + function << BCM281XX_PIN_REG_F_SEL_SHIFT); + if (rc) + dev_err(pctldev->dev, + "Error updating register for pin %s (%d).\n", + pdata->pins[group].name, pdata->pins[group].number); + + return rc; +} + +static struct pinmux_ops bcm281xx_pinctrl_pinmux_ops = { + .get_functions_count = bcm281xx_pinctrl_get_fcns_count, + .get_function_name = bcm281xx_pinctrl_get_fcn_name, + .get_function_groups = bcm281xx_pinctrl_get_fcn_groups, + .enable = bcm281xx_pinmux_enable, +}; + +static int bcm281xx_pinctrl_pin_config_get(struct pinctrl_dev *pctldev, + unsigned pin, + unsigned long *config) +{ + return -ENOTSUPP; +} + + +/* Goes through the configs and update register val/mask */ +static int bcm281xx_std_pin_update(struct pinctrl_dev *pctldev, + unsigned pin, + unsigned long *configs, + unsigned num_configs, + u32 *val, + u32 *mask) +{ + struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); + int i; + enum pin_config_param param; + u16 arg; + + for (i = 0; i < num_configs; i++) { + param = pinconf_to_config_param(configs[i]); + arg = pinconf_to_config_argument(configs[i]); + + switch (param) { + case PIN_CONFIG_INPUT_SCHMITT_ENABLE: + arg = (arg >= 1 ? 1 : 0); + bcm281xx_pin_update(val, mask, arg, + BCM281XX_PIN_SHIFT(STD, HYST), + BCM281XX_PIN_MASK(STD, HYST)); + break; + /* + * The pin bias can only be one of pull-up, pull-down, or + * disable. The user does not need to specify a value for the + * property, and the default value from pinconf-generic is + * ignored. + */ + case PIN_CONFIG_BIAS_DISABLE: + bcm281xx_pin_update(val, mask, 0, + BCM281XX_PIN_SHIFT(STD, PULL_UP), + BCM281XX_PIN_MASK(STD, PULL_UP)); + bcm281xx_pin_update(val, mask, 0, + BCM281XX_PIN_SHIFT(STD, PULL_DN), + BCM281XX_PIN_MASK(STD, PULL_DN)); + break; + + case PIN_CONFIG_BIAS_PULL_UP: + bcm281xx_pin_update(val, mask, 1, + BCM281XX_PIN_SHIFT(STD, PULL_UP), + BCM281XX_PIN_MASK(STD, PULL_UP)); + bcm281xx_pin_update(val, mask, 0, + BCM281XX_PIN_SHIFT(STD, PULL_DN), + BCM281XX_PIN_MASK(STD, PULL_DN)); + break; + + case PIN_CONFIG_BIAS_PULL_DOWN: + bcm281xx_pin_update(val, mask, 0, + BCM281XX_PIN_SHIFT(STD, PULL_UP), + BCM281XX_PIN_MASK(STD, PULL_UP)); + bcm281xx_pin_update(val, mask, 1, + BCM281XX_PIN_SHIFT(STD, PULL_DN), + BCM281XX_PIN_MASK(STD, PULL_DN)); + break; + + case PIN_CONFIG_SLEW_RATE: + arg = (arg >= 1 ? 1 : 0); + bcm281xx_pin_update(val, mask, arg, + BCM281XX_PIN_SHIFT(STD, SLEW), + BCM281XX_PIN_MASK(STD, SLEW)); + break; + + case PIN_CONFIG_INPUT_ENABLE: + /* inversed since register is for input _disable_ */ + arg = (arg >= 1 ? 0 : 1); + bcm281xx_pin_update(val, mask, arg, + BCM281XX_PIN_SHIFT(STD, INPUT_DIS), + BCM281XX_PIN_MASK(STD, INPUT_DIS)); + break; + + case PIN_CONFIG_DRIVE_STRENGTH: + /* Valid range is 2-16 mA, even numbers only */ + if ((arg < 2) || (arg > 16) || (arg % 2)) { + dev_err(pctldev->dev, + "Invalid Drive Strength value (%d) for " + "pin %s (%d). Valid values are " + "(2..16) mA, even numbers only.\n", + arg, pdata->pins[pin].name, pin); + return -EINVAL; + } + bcm281xx_pin_update(val, mask, (arg/2)-1, + BCM281XX_PIN_SHIFT(STD, DRV_STR), + BCM281XX_PIN_MASK(STD, DRV_STR)); + break; + + default: + dev_err(pctldev->dev, + "Unrecognized pin config %d for pin %s (%d).\n", + param, pdata->pins[pin].name, pin); + return -EINVAL; + + } /* switch config */ + } /* for each config */ + + return 0; +} + +/* + * The pull-up strength for an I2C pin is represented by bits 4-6 in the + * register with the following mapping: + * 0b000: No pull-up + * 0b001: 1200 Ohm + * 0b010: 1800 Ohm + * 0b011: 720 Ohm + * 0b100: 2700 Ohm + * 0b101: 831 Ohm + * 0b110: 1080 Ohm + * 0b111: 568 Ohm + * This array maps pull-up strength in Ohms to register values (1+index). + */ +static const u16 bcm281xx_pullup_map[] = { + 1200, 1800, 720, 2700, 831, 1080, 568 +}; + +/* Goes through the configs and update register val/mask */ +static int bcm281xx_i2c_pin_update(struct pinctrl_dev *pctldev, + unsigned pin, + unsigned long *configs, + unsigned num_configs, + u32 *val, + u32 *mask) +{ + struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); + int i, j; + enum pin_config_param param; + u16 arg; + + for (i = 0; i < num_configs; i++) { + param = pinconf_to_config_param(configs[i]); + arg = pinconf_to_config_argument(configs[i]); + + switch (param) { + case PIN_CONFIG_BIAS_PULL_UP: + for (j = 0; j < ARRAY_SIZE(bcm281xx_pullup_map); j++) + if (bcm281xx_pullup_map[j] == arg) + break; + + if (j == ARRAY_SIZE(bcm281xx_pullup_map)) { + dev_err(pctldev->dev, + "Invalid pull-up value (%d) for pin %s " + "(%d). Valid values are 568, 720, 831, " + "1080, 1200, 1800, 2700 Ohms.\n", + arg, pdata->pins[pin].name, pin); + return -EINVAL; + } + + bcm281xx_pin_update(val, mask, j+1, + BCM281XX_PIN_SHIFT(I2C, PULL_UP_STR), + BCM281XX_PIN_MASK(I2C, PULL_UP_STR)); + break; + + case PIN_CONFIG_BIAS_DISABLE: + bcm281xx_pin_update(val, mask, 0, + BCM281XX_PIN_SHIFT(I2C, PULL_UP_STR), + BCM281XX_PIN_MASK(I2C, PULL_UP_STR)); + break; + + case PIN_CONFIG_SLEW_RATE: + arg = (arg >= 1 ? 1 : 0); + bcm281xx_pin_update(val, mask, arg, + BCM281XX_PIN_SHIFT(I2C, SLEW), + BCM281XX_PIN_MASK(I2C, SLEW)); + break; + + case PIN_CONFIG_INPUT_ENABLE: + /* inversed since register is for input _disable_ */ + arg = (arg >= 1 ? 0 : 1); + bcm281xx_pin_update(val, mask, arg, + BCM281XX_PIN_SHIFT(I2C, INPUT_DIS), + BCM281XX_PIN_MASK(I2C, INPUT_DIS)); + break; + + default: + dev_err(pctldev->dev, + "Unrecognized pin config %d for pin %s (%d).\n", + param, pdata->pins[pin].name, pin); + return -EINVAL; + + } /* switch config */ + } /* for each config */ + + return 0; +} + +/* Goes through the configs and update register val/mask */ +static int bcm281xx_hdmi_pin_update(struct pinctrl_dev *pctldev, + unsigned pin, + unsigned long *configs, + unsigned num_configs, + u32 *val, + u32 *mask) +{ + struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); + int i; + enum pin_config_param param; + u16 arg; + + for (i = 0; i < num_configs; i++) { + param = pinconf_to_config_param(configs[i]); + arg = pinconf_to_config_argument(configs[i]); + + switch (param) { + case PIN_CONFIG_SLEW_RATE: + arg = (arg >= 1 ? 1 : 0); + bcm281xx_pin_update(val, mask, arg, + BCM281XX_PIN_SHIFT(HDMI, MODE), + BCM281XX_PIN_MASK(HDMI, MODE)); + break; + + case PIN_CONFIG_INPUT_ENABLE: + /* inversed since register is for input _disable_ */ + arg = (arg >= 1 ? 0 : 1); + bcm281xx_pin_update(val, mask, arg, + BCM281XX_PIN_SHIFT(HDMI, INPUT_DIS), + BCM281XX_PIN_MASK(HDMI, INPUT_DIS)); + break; + + default: + dev_err(pctldev->dev, + "Unrecognized pin config %d for pin %s (%d).\n", + param, pdata->pins[pin].name, pin); + return -EINVAL; + + } /* switch config */ + } /* for each config */ + + return 0; +} + +static int bcm281xx_pinctrl_pin_config_set(struct pinctrl_dev *pctldev, + unsigned pin, + unsigned long *configs, + unsigned num_configs) +{ + struct bcm281xx_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); + enum bcm281xx_pin_type pin_type; + u32 offset = 4 * pin; + u32 cfg_val, cfg_mask; + int rc; + + cfg_val = 0; + cfg_mask = 0; + pin_type = pin_type_get(pctldev, pin); + + /* Different pins have different configuration options */ + switch (pin_type) { + case BCM281XX_PIN_TYPE_STD: + rc = bcm281xx_std_pin_update(pctldev, pin, configs, + num_configs, &cfg_val, &cfg_mask); + break; + + case BCM281XX_PIN_TYPE_I2C: + rc = bcm281xx_i2c_pin_update(pctldev, pin, configs, + num_configs, &cfg_val, &cfg_mask); + break; + + case BCM281XX_PIN_TYPE_HDMI: + rc = bcm281xx_hdmi_pin_update(pctldev, pin, configs, + num_configs, &cfg_val, &cfg_mask); + break; + + default: + dev_err(pctldev->dev, "Unknown pin type for pin %s (%d).\n", + pdata->pins[pin].name, pin); + return -EINVAL; + + } /* switch pin type */ + + if (rc) + return rc; + + dev_dbg(pctldev->dev, + "%s(): Set pin %s (%d) with config 0x%x, mask 0x%x\n", + __func__, pdata->pins[pin].name, pin, cfg_val, cfg_mask); + + rc = regmap_update_bits(pdata->regmap, offset, cfg_mask, cfg_val); + if (rc) { + dev_err(pctldev->dev, + "Error updating register for pin %s (%d).\n", + pdata->pins[pin].name, pin); + return rc; + } + + return 0; +} + +static struct pinconf_ops bcm281xx_pinctrl_pinconf_ops = { + .pin_config_get = bcm281xx_pinctrl_pin_config_get, + .pin_config_set = bcm281xx_pinctrl_pin_config_set, +}; + +static struct pinctrl_desc bcm281xx_pinctrl_desc = { + /* name, pins, npins members initialized in probe function */ + .pctlops = &bcm281xx_pinctrl_ops, + .pmxops = &bcm281xx_pinctrl_pinmux_ops, + .confops = &bcm281xx_pinctrl_pinconf_ops, + .owner = THIS_MODULE, +}; + +int __init bcm281xx_pinctrl_probe(struct platform_device *pdev) +{ + struct bcm281xx_pinctrl_data *pdata = &bcm281xx_pinctrl; + struct resource *res; + struct pinctrl_dev *pctl; + + /* So far We can assume there is only 1 bank of registers */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "Missing MEM resource\n"); + return -ENODEV; + } + + pdata->reg_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(pdata->reg_base)) { + dev_err(&pdev->dev, "Failed to ioremap MEM resource\n"); + return -ENODEV; + } + + /* Initialize the dynamic part of pinctrl_desc */ + pdata->regmap = devm_regmap_init_mmio(&pdev->dev, pdata->reg_base, + &bcm281xx_pinctrl_regmap_config); + if (IS_ERR(pdata->regmap)) { + dev_err(&pdev->dev, "Regmap MMIO init failed.\n"); + return -ENODEV; + } + + bcm281xx_pinctrl_desc.name = dev_name(&pdev->dev); + bcm281xx_pinctrl_desc.pins = bcm281xx_pinctrl.pins; + bcm281xx_pinctrl_desc.npins = bcm281xx_pinctrl.npins; + + pctl = pinctrl_register(&bcm281xx_pinctrl_desc, + &pdev->dev, + pdata); + if (!pctl) { + dev_err(&pdev->dev, "Failed to register pinctrl\n"); + return -ENODEV; + } + + platform_set_drvdata(pdev, pdata); + + return 0; +} + +static struct of_device_id bcm281xx_pinctrl_of_match[] = { + { .compatible = "brcm,bcm11351-pinctrl", }, + { }, +}; + +static struct platform_driver bcm281xx_pinctrl_driver = { + .driver = { + .name = "bcm281xx-pinctrl", + .owner = THIS_MODULE, + .of_match_table = bcm281xx_pinctrl_of_match, + }, +}; + +module_platform_driver_probe(bcm281xx_pinctrl_driver, bcm281xx_pinctrl_probe); + +MODULE_AUTHOR("Broadcom Corporation "); +MODULE_AUTHOR("Sherman Yin "); +MODULE_DESCRIPTION("Broadcom BCM281xx pinctrl driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/pinctrl/pinctrl-capri.c b/drivers/pinctrl/pinctrl-capri.c deleted file mode 100644 index eb250021214..00000000000 --- a/drivers/pinctrl/pinctrl-capri.c +++ /dev/null @@ -1,1454 +0,0 @@ -/* - * Copyright (C) 2013 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "core.h" -#include "pinctrl-utils.h" - -/* Capri Pin Control Registers Definitions */ - -/* Function Select bits are the same for all pin control registers */ -#define CAPRI_PIN_REG_F_SEL_MASK 0x0700 -#define CAPRI_PIN_REG_F_SEL_SHIFT 8 - -/* Standard pin register */ -#define CAPRI_STD_PIN_REG_DRV_STR_MASK 0x0007 -#define CAPRI_STD_PIN_REG_DRV_STR_SHIFT 0 -#define CAPRI_STD_PIN_REG_INPUT_DIS_MASK 0x0008 -#define CAPRI_STD_PIN_REG_INPUT_DIS_SHIFT 3 -#define CAPRI_STD_PIN_REG_SLEW_MASK 0x0010 -#define CAPRI_STD_PIN_REG_SLEW_SHIFT 4 -#define CAPRI_STD_PIN_REG_PULL_UP_MASK 0x0020 -#define CAPRI_STD_PIN_REG_PULL_UP_SHIFT 5 -#define CAPRI_STD_PIN_REG_PULL_DN_MASK 0x0040 -#define CAPRI_STD_PIN_REG_PULL_DN_SHIFT 6 -#define CAPRI_STD_PIN_REG_HYST_MASK 0x0080 -#define CAPRI_STD_PIN_REG_HYST_SHIFT 7 - -/* I2C pin register */ -#define CAPRI_I2C_PIN_REG_INPUT_DIS_MASK 0x0004 -#define CAPRI_I2C_PIN_REG_INPUT_DIS_SHIFT 2 -#define CAPRI_I2C_PIN_REG_SLEW_MASK 0x0008 -#define CAPRI_I2C_PIN_REG_SLEW_SHIFT 3 -#define CAPRI_I2C_PIN_REG_PULL_UP_STR_MASK 0x0070 -#define CAPRI_I2C_PIN_REG_PULL_UP_STR_SHIFT 4 - -/* HDMI pin register */ -#define CAPRI_HDMI_PIN_REG_INPUT_DIS_MASK 0x0008 -#define CAPRI_HDMI_PIN_REG_INPUT_DIS_SHIFT 3 -#define CAPRI_HDMI_PIN_REG_MODE_MASK 0x0010 -#define CAPRI_HDMI_PIN_REG_MODE_SHIFT 4 - -/** - * capri_pin_type - types of pin register - */ -enum capri_pin_type { - CAPRI_PIN_TYPE_UNKNOWN = 0, - CAPRI_PIN_TYPE_STD, - CAPRI_PIN_TYPE_I2C, - CAPRI_PIN_TYPE_HDMI, -}; - -static enum capri_pin_type std_pin = CAPRI_PIN_TYPE_STD; -static enum capri_pin_type i2c_pin = CAPRI_PIN_TYPE_I2C; -static enum capri_pin_type hdmi_pin = CAPRI_PIN_TYPE_HDMI; - -/** - * capri_pin_function- define pin function - */ -struct capri_pin_function { - const char *name; - const char * const *groups; - const unsigned ngroups; -}; - -/** - * capri_pinctrl_data - Broadcom-specific pinctrl data - * @reg_base - base of pinctrl registers - */ -struct capri_pinctrl_data { - void __iomem *reg_base; - - /* List of all pins */ - const struct pinctrl_pin_desc *pins; - const unsigned npins; - - const struct capri_pin_function *functions; - const unsigned nfunctions; - - struct regmap *regmap; -}; - -/* - * Pin number definition. The order here must be the same as defined in the - * PADCTRLREG block in the RDB. - */ -#define CAPRI_PIN_ADCSYNC 0 -#define CAPRI_PIN_BAT_RM 1 -#define CAPRI_PIN_BSC1_SCL 2 -#define CAPRI_PIN_BSC1_SDA 3 -#define CAPRI_PIN_BSC2_SCL 4 -#define CAPRI_PIN_BSC2_SDA 5 -#define CAPRI_PIN_CLASSGPWR 6 -#define CAPRI_PIN_CLK_CX8 7 -#define CAPRI_PIN_CLKOUT_0 8 -#define CAPRI_PIN_CLKOUT_1 9 -#define CAPRI_PIN_CLKOUT_2 10 -#define CAPRI_PIN_CLKOUT_3 11 -#define CAPRI_PIN_CLKREQ_IN_0 12 -#define CAPRI_PIN_CLKREQ_IN_1 13 -#define CAPRI_PIN_CWS_SYS_REQ1 14 -#define CAPRI_PIN_CWS_SYS_REQ2 15 -#define CAPRI_PIN_CWS_SYS_REQ3 16 -#define CAPRI_PIN_DIGMIC1_CLK 17 -#define CAPRI_PIN_DIGMIC1_DQ 18 -#define CAPRI_PIN_DIGMIC2_CLK 19 -#define CAPRI_PIN_DIGMIC2_DQ 20 -#define CAPRI_PIN_GPEN13 21 -#define CAPRI_PIN_GPEN14 22 -#define CAPRI_PIN_GPEN15 23 -#define CAPRI_PIN_GPIO00 24 -#define CAPRI_PIN_GPIO01 25 -#define CAPRI_PIN_GPIO02 26 -#define CAPRI_PIN_GPIO03 27 -#define CAPRI_PIN_GPIO04 28 -#define CAPRI_PIN_GPIO05 29 -#define CAPRI_PIN_GPIO06 30 -#define CAPRI_PIN_GPIO07 31 -#define CAPRI_PIN_GPIO08 32 -#define CAPRI_PIN_GPIO09 33 -#define CAPRI_PIN_GPIO10 34 -#define CAPRI_PIN_GPIO11 35 -#define CAPRI_PIN_GPIO12 36 -#define CAPRI_PIN_GPIO13 37 -#define CAPRI_PIN_GPIO14 38 -#define CAPRI_PIN_GPS_PABLANK 39 -#define CAPRI_PIN_GPS_TMARK 40 -#define CAPRI_PIN_HDMI_SCL 41 -#define CAPRI_PIN_HDMI_SDA 42 -#define CAPRI_PIN_IC_DM 43 -#define CAPRI_PIN_IC_DP 44 -#define CAPRI_PIN_KP_COL_IP_0 45 -#define CAPRI_PIN_KP_COL_IP_1 46 -#define CAPRI_PIN_KP_COL_IP_2 47 -#define CAPRI_PIN_KP_COL_IP_3 48 -#define CAPRI_PIN_KP_ROW_OP_0 49 -#define CAPRI_PIN_KP_ROW_OP_1 50 -#define CAPRI_PIN_KP_ROW_OP_2 51 -#define CAPRI_PIN_KP_ROW_OP_3 52 -#define CAPRI_PIN_LCD_B_0 53 -#define CAPRI_PIN_LCD_B_1 54 -#define CAPRI_PIN_LCD_B_2 55 -#define CAPRI_PIN_LCD_B_3 56 -#define CAPRI_PIN_LCD_B_4 57 -#define CAPRI_PIN_LCD_B_5 58 -#define CAPRI_PIN_LCD_B_6 59 -#define CAPRI_PIN_LCD_B_7 60 -#define CAPRI_PIN_LCD_G_0 61 -#define CAPRI_PIN_LCD_G_1 62 -#define CAPRI_PIN_LCD_G_2 63 -#define CAPRI_PIN_LCD_G_3 64 -#define CAPRI_PIN_LCD_G_4 65 -#define CAPRI_PIN_LCD_G_5 66 -#define CAPRI_PIN_LCD_G_6 67 -#define CAPRI_PIN_LCD_G_7 68 -#define CAPRI_PIN_LCD_HSYNC 69 -#define CAPRI_PIN_LCD_OE 70 -#define CAPRI_PIN_LCD_PCLK 71 -#define CAPRI_PIN_LCD_R_0 72 -#define CAPRI_PIN_LCD_R_1 73 -#define CAPRI_PIN_LCD_R_2 74 -#define CAPRI_PIN_LCD_R_3 75 -#define CAPRI_PIN_LCD_R_4 76 -#define CAPRI_PIN_LCD_R_5 77 -#define CAPRI_PIN_LCD_R_6 78 -#define CAPRI_PIN_LCD_R_7 79 -#define CAPRI_PIN_LCD_VSYNC 80 -#define CAPRI_PIN_MDMGPIO0 81 -#define CAPRI_PIN_MDMGPIO1 82 -#define CAPRI_PIN_MDMGPIO2 83 -#define CAPRI_PIN_MDMGPIO3 84 -#define CAPRI_PIN_MDMGPIO4 85 -#define CAPRI_PIN_MDMGPIO5 86 -#define CAPRI_PIN_MDMGPIO6 87 -#define CAPRI_PIN_MDMGPIO7 88 -#define CAPRI_PIN_MDMGPIO8 89 -#define CAPRI_PIN_MPHI_DATA_0 90 -#define CAPRI_PIN_MPHI_DATA_1 91 -#define CAPRI_PIN_MPHI_DATA_2 92 -#define CAPRI_PIN_MPHI_DATA_3 93 -#define CAPRI_PIN_MPHI_DATA_4 94 -#define CAPRI_PIN_MPHI_DATA_5 95 -#define CAPRI_PIN_MPHI_DATA_6 96 -#define CAPRI_PIN_MPHI_DATA_7 97 -#define CAPRI_PIN_MPHI_DATA_8 98 -#define CAPRI_PIN_MPHI_DATA_9 99 -#define CAPRI_PIN_MPHI_DATA_10 100 -#define CAPRI_PIN_MPHI_DATA_11 101 -#define CAPRI_PIN_MPHI_DATA_12 102 -#define CAPRI_PIN_MPHI_DATA_13 103 -#define CAPRI_PIN_MPHI_DATA_14 104 -#define CAPRI_PIN_MPHI_DATA_15 105 -#define CAPRI_PIN_MPHI_HA0 106 -#define CAPRI_PIN_MPHI_HAT0 107 -#define CAPRI_PIN_MPHI_HAT1 108 -#define CAPRI_PIN_MPHI_HCE0_N 109 -#define CAPRI_PIN_MPHI_HCE1_N 110 -#define CAPRI_PIN_MPHI_HRD_N 111 -#define CAPRI_PIN_MPHI_HWR_N 112 -#define CAPRI_PIN_MPHI_RUN0 113 -#define CAPRI_PIN_MPHI_RUN1 114 -#define CAPRI_PIN_MTX_SCAN_CLK 115 -#define CAPRI_PIN_MTX_SCAN_DATA 116 -#define CAPRI_PIN_NAND_AD_0 117 -#define CAPRI_PIN_NAND_AD_1 118 -#define CAPRI_PIN_NAND_AD_2 119 -#define CAPRI_PIN_NAND_AD_3 120 -#define CAPRI_PIN_NAND_AD_4 121 -#define CAPRI_PIN_NAND_AD_5 122 -#define CAPRI_PIN_NAND_AD_6 123 -#define CAPRI_PIN_NAND_AD_7 124 -#define CAPRI_PIN_NAND_ALE 125 -#define CAPRI_PIN_NAND_CEN_0 126 -#define CAPRI_PIN_NAND_CEN_1 127 -#define CAPRI_PIN_NAND_CLE 128 -#define CAPRI_PIN_NAND_OEN 129 -#define CAPRI_PIN_NAND_RDY_0 130 -#define CAPRI_PIN_NAND_RDY_1 131 -#define CAPRI_PIN_NAND_WEN 132 -#define CAPRI_PIN_NAND_WP 133 -#define CAPRI_PIN_PC1 134 -#define CAPRI_PIN_PC2 135 -#define CAPRI_PIN_PMU_INT 136 -#define CAPRI_PIN_PMU_SCL 137 -#define CAPRI_PIN_PMU_SDA 138 -#define CAPRI_PIN_RFST2G_MTSLOTEN3G 139 -#define CAPRI_PIN_RGMII_0_RX_CTL 140 -#define CAPRI_PIN_RGMII_0_RXC 141 -#define CAPRI_PIN_RGMII_0_RXD_0 142 -#define CAPRI_PIN_RGMII_0_RXD_1 143 -#define CAPRI_PIN_RGMII_0_RXD_2 144 -#define CAPRI_PIN_RGMII_0_RXD_3 145 -#define CAPRI_PIN_RGMII_0_TX_CTL 146 -#define CAPRI_PIN_RGMII_0_TXC 147 -#define CAPRI_PIN_RGMII_0_TXD_0 148 -#define CAPRI_PIN_RGMII_0_TXD_1 149 -#define CAPRI_PIN_RGMII_0_TXD_2 150 -#define CAPRI_PIN_RGMII_0_TXD_3 151 -#define CAPRI_PIN_RGMII_1_RX_CTL 152 -#define CAPRI_PIN_RGMII_1_RXC 153 -#define CAPRI_PIN_RGMII_1_RXD_0 154 -#define CAPRI_PIN_RGMII_1_RXD_1 155 -#define CAPRI_PIN_RGMII_1_RXD_2 156 -#define CAPRI_PIN_RGMII_1_RXD_3 157 -#define CAPRI_PIN_RGMII_1_TX_CTL 158 -#define CAPRI_PIN_RGMII_1_TXC 159 -#define CAPRI_PIN_RGMII_1_TXD_0 160 -#define CAPRI_PIN_RGMII_1_TXD_1 161 -#define CAPRI_PIN_RGMII_1_TXD_2 162 -#define CAPRI_PIN_RGMII_1_TXD_3 163 -#define CAPRI_PIN_RGMII_GPIO_0 164 -#define CAPRI_PIN_RGMII_GPIO_1 165 -#define CAPRI_PIN_RGMII_GPIO_2 166 -#define CAPRI_PIN_RGMII_GPIO_3 167 -#define CAPRI_PIN_RTXDATA2G_TXDATA3G1 168 -#define CAPRI_PIN_RTXEN2G_TXDATA3G2 169 -#define CAPRI_PIN_RXDATA3G0 170 -#define CAPRI_PIN_RXDATA3G1 171 -#define CAPRI_PIN_RXDATA3G2 172 -#define CAPRI_PIN_SDIO1_CLK 173 -#define CAPRI_PIN_SDIO1_CMD 174 -#define CAPRI_PIN_SDIO1_DATA_0 175 -#define CAPRI_PIN_SDIO1_DATA_1 176 -#define CAPRI_PIN_SDIO1_DATA_2 177 -#define CAPRI_PIN_SDIO1_DATA_3 178 -#define CAPRI_PIN_SDIO4_CLK 179 -#define CAPRI_PIN_SDIO4_CMD 180 -#define CAPRI_PIN_SDIO4_DATA_0 181 -#define CAPRI_PIN_SDIO4_DATA_1 182 -#define CAPRI_PIN_SDIO4_DATA_2 183 -#define CAPRI_PIN_SDIO4_DATA_3 184 -#define CAPRI_PIN_SIM_CLK 185 -#define CAPRI_PIN_SIM_DATA 186 -#define CAPRI_PIN_SIM_DET 187 -#define CAPRI_PIN_SIM_RESETN 188 -#define CAPRI_PIN_SIM2_CLK 189 -#define CAPRI_PIN_SIM2_DATA 190 -#define CAPRI_PIN_SIM2_DET 191 -#define CAPRI_PIN_SIM2_RESETN 192 -#define CAPRI_PIN_SRI_C 193 -#define CAPRI_PIN_SRI_D 194 -#define CAPRI_PIN_SRI_E 195 -#define CAPRI_PIN_SSP_EXTCLK 196 -#define CAPRI_PIN_SSP0_CLK 197 -#define CAPRI_PIN_SSP0_FS 198 -#define CAPRI_PIN_SSP0_RXD 199 -#define CAPRI_PIN_SSP0_TXD 200 -#define CAPRI_PIN_SSP2_CLK 201 -#define CAPRI_PIN_SSP2_FS_0 202 -#define CAPRI_PIN_SSP2_FS_1 203 -#define CAPRI_PIN_SSP2_FS_2 204 -#define CAPRI_PIN_SSP2_FS_3 205 -#define CAPRI_PIN_SSP2_RXD_0 206 -#define CAPRI_PIN_SSP2_RXD_1 207 -#define CAPRI_PIN_SSP2_TXD_0 208 -#define CAPRI_PIN_SSP2_TXD_1 209 -#define CAPRI_PIN_SSP3_CLK 210 -#define CAPRI_PIN_SSP3_FS 211 -#define CAPRI_PIN_SSP3_RXD 212 -#define CAPRI_PIN_SSP3_TXD 213 -#define CAPRI_PIN_SSP4_CLK 214 -#define CAPRI_PIN_SSP4_FS 215 -#define CAPRI_PIN_SSP4_RXD 216 -#define CAPRI_PIN_SSP4_TXD 217 -#define CAPRI_PIN_SSP5_CLK 218 -#define CAPRI_PIN_SSP5_FS 219 -#define CAPRI_PIN_SSP5_RXD 220 -#define CAPRI_PIN_SSP5_TXD 221 -#define CAPRI_PIN_SSP6_CLK 222 -#define CAPRI_PIN_SSP6_FS 223 -#define CAPRI_PIN_SSP6_RXD 224 -#define CAPRI_PIN_SSP6_TXD 225 -#define CAPRI_PIN_STAT_1 226 -#define CAPRI_PIN_STAT_2 227 -#define CAPRI_PIN_SYSCLKEN 228 -#define CAPRI_PIN_TRACECLK 229 -#define CAPRI_PIN_TRACEDT00 230 -#define CAPRI_PIN_TRACEDT01 231 -#define CAPRI_PIN_TRACEDT02 232 -#define CAPRI_PIN_TRACEDT03 233 -#define CAPRI_PIN_TRACEDT04 234 -#define CAPRI_PIN_TRACEDT05 235 -#define CAPRI_PIN_TRACEDT06 236 -#define CAPRI_PIN_TRACEDT07 237 -#define CAPRI_PIN_TRACEDT08 238 -#define CAPRI_PIN_TRACEDT09 239 -#define CAPRI_PIN_TRACEDT10 240 -#define CAPRI_PIN_TRACEDT11 241 -#define CAPRI_PIN_TRACEDT12 242 -#define CAPRI_PIN_TRACEDT13 243 -#define CAPRI_PIN_TRACEDT14 244 -#define CAPRI_PIN_TRACEDT15 245 -#define CAPRI_PIN_TXDATA3G0 246 -#define CAPRI_PIN_TXPWRIND 247 -#define CAPRI_PIN_UARTB1_UCTS 248 -#define CAPRI_PIN_UARTB1_URTS 249 -#define CAPRI_PIN_UARTB1_URXD 250 -#define CAPRI_PIN_UARTB1_UTXD 251 -#define CAPRI_PIN_UARTB2_URXD 252 -#define CAPRI_PIN_UARTB2_UTXD 253 -#define CAPRI_PIN_UARTB3_UCTS 254 -#define CAPRI_PIN_UARTB3_URTS 255 -#define CAPRI_PIN_UARTB3_URXD 256 -#define CAPRI_PIN_UARTB3_UTXD 257 -#define CAPRI_PIN_UARTB4_UCTS 258 -#define CAPRI_PIN_UARTB4_URTS 259 -#define CAPRI_PIN_UARTB4_URXD 260 -#define CAPRI_PIN_UARTB4_UTXD 261 -#define CAPRI_PIN_VC_CAM1_SCL 262 -#define CAPRI_PIN_VC_CAM1_SDA 263 -#define CAPRI_PIN_VC_CAM2_SCL 264 -#define CAPRI_PIN_VC_CAM2_SDA 265 -#define CAPRI_PIN_VC_CAM3_SCL 266 -#define CAPRI_PIN_VC_CAM3_SDA 267 - -#define CAPRI_PIN_DESC(a, b, c) \ - { .number = a, .name = b, .drv_data = &c##_pin } - -/* - * Pin description definition. The order here must be the same as defined in - * the PADCTRLREG block in the RDB, since the pin number is used as an index - * into this array. - */ -static const struct pinctrl_pin_desc capri_pinctrl_pins[] = { - CAPRI_PIN_DESC(CAPRI_PIN_ADCSYNC, "adcsync", std), - CAPRI_PIN_DESC(CAPRI_PIN_BAT_RM, "bat_rm", std), - CAPRI_PIN_DESC(CAPRI_PIN_BSC1_SCL, "bsc1_scl", i2c), - CAPRI_PIN_DESC(CAPRI_PIN_BSC1_SDA, "bsc1_sda", i2c), - CAPRI_PIN_DESC(CAPRI_PIN_BSC2_SCL, "bsc2_scl", i2c), - CAPRI_PIN_DESC(CAPRI_PIN_BSC2_SDA, "bsc2_sda", i2c), - CAPRI_PIN_DESC(CAPRI_PIN_CLASSGPWR, "classgpwr", std), - CAPRI_PIN_DESC(CAPRI_PIN_CLK_CX8, "clk_cx8", std), - CAPRI_PIN_DESC(CAPRI_PIN_CLKOUT_0, "clkout_0", std), - CAPRI_PIN_DESC(CAPRI_PIN_CLKOUT_1, "clkout_1", std), - CAPRI_PIN_DESC(CAPRI_PIN_CLKOUT_2, "clkout_2", std), - CAPRI_PIN_DESC(CAPRI_PIN_CLKOUT_3, "clkout_3", std), - CAPRI_PIN_DESC(CAPRI_PIN_CLKREQ_IN_0, "clkreq_in_0", std), - CAPRI_PIN_DESC(CAPRI_PIN_CLKREQ_IN_1, "clkreq_in_1", std), - CAPRI_PIN_DESC(CAPRI_PIN_CWS_SYS_REQ1, "cws_sys_req1", std), - CAPRI_PIN_DESC(CAPRI_PIN_CWS_SYS_REQ2, "cws_sys_req2", std), - CAPRI_PIN_DESC(CAPRI_PIN_CWS_SYS_REQ3, "cws_sys_req3", std), - CAPRI_PIN_DESC(CAPRI_PIN_DIGMIC1_CLK, "digmic1_clk", std), - CAPRI_PIN_DESC(CAPRI_PIN_DIGMIC1_DQ, "digmic1_dq", std), - CAPRI_PIN_DESC(CAPRI_PIN_DIGMIC2_CLK, "digmic2_clk", std), - CAPRI_PIN_DESC(CAPRI_PIN_DIGMIC2_DQ, "digmic2_dq", std), - CAPRI_PIN_DESC(CAPRI_PIN_GPEN13, "gpen13", std), - CAPRI_PIN_DESC(CAPRI_PIN_GPEN14, "gpen14", std), - CAPRI_PIN_DESC(CAPRI_PIN_GPEN15, "gpen15", std), - CAPRI_PIN_DESC(CAPRI_PIN_GPIO00, "gpio00", std), - CAPRI_PIN_DESC(CAPRI_PIN_GPIO01, "gpio01", std), - CAPRI_PIN_DESC(CAPRI_PIN_GPIO02, "gpio02", std), - CAPRI_PIN_DESC(CAPRI_PIN_GPIO03, "gpio03", std), - CAPRI_PIN_DESC(CAPRI_PIN_GPIO04, "gpio04", std), - CAPRI_PIN_DESC(CAPRI_PIN_GPIO05, "gpio05", std), - CAPRI_PIN_DESC(CAPRI_PIN_GPIO06, "gpio06", std), - CAPRI_PIN_DESC(CAPRI_PIN_GPIO07, "gpio07", std), - CAPRI_PIN_DESC(CAPRI_PIN_GPIO08, "gpio08", std), - CAPRI_PIN_DESC(CAPRI_PIN_GPIO09, "gpio09", std), - CAPRI_PIN_DESC(CAPRI_PIN_GPIO10, "gpio10", std), - CAPRI_PIN_DESC(CAPRI_PIN_GPIO11, "gpio11", std), - CAPRI_PIN_DESC(CAPRI_PIN_GPIO12, "gpio12", std), - CAPRI_PIN_DESC(CAPRI_PIN_GPIO13, "gpio13", std), - CAPRI_PIN_DESC(CAPRI_PIN_GPIO14, "gpio14", std), - CAPRI_PIN_DESC(CAPRI_PIN_GPS_PABLANK, "gps_pablank", std), - CAPRI_PIN_DESC(CAPRI_PIN_GPS_TMARK, "gps_tmark", std), - CAPRI_PIN_DESC(CAPRI_PIN_HDMI_SCL, "hdmi_scl", hdmi), - CAPRI_PIN_DESC(CAPRI_PIN_HDMI_SDA, "hdmi_sda", hdmi), - CAPRI_PIN_DESC(CAPRI_PIN_IC_DM, "ic_dm", std), - CAPRI_PIN_DESC(CAPRI_PIN_IC_DP, "ic_dp", std), - CAPRI_PIN_DESC(CAPRI_PIN_KP_COL_IP_0, "kp_col_ip_0", std), - CAPRI_PIN_DESC(CAPRI_PIN_KP_COL_IP_1, "kp_col_ip_1", std), - CAPRI_PIN_DESC(CAPRI_PIN_KP_COL_IP_2, "kp_col_ip_2", std), - CAPRI_PIN_DESC(CAPRI_PIN_KP_COL_IP_3, "kp_col_ip_3", std), - CAPRI_PIN_DESC(CAPRI_PIN_KP_ROW_OP_0, "kp_row_op_0", std), - CAPRI_PIN_DESC(CAPRI_PIN_KP_ROW_OP_1, "kp_row_op_1", std), - CAPRI_PIN_DESC(CAPRI_PIN_KP_ROW_OP_2, "kp_row_op_2", std), - CAPRI_PIN_DESC(CAPRI_PIN_KP_ROW_OP_3, "kp_row_op_3", std), - CAPRI_PIN_DESC(CAPRI_PIN_LCD_B_0, "lcd_b_0", std), - CAPRI_PIN_DESC(CAPRI_PIN_LCD_B_1, "lcd_b_1", std), - CAPRI_PIN_DESC(CAPRI_PIN_LCD_B_2, "lcd_b_2", std), - CAPRI_PIN_DESC(CAPRI_PIN_LCD_B_3, "lcd_b_3", std), - CAPRI_PIN_DESC(CAPRI_PIN_LCD_B_4, "lcd_b_4", std), - CAPRI_PIN_DESC(CAPRI_PIN_LCD_B_5, "lcd_b_5", std), - CAPRI_PIN_DESC(CAPRI_PIN_LCD_B_6, "lcd_b_6", std), - CAPRI_PIN_DESC(CAPRI_PIN_LCD_B_7, "lcd_b_7", std), - CAPRI_PIN_DESC(CAPRI_PIN_LCD_G_0, "lcd_g_0", std), - CAPRI_PIN_DESC(CAPRI_PIN_LCD_G_1, "lcd_g_1", std), - CAPRI_PIN_DESC(CAPRI_PIN_LCD_G_2, "lcd_g_2", std), - CAPRI_PIN_DESC(CAPRI_PIN_LCD_G_3, "lcd_g_3", std), - CAPRI_PIN_DESC(CAPRI_PIN_LCD_G_4, "lcd_g_4", std), - CAPRI_PIN_DESC(CAPRI_PIN_LCD_G_5, "lcd_g_5", std), - CAPRI_PIN_DESC(CAPRI_PIN_LCD_G_6, "lcd_g_6", std), - CAPRI_PIN_DESC(CAPRI_PIN_LCD_G_7, "lcd_g_7", std), - CAPRI_PIN_DESC(CAPRI_PIN_LCD_HSYNC, "lcd_hsync", std), - CAPRI_PIN_DESC(CAPRI_PIN_LCD_OE, "lcd_oe", std), - CAPRI_PIN_DESC(CAPRI_PIN_LCD_PCLK, "lcd_pclk", std), - CAPRI_PIN_DESC(CAPRI_PIN_LCD_R_0, "lcd_r_0", std), - CAPRI_PIN_DESC(CAPRI_PIN_LCD_R_1, "lcd_r_1", std), - CAPRI_PIN_DESC(CAPRI_PIN_LCD_R_2, "lcd_r_2", std), - CAPRI_PIN_DESC(CAPRI_PIN_LCD_R_3, "lcd_r_3", std), - CAPRI_PIN_DESC(CAPRI_PIN_LCD_R_4, "lcd_r_4", std), - CAPRI_PIN_DESC(CAPRI_PIN_LCD_R_5, "lcd_r_5", std), - CAPRI_PIN_DESC(CAPRI_PIN_LCD_R_6, "lcd_r_6", std), - CAPRI_PIN_DESC(CAPRI_PIN_LCD_R_7, "lcd_r_7", std), - CAPRI_PIN_DESC(CAPRI_PIN_LCD_VSYNC, "lcd_vsync", std), - CAPRI_PIN_DESC(CAPRI_PIN_MDMGPIO0, "mdmgpio0", std), - CAPRI_PIN_DESC(CAPRI_PIN_MDMGPIO1, "mdmgpio1", std), - CAPRI_PIN_DESC(CAPRI_PIN_MDMGPIO2, "mdmgpio2", std), - CAPRI_PIN_DESC(CAPRI_PIN_MDMGPIO3, "mdmgpio3", std), - CAPRI_PIN_DESC(CAPRI_PIN_MDMGPIO4, "mdmgpio4", std), - CAPRI_PIN_DESC(CAPRI_PIN_MDMGPIO5, "mdmgpio5", std), - CAPRI_PIN_DESC(CAPRI_PIN_MDMGPIO6, "mdmgpio6", std), - CAPRI_PIN_DESC(CAPRI_PIN_MDMGPIO7, "mdmgpio7", std), - CAPRI_PIN_DESC(CAPRI_PIN_MDMGPIO8, "mdmgpio8", std), - CAPRI_PIN_DESC(CAPRI_PIN_MPHI_DATA_0, "mphi_data_0", std), - CAPRI_PIN_DESC(CAPRI_PIN_MPHI_DATA_1, "mphi_data_1", std), - CAPRI_PIN_DESC(CAPRI_PIN_MPHI_DATA_2, "mphi_data_2", std), - CAPRI_PIN_DESC(CAPRI_PIN_MPHI_DATA_3, "mphi_data_3", std), - CAPRI_PIN_DESC(CAPRI_PIN_MPHI_DATA_4, "mphi_data_4", std), - CAPRI_PIN_DESC(CAPRI_PIN_MPHI_DATA_5, "mphi_data_5", std), - CAPRI_PIN_DESC(CAPRI_PIN_MPHI_DATA_6, "mphi_data_6", std), - CAPRI_PIN_DESC(CAPRI_PIN_MPHI_DATA_7, "mphi_data_7", std), - CAPRI_PIN_DESC(CAPRI_PIN_MPHI_DATA_8, "mphi_data_8", std), - CAPRI_PIN_DESC(CAPRI_PIN_MPHI_DATA_9, "mphi_data_9", std), - CAPRI_PIN_DESC(CAPRI_PIN_MPHI_DATA_10, "mphi_data_10", std), - CAPRI_PIN_DESC(CAPRI_PIN_MPHI_DATA_11, "mphi_data_11", std), - CAPRI_PIN_DESC(CAPRI_PIN_MPHI_DATA_12, "mphi_data_12", std), - CAPRI_PIN_DESC(CAPRI_PIN_MPHI_DATA_13, "mphi_data_13", std), - CAPRI_PIN_DESC(CAPRI_PIN_MPHI_DATA_14, "mphi_data_14", std), - CAPRI_PIN_DESC(CAPRI_PIN_MPHI_DATA_15, "mphi_data_15", std), - CAPRI_PIN_DESC(CAPRI_PIN_MPHI_HA0, "mphi_ha0", std), - CAPRI_PIN_DESC(CAPRI_PIN_MPHI_HAT0, "mphi_hat0", std), - CAPRI_PIN_DESC(CAPRI_PIN_MPHI_HAT1, "mphi_hat1", std), - CAPRI_PIN_DESC(CAPRI_PIN_MPHI_HCE0_N, "mphi_hce0_n", std), - CAPRI_PIN_DESC(CAPRI_PIN_MPHI_HCE1_N, "mphi_hce1_n", std), - CAPRI_PIN_DESC(CAPRI_PIN_MPHI_HRD_N, "mphi_hrd_n", std), - CAPRI_PIN_DESC(CAPRI_PIN_MPHI_HWR_N, "mphi_hwr_n", std), - CAPRI_PIN_DESC(CAPRI_PIN_MPHI_RUN0, "mphi_run0", std), - CAPRI_PIN_DESC(CAPRI_PIN_MPHI_RUN1, "mphi_run1", std), - CAPRI_PIN_DESC(CAPRI_PIN_MTX_SCAN_CLK, "mtx_scan_clk", std), - CAPRI_PIN_DESC(CAPRI_PIN_MTX_SCAN_DATA, "mtx_scan_data", std), - CAPRI_PIN_DESC(CAPRI_PIN_NAND_AD_0, "nand_ad_0", std), - CAPRI_PIN_DESC(CAPRI_PIN_NAND_AD_1, "nand_ad_1", std), - CAPRI_PIN_DESC(CAPRI_PIN_NAND_AD_2, "nand_ad_2", std), - CAPRI_PIN_DESC(CAPRI_PIN_NAND_AD_3, "nand_ad_3", std), - CAPRI_PIN_DESC(CAPRI_PIN_NAND_AD_4, "nand_ad_4", std), - CAPRI_PIN_DESC(CAPRI_PIN_NAND_AD_5, "nand_ad_5", std), - CAPRI_PIN_DESC(CAPRI_PIN_NAND_AD_6, "nand_ad_6", std), - CAPRI_PIN_DESC(CAPRI_PIN_NAND_AD_7, "nand_ad_7", std), - CAPRI_PIN_DESC(CAPRI_PIN_NAND_ALE, "nand_ale", std), - CAPRI_PIN_DESC(CAPRI_PIN_NAND_CEN_0, "nand_cen_0", std), - CAPRI_PIN_DESC(CAPRI_PIN_NAND_CEN_1, "nand_cen_1", std), - CAPRI_PIN_DESC(CAPRI_PIN_NAND_CLE, "nand_cle", std), - CAPRI_PIN_DESC(CAPRI_PIN_NAND_OEN, "nand_oen", std), - CAPRI_PIN_DESC(CAPRI_PIN_NAND_RDY_0, "nand_rdy_0", std), - CAPRI_PIN_DESC(CAPRI_PIN_NAND_RDY_1, "nand_rdy_1", std), - CAPRI_PIN_DESC(CAPRI_PIN_NAND_WEN, "nand_wen", std), - CAPRI_PIN_DESC(CAPRI_PIN_NAND_WP, "nand_wp", std), - CAPRI_PIN_DESC(CAPRI_PIN_PC1, "pc1", std), - CAPRI_PIN_DESC(CAPRI_PIN_PC2, "pc2", std), - CAPRI_PIN_DESC(CAPRI_PIN_PMU_INT, "pmu_int", std), - CAPRI_PIN_DESC(CAPRI_PIN_PMU_SCL, "pmu_scl", i2c), - CAPRI_PIN_DESC(CAPRI_PIN_PMU_SDA, "pmu_sda", i2c), - CAPRI_PIN_DESC(CAPRI_PIN_RFST2G_MTSLOTEN3G, "rfst2g_mtsloten3g", std), - CAPRI_PIN_DESC(CAPRI_PIN_RGMII_0_RX_CTL, "rgmii_0_rx_ctl", std), - CAPRI_PIN_DESC(CAPRI_PIN_RGMII_0_RXC, "rgmii_0_rxc", std), - CAPRI_PIN_DESC(CAPRI_PIN_RGMII_0_RXD_0, "rgmii_0_rxd_0", std), - CAPRI_PIN_DESC(CAPRI_PIN_RGMII_0_RXD_1, "rgmii_0_rxd_1", std), - CAPRI_PIN_DESC(CAPRI_PIN_RGMII_0_RXD_2, "rgmii_0_rxd_2", std), - CAPRI_PIN_DESC(CAPRI_PIN_RGMII_0_RXD_3, "rgmii_0_rxd_3", std), - CAPRI_PIN_DESC(CAPRI_PIN_RGMII_0_TX_CTL, "rgmii_0_tx_ctl", std), - CAPRI_PIN_DESC(CAPRI_PIN_RGMII_0_TXC, "rgmii_0_txc", std), - CAPRI_PIN_DESC(CAPRI_PIN_RGMII_0_TXD_0, "rgmii_0_txd_0", std), - CAPRI_PIN_DESC(CAPRI_PIN_RGMII_0_TXD_1, "rgmii_0_txd_1", std), - CAPRI_PIN_DESC(CAPRI_PIN_RGMII_0_TXD_2, "rgmii_0_txd_2", std), - CAPRI_PIN_DESC(CAPRI_PIN_RGMII_0_TXD_3, "rgmii_0_txd_3", std), - CAPRI_PIN_DESC(CAPRI_PIN_RGMII_1_RX_CTL, "rgmii_1_rx_ctl", std), - CAPRI_PIN_DESC(CAPRI_PIN_RGMII_1_RXC, "rgmii_1_rxc", std), - CAPRI_PIN_DESC(CAPRI_PIN_RGMII_1_RXD_0, "rgmii_1_rxd_0", std), - CAPRI_PIN_DESC(CAPRI_PIN_RGMII_1_RXD_1, "rgmii_1_rxd_1", std), - CAPRI_PIN_DESC(CAPRI_PIN_RGMII_1_RXD_2, "rgmii_1_rxd_2", std), - CAPRI_PIN_DESC(CAPRI_PIN_RGMII_1_RXD_3, "rgmii_1_rxd_3", std), - CAPRI_PIN_DESC(CAPRI_PIN_RGMII_1_TX_CTL, "rgmii_1_tx_ctl", std), - CAPRI_PIN_DESC(CAPRI_PIN_RGMII_1_TXC, "rgmii_1_txc", std), - CAPRI_PIN_DESC(CAPRI_PIN_RGMII_1_TXD_0, "rgmii_1_txd_0", std), - CAPRI_PIN_DESC(CAPRI_PIN_RGMII_1_TXD_1, "rgmii_1_txd_1", std), - CAPRI_PIN_DESC(CAPRI_PIN_RGMII_1_TXD_2, "rgmii_1_txd_2", std), - CAPRI_PIN_DESC(CAPRI_PIN_RGMII_1_TXD_3, "rgmii_1_txd_3", std), - CAPRI_PIN_DESC(CAPRI_PIN_RGMII_GPIO_0, "rgmii_gpio_0", std), - CAPRI_PIN_DESC(CAPRI_PIN_RGMII_GPIO_1, "rgmii_gpio_1", std), - CAPRI_PIN_DESC(CAPRI_PIN_RGMII_GPIO_2, "rgmii_gpio_2", std), - CAPRI_PIN_DESC(CAPRI_PIN_RGMII_GPIO_3, "rgmii_gpio_3", std), - CAPRI_PIN_DESC(CAPRI_PIN_RTXDATA2G_TXDATA3G1, "rtxdata2g_txdata3g1", - std), - CAPRI_PIN_DESC(CAPRI_PIN_RTXEN2G_TXDATA3G2, "rtxen2g_txdata3g2", std), - CAPRI_PIN_DESC(CAPRI_PIN_RXDATA3G0, "rxdata3g0", std), - CAPRI_PIN_DESC(CAPRI_PIN_RXDATA3G1, "rxdata3g1", std), - CAPRI_PIN_DESC(CAPRI_PIN_RXDATA3G2, "rxdata3g2", std), - CAPRI_PIN_DESC(CAPRI_PIN_SDIO1_CLK, "sdio1_clk", std), - CAPRI_PIN_DESC(CAPRI_PIN_SDIO1_CMD, "sdio1_cmd", std), - CAPRI_PIN_DESC(CAPRI_PIN_SDIO1_DATA_0, "sdio1_data_0", std), - CAPRI_PIN_DESC(CAPRI_PIN_SDIO1_DATA_1, "sdio1_data_1", std), - CAPRI_PIN_DESC(CAPRI_PIN_SDIO1_DATA_2, "sdio1_data_2", std), - CAPRI_PIN_DESC(CAPRI_PIN_SDIO1_DATA_3, "sdio1_data_3", std), - CAPRI_PIN_DESC(CAPRI_PIN_SDIO4_CLK, "sdio4_clk", std), - CAPRI_PIN_DESC(CAPRI_PIN_SDIO4_CMD, "sdio4_cmd", std), - CAPRI_PIN_DESC(CAPRI_PIN_SDIO4_DATA_0, "sdio4_data_0", std), - CAPRI_PIN_DESC(CAPRI_PIN_SDIO4_DATA_1, "sdio4_data_1", std), - CAPRI_PIN_DESC(CAPRI_PIN_SDIO4_DATA_2, "sdio4_data_2", std), - CAPRI_PIN_DESC(CAPRI_PIN_SDIO4_DATA_3, "sdio4_data_3", std), - CAPRI_PIN_DESC(CAPRI_PIN_SIM_CLK, "sim_clk", std), - CAPRI_PIN_DESC(CAPRI_PIN_SIM_DATA, "sim_data", std), - CAPRI_PIN_DESC(CAPRI_PIN_SIM_DET, "sim_det", std), - CAPRI_PIN_DESC(CAPRI_PIN_SIM_RESETN, "sim_resetn", std), - CAPRI_PIN_DESC(CAPRI_PIN_SIM2_CLK, "sim2_clk", std), - CAPRI_PIN_DESC(CAPRI_PIN_SIM2_DATA, "sim2_data", std), - CAPRI_PIN_DESC(CAPRI_PIN_SIM2_DET, "sim2_det", std), - CAPRI_PIN_DESC(CAPRI_PIN_SIM2_RESETN, "sim2_resetn", std), - CAPRI_PIN_DESC(CAPRI_PIN_SRI_C, "sri_c", std), - CAPRI_PIN_DESC(CAPRI_PIN_SRI_D, "sri_d", std), - CAPRI_PIN_DESC(CAPRI_PIN_SRI_E, "sri_e", std), - CAPRI_PIN_DESC(CAPRI_PIN_SSP_EXTCLK, "ssp_extclk", std), - CAPRI_PIN_DESC(CAPRI_PIN_SSP0_CLK, "ssp0_clk", std), - CAPRI_PIN_DESC(CAPRI_PIN_SSP0_FS, "ssp0_fs", std), - CAPRI_PIN_DESC(CAPRI_PIN_SSP0_RXD, "ssp0_rxd", std), - CAPRI_PIN_DESC(CAPRI_PIN_SSP0_TXD, "ssp0_txd", std), - CAPRI_PIN_DESC(CAPRI_PIN_SSP2_CLK, "ssp2_clk", std), - CAPRI_PIN_DESC(CAPRI_PIN_SSP2_FS_0, "ssp2_fs_0", std), - CAPRI_PIN_DESC(CAPRI_PIN_SSP2_FS_1, "ssp2_fs_1", std), - CAPRI_PIN_DESC(CAPRI_PIN_SSP2_FS_2, "ssp2_fs_2", std), - CAPRI_PIN_DESC(CAPRI_PIN_SSP2_FS_3, "ssp2_fs_3", std), - CAPRI_PIN_DESC(CAPRI_PIN_SSP2_RXD_0, "ssp2_rxd_0", std), - CAPRI_PIN_DESC(CAPRI_PIN_SSP2_RXD_1, "ssp2_rxd_1", std), - CAPRI_PIN_DESC(CAPRI_PIN_SSP2_TXD_0, "ssp2_txd_0", std), - CAPRI_PIN_DESC(CAPRI_PIN_SSP2_TXD_1, "ssp2_txd_1", std), - CAPRI_PIN_DESC(CAPRI_PIN_SSP3_CLK, "ssp3_clk", std), - CAPRI_PIN_DESC(CAPRI_PIN_SSP3_FS, "ssp3_fs", std), - CAPRI_PIN_DESC(CAPRI_PIN_SSP3_RXD, "ssp3_rxd", std), - CAPRI_PIN_DESC(CAPRI_PIN_SSP3_TXD, "ssp3_txd", std), - CAPRI_PIN_DESC(CAPRI_PIN_SSP4_CLK, "ssp4_clk", std), - CAPRI_PIN_DESC(CAPRI_PIN_SSP4_FS, "ssp4_fs", std), - CAPRI_PIN_DESC(CAPRI_PIN_SSP4_RXD, "ssp4_rxd", std), - CAPRI_PIN_DESC(CAPRI_PIN_SSP4_TXD, "ssp4_txd", std), - CAPRI_PIN_DESC(CAPRI_PIN_SSP5_CLK, "ssp5_clk", std), - CAPRI_PIN_DESC(CAPRI_PIN_SSP5_FS, "ssp5_fs", std), - CAPRI_PIN_DESC(CAPRI_PIN_SSP5_RXD, "ssp5_rxd", std), - CAPRI_PIN_DESC(CAPRI_PIN_SSP5_TXD, "ssp5_txd", std), - CAPRI_PIN_DESC(CAPRI_PIN_SSP6_CLK, "ssp6_clk", std), - CAPRI_PIN_DESC(CAPRI_PIN_SSP6_FS, "ssp6_fs", std), - CAPRI_PIN_DESC(CAPRI_PIN_SSP6_RXD, "ssp6_rxd", std), - CAPRI_PIN_DESC(CAPRI_PIN_SSP6_TXD, "ssp6_txd", std), - CAPRI_PIN_DESC(CAPRI_PIN_STAT_1, "stat_1", std), - CAPRI_PIN_DESC(CAPRI_PIN_STAT_2, "stat_2", std), - CAPRI_PIN_DESC(CAPRI_PIN_SYSCLKEN, "sysclken", std), - CAPRI_PIN_DESC(CAPRI_PIN_TRACECLK, "traceclk", std), - CAPRI_PIN_DESC(CAPRI_PIN_TRACEDT00, "tracedt00", std), - CAPRI_PIN_DESC(CAPRI_PIN_TRACEDT01, "tracedt01", std), - CAPRI_PIN_DESC(CAPRI_PIN_TRACEDT02, "tracedt02", std), - CAPRI_PIN_DESC(CAPRI_PIN_TRACEDT03, "tracedt03", std), - CAPRI_PIN_DESC(CAPRI_PIN_TRACEDT04, "tracedt04", std), - CAPRI_PIN_DESC(CAPRI_PIN_TRACEDT05, "tracedt05", std), - CAPRI_PIN_DESC(CAPRI_PIN_TRACEDT06, "tracedt06", std), - CAPRI_PIN_DESC(CAPRI_PIN_TRACEDT07, "tracedt07", std), - CAPRI_PIN_DESC(CAPRI_PIN_TRACEDT08, "tracedt08", std), - CAPRI_PIN_DESC(CAPRI_PIN_TRACEDT09, "tracedt09", std), - CAPRI_PIN_DESC(CAPRI_PIN_TRACEDT10, "tracedt10", std), - CAPRI_PIN_DESC(CAPRI_PIN_TRACEDT11, "tracedt11", std), - CAPRI_PIN_DESC(CAPRI_PIN_TRACEDT12, "tracedt12", std), - CAPRI_PIN_DESC(CAPRI_PIN_TRACEDT13, "tracedt13", std), - CAPRI_PIN_DESC(CAPRI_PIN_TRACEDT14, "tracedt14", std), - CAPRI_PIN_DESC(CAPRI_PIN_TRACEDT15, "tracedt15", std), - CAPRI_PIN_DESC(CAPRI_PIN_TXDATA3G0, "txdata3g0", std), - CAPRI_PIN_DESC(CAPRI_PIN_TXPWRIND, "txpwrind", std), - CAPRI_PIN_DESC(CAPRI_PIN_UARTB1_UCTS, "uartb1_ucts", std), - CAPRI_PIN_DESC(CAPRI_PIN_UARTB1_URTS, "uartb1_urts", std), - CAPRI_PIN_DESC(CAPRI_PIN_UARTB1_URXD, "uartb1_urxd", std), - CAPRI_PIN_DESC(CAPRI_PIN_UARTB1_UTXD, "uartb1_utxd", std), - CAPRI_PIN_DESC(CAPRI_PIN_UARTB2_URXD, "uartb2_urxd", std), - CAPRI_PIN_DESC(CAPRI_PIN_UARTB2_UTXD, "uartb2_utxd", std), - CAPRI_PIN_DESC(CAPRI_PIN_UARTB3_UCTS, "uartb3_ucts", std), - CAPRI_PIN_DESC(CAPRI_PIN_UARTB3_URTS, "uartb3_urts", std), - CAPRI_PIN_DESC(CAPRI_PIN_UARTB3_URXD, "uartb3_urxd", std), - CAPRI_PIN_DESC(CAPRI_PIN_UARTB3_UTXD, "uartb3_utxd", std), - CAPRI_PIN_DESC(CAPRI_PIN_UARTB4_UCTS, "uartb4_ucts", std), - CAPRI_PIN_DESC(CAPRI_PIN_UARTB4_URTS, "uartb4_urts", std), - CAPRI_PIN_DESC(CAPRI_PIN_UARTB4_URXD, "uartb4_urxd", std), - CAPRI_PIN_DESC(CAPRI_PIN_UARTB4_UTXD, "uartb4_utxd", std), - CAPRI_PIN_DESC(CAPRI_PIN_VC_CAM1_SCL, "vc_cam1_scl", i2c), - CAPRI_PIN_DESC(CAPRI_PIN_VC_CAM1_SDA, "vc_cam1_sda", i2c), - CAPRI_PIN_DESC(CAPRI_PIN_VC_CAM2_SCL, "vc_cam2_scl", i2c), - CAPRI_PIN_DESC(CAPRI_PIN_VC_CAM2_SDA, "vc_cam2_sda", i2c), - CAPRI_PIN_DESC(CAPRI_PIN_VC_CAM3_SCL, "vc_cam3_scl", i2c), - CAPRI_PIN_DESC(CAPRI_PIN_VC_CAM3_SDA, "vc_cam3_sda", i2c), -}; - -static const char * const capri_alt_groups[] = { - "adcsync", - "bat_rm", - "bsc1_scl", - "bsc1_sda", - "bsc2_scl", - "bsc2_sda", - "classgpwr", - "clk_cx8", - "clkout_0", - "clkout_1", - "clkout_2", - "clkout_3", - "clkreq_in_0", - "clkreq_in_1", - "cws_sys_req1", - "cws_sys_req2", - "cws_sys_req3", - "digmic1_clk", - "digmic1_dq", - "digmic2_clk", - "digmic2_dq", - "gpen13", - "gpen14", - "gpen15", - "gpio00", - "gpio01", - "gpio02", - "gpio03", - "gpio04", - "gpio05", - "gpio06", - "gpio07", - "gpio08", - "gpio09", - "gpio10", - "gpio11", - "gpio12", - "gpio13", - "gpio14", - "gps_pablank", - "gps_tmark", - "hdmi_scl", - "hdmi_sda", - "ic_dm", - "ic_dp", - "kp_col_ip_0", - "kp_col_ip_1", - "kp_col_ip_2", - "kp_col_ip_3", - "kp_row_op_0", - "kp_row_op_1", - "kp_row_op_2", - "kp_row_op_3", - "lcd_b_0", - "lcd_b_1", - "lcd_b_2", - "lcd_b_3", - "lcd_b_4", - "lcd_b_5", - "lcd_b_6", - "lcd_b_7", - "lcd_g_0", - "lcd_g_1", - "lcd_g_2", - "lcd_g_3", - "lcd_g_4", - "lcd_g_5", - "lcd_g_6", - "lcd_g_7", - "lcd_hsync", - "lcd_oe", - "lcd_pclk", - "lcd_r_0", - "lcd_r_1", - "lcd_r_2", - "lcd_r_3", - "lcd_r_4", - "lcd_r_5", - "lcd_r_6", - "lcd_r_7", - "lcd_vsync", - "mdmgpio0", - "mdmgpio1", - "mdmgpio2", - "mdmgpio3", - "mdmgpio4", - "mdmgpio5", - "mdmgpio6", - "mdmgpio7", - "mdmgpio8", - "mphi_data_0", - "mphi_data_1", - "mphi_data_2", - "mphi_data_3", - "mphi_data_4", - "mphi_data_5", - "mphi_data_6", - "mphi_data_7", - "mphi_data_8", - "mphi_data_9", - "mphi_data_10", - "mphi_data_11", - "mphi_data_12", - "mphi_data_13", - "mphi_data_14", - "mphi_data_15", - "mphi_ha0", - "mphi_hat0", - "mphi_hat1", - "mphi_hce0_n", - "mphi_hce1_n", - "mphi_hrd_n", - "mphi_hwr_n", - "mphi_run0", - "mphi_run1", - "mtx_scan_clk", - "mtx_scan_data", - "nand_ad_0", - "nand_ad_1", - "nand_ad_2", - "nand_ad_3", - "nand_ad_4", - "nand_ad_5", - "nand_ad_6", - "nand_ad_7", - "nand_ale", - "nand_cen_0", - "nand_cen_1", - "nand_cle", - "nand_oen", - "nand_rdy_0", - "nand_rdy_1", - "nand_wen", - "nand_wp", - "pc1", - "pc2", - "pmu_int", - "pmu_scl", - "pmu_sda", - "rfst2g_mtsloten3g", - "rgmii_0_rx_ctl", - "rgmii_0_rxc", - "rgmii_0_rxd_0", - "rgmii_0_rxd_1", - "rgmii_0_rxd_2", - "rgmii_0_rxd_3", - "rgmii_0_tx_ctl", - "rgmii_0_txc", - "rgmii_0_txd_0", - "rgmii_0_txd_1", - "rgmii_0_txd_2", - "rgmii_0_txd_3", - "rgmii_1_rx_ctl", - "rgmii_1_rxc", - "rgmii_1_rxd_0", - "rgmii_1_rxd_1", - "rgmii_1_rxd_2", - "rgmii_1_rxd_3", - "rgmii_1_tx_ctl", - "rgmii_1_txc", - "rgmii_1_txd_0", - "rgmii_1_txd_1", - "rgmii_1_txd_2", - "rgmii_1_txd_3", - "rgmii_gpio_0", - "rgmii_gpio_1", - "rgmii_gpio_2", - "rgmii_gpio_3", - "rtxdata2g_txdata3g1", - "rtxen2g_txdata3g2", - "rxdata3g0", - "rxdata3g1", - "rxdata3g2", - "sdio1_clk", - "sdio1_cmd", - "sdio1_data_0", - "sdio1_data_1", - "sdio1_data_2", - "sdio1_data_3", - "sdio4_clk", - "sdio4_cmd", - "sdio4_data_0", - "sdio4_data_1", - "sdio4_data_2", - "sdio4_data_3", - "sim_clk", - "sim_data", - "sim_det", - "sim_resetn", - "sim2_clk", - "sim2_data", - "sim2_det", - "sim2_resetn", - "sri_c", - "sri_d", - "sri_e", - "ssp_extclk", - "ssp0_clk", - "ssp0_fs", - "ssp0_rxd", - "ssp0_txd", - "ssp2_clk", - "ssp2_fs_0", - "ssp2_fs_1", - "ssp2_fs_2", - "ssp2_fs_3", - "ssp2_rxd_0", - "ssp2_rxd_1", - "ssp2_txd_0", - "ssp2_txd_1", - "ssp3_clk", - "ssp3_fs", - "ssp3_rxd", - "ssp3_txd", - "ssp4_clk", - "ssp4_fs", - "ssp4_rxd", - "ssp4_txd", - "ssp5_clk", - "ssp5_fs", - "ssp5_rxd", - "ssp5_txd", - "ssp6_clk", - "ssp6_fs", - "ssp6_rxd", - "ssp6_txd", - "stat_1", - "stat_2", - "sysclken", - "traceclk", - "tracedt00", - "tracedt01", - "tracedt02", - "tracedt03", - "tracedt04", - "tracedt05", - "tracedt06", - "tracedt07", - "tracedt08", - "tracedt09", - "tracedt10", - "tracedt11", - "tracedt12", - "tracedt13", - "tracedt14", - "tracedt15", - "txdata3g0", - "txpwrind", - "uartb1_ucts", - "uartb1_urts", - "uartb1_urxd", - "uartb1_utxd", - "uartb2_urxd", - "uartb2_utxd", - "uartb3_ucts", - "uartb3_urts", - "uartb3_urxd", - "uartb3_utxd", - "uartb4_ucts", - "uartb4_urts", - "uartb4_urxd", - "uartb4_utxd", - "vc_cam1_scl", - "vc_cam1_sda", - "vc_cam2_scl", - "vc_cam2_sda", - "vc_cam3_scl", - "vc_cam3_sda", -}; - -/* Every pin can implement all ALT1-ALT4 functions */ -#define CAPRI_PIN_FUNCTION(fcn_name) \ -{ \ - .name = #fcn_name, \ - .groups = capri_alt_groups, \ - .ngroups = ARRAY_SIZE(capri_alt_groups), \ -} - -static const struct capri_pin_function capri_functions[] = { - CAPRI_PIN_FUNCTION(alt1), - CAPRI_PIN_FUNCTION(alt2), - CAPRI_PIN_FUNCTION(alt3), - CAPRI_PIN_FUNCTION(alt4), -}; - -static struct capri_pinctrl_data capri_pinctrl = { - .pins = capri_pinctrl_pins, - .npins = ARRAY_SIZE(capri_pinctrl_pins), - .functions = capri_functions, - .nfunctions = ARRAY_SIZE(capri_functions), -}; - -static inline enum capri_pin_type pin_type_get(struct pinctrl_dev *pctldev, - unsigned pin) -{ - struct capri_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); - - if (pin >= pdata->npins) - return CAPRI_PIN_TYPE_UNKNOWN; - - return *(enum capri_pin_type *)(pdata->pins[pin].drv_data); -} - -#define CAPRI_PIN_SHIFT(type, param) \ - (CAPRI_ ## type ## _PIN_REG_ ## param ## _SHIFT) - -#define CAPRI_PIN_MASK(type, param) \ - (CAPRI_ ## type ## _PIN_REG_ ## param ## _MASK) - -/* - * This helper function is used to build up the value and mask used to write to - * a pin register, but does not actually write to the register. - */ -static inline void capri_pin_update(u32 *reg_val, u32 *reg_mask, u32 param_val, - u32 param_shift, u32 param_mask) -{ - *reg_val &= ~param_mask; - *reg_val |= (param_val << param_shift) & param_mask; - *reg_mask |= param_mask; -} - -static struct regmap_config capri_pinctrl_regmap_config = { - .reg_bits = 32, - .reg_stride = 4, - .val_bits = 32, - .max_register = CAPRI_PIN_VC_CAM3_SDA, -}; - -static int capri_pinctrl_get_groups_count(struct pinctrl_dev *pctldev) -{ - struct capri_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); - - return pdata->npins; -} - -static const char *capri_pinctrl_get_group_name(struct pinctrl_dev *pctldev, - unsigned group) -{ - struct capri_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); - - return pdata->pins[group].name; -} - -static int capri_pinctrl_get_group_pins(struct pinctrl_dev *pctldev, - unsigned group, - const unsigned **pins, - unsigned *num_pins) -{ - struct capri_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); - - *pins = &pdata->pins[group].number; - *num_pins = 1; - - return 0; -} - -static void capri_pinctrl_pin_dbg_show(struct pinctrl_dev *pctldev, - struct seq_file *s, - unsigned offset) -{ - seq_printf(s, " %s", dev_name(pctldev->dev)); -} - -static struct pinctrl_ops capri_pinctrl_ops = { - .get_groups_count = capri_pinctrl_get_groups_count, - .get_group_name = capri_pinctrl_get_group_name, - .get_group_pins = capri_pinctrl_get_group_pins, - .pin_dbg_show = capri_pinctrl_pin_dbg_show, - .dt_node_to_map = pinconf_generic_dt_node_to_map_pin, - .dt_free_map = pinctrl_utils_dt_free_map, -}; - -static int capri_pinctrl_get_fcns_count(struct pinctrl_dev *pctldev) -{ - struct capri_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); - - return pdata->nfunctions; -} - -static const char *capri_pinctrl_get_fcn_name(struct pinctrl_dev *pctldev, - unsigned function) -{ - struct capri_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); - - return pdata->functions[function].name; -} - -static int capri_pinctrl_get_fcn_groups(struct pinctrl_dev *pctldev, - unsigned function, - const char * const **groups, - unsigned * const num_groups) -{ - struct capri_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); - - *groups = pdata->functions[function].groups; - *num_groups = pdata->functions[function].ngroups; - - return 0; -} - -static int capri_pinmux_enable(struct pinctrl_dev *pctldev, - unsigned function, - unsigned group) -{ - struct capri_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); - const struct capri_pin_function *f = &pdata->functions[function]; - u32 offset = 4 * pdata->pins[group].number; - int rc = 0; - - dev_dbg(pctldev->dev, - "%s(): Enable function %s (%d) of pin %s (%d) @offset 0x%x.\n", - __func__, f->name, function, pdata->pins[group].name, - pdata->pins[group].number, offset); - - rc = regmap_update_bits(pdata->regmap, offset, CAPRI_PIN_REG_F_SEL_MASK, - function << CAPRI_PIN_REG_F_SEL_SHIFT); - if (rc) - dev_err(pctldev->dev, - "Error updating register for pin %s (%d).\n", - pdata->pins[group].name, pdata->pins[group].number); - - return rc; -} - -static struct pinmux_ops capri_pinctrl_pinmux_ops = { - .get_functions_count = capri_pinctrl_get_fcns_count, - .get_function_name = capri_pinctrl_get_fcn_name, - .get_function_groups = capri_pinctrl_get_fcn_groups, - .enable = capri_pinmux_enable, -}; - -static int capri_pinctrl_pin_config_get(struct pinctrl_dev *pctldev, - unsigned pin, - unsigned long *config) -{ - return -ENOTSUPP; -} - - -/* Goes through the configs and update register val/mask */ -static int capri_std_pin_update(struct pinctrl_dev *pctldev, - unsigned pin, - unsigned long *configs, - unsigned num_configs, - u32 *val, - u32 *mask) -{ - struct capri_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); - int i; - enum pin_config_param param; - u16 arg; - - for (i = 0; i < num_configs; i++) { - param = pinconf_to_config_param(configs[i]); - arg = pinconf_to_config_argument(configs[i]); - - switch (param) { - case PIN_CONFIG_INPUT_SCHMITT_ENABLE: - arg = (arg >= 1 ? 1 : 0); - capri_pin_update(val, mask, arg, - CAPRI_PIN_SHIFT(STD, HYST), - CAPRI_PIN_MASK(STD, HYST)); - break; - /* - * The pin bias can only be one of pull-up, pull-down, or - * disable. The user does not need to specify a value for the - * property, and the default value from pinconf-generic is - * ignored. - */ - case PIN_CONFIG_BIAS_DISABLE: - capri_pin_update(val, mask, 0, - CAPRI_PIN_SHIFT(STD, PULL_UP), - CAPRI_PIN_MASK(STD, PULL_UP)); - capri_pin_update(val, mask, 0, - CAPRI_PIN_SHIFT(STD, PULL_DN), - CAPRI_PIN_MASK(STD, PULL_DN)); - break; - - case PIN_CONFIG_BIAS_PULL_UP: - capri_pin_update(val, mask, 1, - CAPRI_PIN_SHIFT(STD, PULL_UP), - CAPRI_PIN_MASK(STD, PULL_UP)); - capri_pin_update(val, mask, 0, - CAPRI_PIN_SHIFT(STD, PULL_DN), - CAPRI_PIN_MASK(STD, PULL_DN)); - break; - - case PIN_CONFIG_BIAS_PULL_DOWN: - capri_pin_update(val, mask, 0, - CAPRI_PIN_SHIFT(STD, PULL_UP), - CAPRI_PIN_MASK(STD, PULL_UP)); - capri_pin_update(val, mask, 1, - CAPRI_PIN_SHIFT(STD, PULL_DN), - CAPRI_PIN_MASK(STD, PULL_DN)); - break; - - case PIN_CONFIG_SLEW_RATE: - arg = (arg >= 1 ? 1 : 0); - capri_pin_update(val, mask, arg, - CAPRI_PIN_SHIFT(STD, SLEW), - CAPRI_PIN_MASK(STD, SLEW)); - break; - - case PIN_CONFIG_INPUT_ENABLE: - /* inversed since register is for input _disable_ */ - arg = (arg >= 1 ? 0 : 1); - capri_pin_update(val, mask, arg, - CAPRI_PIN_SHIFT(STD, INPUT_DIS), - CAPRI_PIN_MASK(STD, INPUT_DIS)); - break; - - case PIN_CONFIG_DRIVE_STRENGTH: - /* Valid range is 2-16 mA, even numbers only */ - if ((arg < 2) || (arg > 16) || (arg % 2)) { - dev_err(pctldev->dev, - "Invalid Drive Strength value (%d) for " - "pin %s (%d). Valid values are " - "(2..16) mA, even numbers only.\n", - arg, pdata->pins[pin].name, pin); - return -EINVAL; - } - capri_pin_update(val, mask, (arg/2)-1, - CAPRI_PIN_SHIFT(STD, DRV_STR), - CAPRI_PIN_MASK(STD, DRV_STR)); - break; - - default: - dev_err(pctldev->dev, - "Unrecognized pin config %d for pin %s (%d).\n", - param, pdata->pins[pin].name, pin); - return -EINVAL; - - } /* switch config */ - } /* for each config */ - - return 0; -} - -/* - * The pull-up strength for an I2C pin is represented by bits 4-6 in the - * register with the following mapping: - * 0b000: No pull-up - * 0b001: 1200 Ohm - * 0b010: 1800 Ohm - * 0b011: 720 Ohm - * 0b100: 2700 Ohm - * 0b101: 831 Ohm - * 0b110: 1080 Ohm - * 0b111: 568 Ohm - * This array maps pull-up strength in Ohms to register values (1+index). - */ -static const u16 capri_pullup_map[] = {1200, 1800, 720, 2700, 831, 1080, 568}; - -/* Goes through the configs and update register val/mask */ -static int capri_i2c_pin_update(struct pinctrl_dev *pctldev, - unsigned pin, - unsigned long *configs, - unsigned num_configs, - u32 *val, - u32 *mask) -{ - struct capri_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); - int i, j; - enum pin_config_param param; - u16 arg; - - for (i = 0; i < num_configs; i++) { - param = pinconf_to_config_param(configs[i]); - arg = pinconf_to_config_argument(configs[i]); - - switch (param) { - case PIN_CONFIG_BIAS_PULL_UP: - for (j = 0; j < ARRAY_SIZE(capri_pullup_map); j++) - if (capri_pullup_map[j] == arg) - break; - - if (j == ARRAY_SIZE(capri_pullup_map)) { - dev_err(pctldev->dev, - "Invalid pull-up value (%d) for pin %s " - "(%d). Valid values are 568, 720, 831, " - "1080, 1200, 1800, 2700 Ohms.\n", - arg, pdata->pins[pin].name, pin); - return -EINVAL; - } - - capri_pin_update(val, mask, j+1, - CAPRI_PIN_SHIFT(I2C, PULL_UP_STR), - CAPRI_PIN_MASK(I2C, PULL_UP_STR)); - break; - - case PIN_CONFIG_BIAS_DISABLE: - capri_pin_update(val, mask, 0, - CAPRI_PIN_SHIFT(I2C, PULL_UP_STR), - CAPRI_PIN_MASK(I2C, PULL_UP_STR)); - break; - - case PIN_CONFIG_SLEW_RATE: - arg = (arg >= 1 ? 1 : 0); - capri_pin_update(val, mask, arg, - CAPRI_PIN_SHIFT(I2C, SLEW), - CAPRI_PIN_MASK(I2C, SLEW)); - break; - - case PIN_CONFIG_INPUT_ENABLE: - /* inversed since register is for input _disable_ */ - arg = (arg >= 1 ? 0 : 1); - capri_pin_update(val, mask, arg, - CAPRI_PIN_SHIFT(I2C, INPUT_DIS), - CAPRI_PIN_MASK(I2C, INPUT_DIS)); - break; - - default: - dev_err(pctldev->dev, - "Unrecognized pin config %d for pin %s (%d).\n", - param, pdata->pins[pin].name, pin); - return -EINVAL; - - } /* switch config */ - } /* for each config */ - - return 0; -} - -/* Goes through the configs and update register val/mask */ -static int capri_hdmi_pin_update(struct pinctrl_dev *pctldev, - unsigned pin, - unsigned long *configs, - unsigned num_configs, - u32 *val, - u32 *mask) -{ - struct capri_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); - int i; - enum pin_config_param param; - u16 arg; - - for (i = 0; i < num_configs; i++) { - param = pinconf_to_config_param(configs[i]); - arg = pinconf_to_config_argument(configs[i]); - - switch (param) { - case PIN_CONFIG_SLEW_RATE: - arg = (arg >= 1 ? 1 : 0); - capri_pin_update(val, mask, arg, - CAPRI_PIN_SHIFT(HDMI, MODE), - CAPRI_PIN_MASK(HDMI, MODE)); - break; - - case PIN_CONFIG_INPUT_ENABLE: - /* inversed since register is for input _disable_ */ - arg = (arg >= 1 ? 0 : 1); - capri_pin_update(val, mask, arg, - CAPRI_PIN_SHIFT(HDMI, INPUT_DIS), - CAPRI_PIN_MASK(HDMI, INPUT_DIS)); - break; - - default: - dev_err(pctldev->dev, - "Unrecognized pin config %d for pin %s (%d).\n", - param, pdata->pins[pin].name, pin); - return -EINVAL; - - } /* switch config */ - } /* for each config */ - - return 0; -} - -static int capri_pinctrl_pin_config_set(struct pinctrl_dev *pctldev, - unsigned pin, - unsigned long *configs, - unsigned num_configs) -{ - struct capri_pinctrl_data *pdata = pinctrl_dev_get_drvdata(pctldev); - enum capri_pin_type pin_type; - u32 offset = 4 * pin; - u32 cfg_val, cfg_mask; - int rc; - - cfg_val = 0; - cfg_mask = 0; - pin_type = pin_type_get(pctldev, pin); - - /* Different pins have different configuration options */ - switch (pin_type) { - case CAPRI_PIN_TYPE_STD: - rc = capri_std_pin_update(pctldev, pin, configs, num_configs, - &cfg_val, &cfg_mask); - break; - - case CAPRI_PIN_TYPE_I2C: - rc = capri_i2c_pin_update(pctldev, pin, configs, num_configs, - &cfg_val, &cfg_mask); - break; - - case CAPRI_PIN_TYPE_HDMI: - rc = capri_hdmi_pin_update(pctldev, pin, configs, num_configs, - &cfg_val, &cfg_mask); - break; - - default: - dev_err(pctldev->dev, "Unknown pin type for pin %s (%d).\n", - pdata->pins[pin].name, pin); - return -EINVAL; - - } /* switch pin type */ - - if (rc) - return rc; - - dev_dbg(pctldev->dev, - "%s(): Set pin %s (%d) with config 0x%x, mask 0x%x\n", - __func__, pdata->pins[pin].name, pin, cfg_val, cfg_mask); - - rc = regmap_update_bits(pdata->regmap, offset, cfg_mask, cfg_val); - if (rc) { - dev_err(pctldev->dev, - "Error updating register for pin %s (%d).\n", - pdata->pins[pin].name, pin); - return rc; - } - - return 0; -} - -static struct pinconf_ops capri_pinctrl_pinconf_ops = { - .pin_config_get = capri_pinctrl_pin_config_get, - .pin_config_set = capri_pinctrl_pin_config_set, -}; - -static struct pinctrl_desc capri_pinctrl_desc = { - /* name, pins, npins members initialized in probe function */ - .pctlops = &capri_pinctrl_ops, - .pmxops = &capri_pinctrl_pinmux_ops, - .confops = &capri_pinctrl_pinconf_ops, - .owner = THIS_MODULE, -}; - -int __init capri_pinctrl_probe(struct platform_device *pdev) -{ - struct capri_pinctrl_data *pdata = &capri_pinctrl; - struct resource *res; - struct pinctrl_dev *pctl; - - /* So far We can assume there is only 1 bank of registers */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "Missing MEM resource\n"); - return -ENODEV; - } - - pdata->reg_base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(pdata->reg_base)) { - dev_err(&pdev->dev, "Failed to ioremap MEM resource\n"); - return -ENODEV; - } - - /* Initialize the dynamic part of pinctrl_desc */ - pdata->regmap = devm_regmap_init_mmio(&pdev->dev, pdata->reg_base, - &capri_pinctrl_regmap_config); - if (IS_ERR(pdata->regmap)) { - dev_err(&pdev->dev, "Regmap MMIO init failed.\n"); - return -ENODEV; - } - - capri_pinctrl_desc.name = dev_name(&pdev->dev); - capri_pinctrl_desc.pins = capri_pinctrl.pins; - capri_pinctrl_desc.npins = capri_pinctrl.npins; - - pctl = pinctrl_register(&capri_pinctrl_desc, - &pdev->dev, - pdata); - if (!pctl) { - dev_err(&pdev->dev, "Failed to register pinctrl\n"); - return -ENODEV; - } - - platform_set_drvdata(pdev, pdata); - - return 0; -} - -static struct of_device_id capri_pinctrl_of_match[] = { - { .compatible = "brcm,bcm11351-pinctrl", }, - { }, -}; - -static struct platform_driver capri_pinctrl_driver = { - .driver = { - .name = "bcm-capri-pinctrl", - .owner = THIS_MODULE, - .of_match_table = capri_pinctrl_of_match, - }, -}; - -module_platform_driver_probe(capri_pinctrl_driver, capri_pinctrl_probe); - -MODULE_AUTHOR("Sherman Yin "); -MODULE_DESCRIPTION("Broadcom Capri pinctrl driver"); -MODULE_LICENSE("GPL v2"); -- cgit v1.2.3-70-g09d2 From 7633fb959b711a8d91548911eb087fb931c7b8e4 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 9 Apr 2014 13:20:38 +0200 Subject: gpio: set data first, then chip and handler During irq mapping, in irq_set_chip_and_handler() the process of setting this up may incur calls to lock the irqchip, which in turn may need to dereference and use the chip data. So set the data first, then set the chip and handler. Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 761013f8b82..f48817d9748 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1387,8 +1387,8 @@ static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq, { struct gpio_chip *chip = d->host_data; - irq_set_chip_and_handler(irq, chip->irqchip, chip->irq_handler); irq_set_chip_data(irq, chip); + irq_set_chip_and_handler(irq, chip->irqchip, chip->irq_handler); #ifdef CONFIG_ARM set_irq_flags(irq, IRQF_VALID); #else -- cgit v1.2.3-70-g09d2 From e9595f84a6273dffc5b75564d9b12a77630c529e Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Mon, 31 Mar 2014 15:16:49 +0300 Subject: gpio / ACPI: Don't crash on NULL chip->dev Commit aa92b6f689ac (gpio / ACPI: Allocate ACPI specific data directly in acpi_gpiochip_add()) moved ACPI handle checking to acpi_gpiochip_add() but forgot to check whether chip->dev is NULL before dereferencing it. Since chip->dev pointer is optional we can end up with crash like following: BUG: unable to handle kernel NULL pointer dereference at 00000138 IP: [] acpi_gpiochip_add+0x13/0x190 *pde = 00000000 Oops: 0000 [#1] PREEMPT SMP Modules linked in: ssb(+) ... CPU: 0 PID: 512 Comm: modprobe Tainted: G W 3.14.0-rc7-next-20140324-t1 #24 Hardware name: Dell Inc. Latitude D830 /0UY141, BIOS A02 06/07/2007 task: f5799900 ti: f543e000 task.ti: f543e000 EIP: 0060:[] EFLAGS: 00010282 CPU: 0 EIP is at acpi_gpiochip_add+0x13/0x190 EAX: 00000000 EBX: f57824c4 ECX: 00000000 EDX: 00000000 ESI: f57824c4 EDI: 00000010 EBP: f543fc54 ESP: f543fc40 DS: 007b ES: 007b FS: 00d8 GS: 0033 SS: 0068 CR0: 8005003b CR2: 00000138 CR3: 355f8000 CR4: 000007d0 Stack: f543fc5c fd1f7790 f57824c4 000000be 00000010 f543fc84 c1269f4e f543fc74 fd1f78bd 00008002 f57822b0 f5782090 fd1f8400 00000286 fd1f9994 00000000 f5782000 f543fc8c fd1f7e39 f543fcc8 fd1f0bd8 000000c0 00000000 00000000 Call Trace: [] ? ssb_pcie_mdio_write+0xa0/0xd0 [ssb] [] gpiochip_add+0xee/0x300 [] ? ssb_pcicore_serdes_workaround+0xfd/0x140 [ssb] [] ssb_gpio_init+0x89/0xa0 [ssb] [] ssb_attach_queued_buses+0xc8/0x2d0 [ssb] [] ssb_bus_register+0x185/0x1f0 [ssb] [] ? ssb_pci_xtal+0x220/0x220 [ssb] [] ssb_bus_pcibus_register+0x2c/0x80 [ssb] [] ssb_pcihost_probe+0x9c/0x110 [ssb] [] pci_device_probe+0x6f/0xc0 [] ? sysfs_create_link+0x25/0x40 [] driver_probe_device+0x79/0x360 [] ? pci_match_device+0xb2/0xc0 [] __driver_attach+0x71/0x80 [] ? __device_attach+0x40/0x40 [] bus_for_each_dev+0x47/0x80 [] driver_attach+0x1e/0x20 [] ? __device_attach+0x40/0x40 [] bus_add_driver+0x157/0x230 [] driver_register+0x59/0xe0 ... Fix this by checking chip->dev pointer against NULL first. Also we can now remove redundant check in acpi_gpiochip_request/free_interrupts(). Reported-by: Sabrina Dubroca Signed-off-by: Mika Westerberg Tested-by: Sabrina Dubroca Acked-by: Alexandre Courbot Tested-by: Josh Boyer Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-acpi.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index bf0f8b47669..d5be56fe689 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -233,7 +233,7 @@ static void acpi_gpiochip_request_interrupts(struct acpi_gpio_chip *acpi_gpio) { struct gpio_chip *chip = acpi_gpio->chip; - if (!chip->dev || !chip->to_irq) + if (!chip->to_irq) return; INIT_LIST_HEAD(&acpi_gpio->events); @@ -253,7 +253,7 @@ static void acpi_gpiochip_free_interrupts(struct acpi_gpio_chip *acpi_gpio) struct acpi_gpio_event *event, *ep; struct gpio_chip *chip = acpi_gpio->chip; - if (!chip->dev || !chip->to_irq) + if (!chip->to_irq) return; list_for_each_entry_safe_reverse(event, ep, &acpi_gpio->events, node) { @@ -501,6 +501,9 @@ void acpi_gpiochip_add(struct gpio_chip *chip) acpi_handle handle; acpi_status status; + if (!chip || !chip->dev) + return; + handle = ACPI_HANDLE(chip->dev); if (!handle) return; @@ -531,6 +534,9 @@ void acpi_gpiochip_remove(struct gpio_chip *chip) acpi_handle handle; acpi_status status; + if (!chip || !chip->dev) + return; + handle = ACPI_HANDLE(chip->dev); if (!handle) return; -- cgit v1.2.3-70-g09d2 From b5539fa2d59d697b7b8e28b4d08da844ff60f7cf Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Tue, 1 Apr 2014 13:03:00 +0300 Subject: gpio / ACPI: Prevent potential wrap of GPIO value on OpRegion read Dan Carpenter's static code checker reports: The patch 473ed7be0da0: "gpio / ACPI: Add support for ACPI GPIO operation regions" from Mar 14, 2014, leads to the following static checker warning: drivers/gpio/gpiolib-acpi.c:454 acpi_gpio_adr_space_handler() warn: should 'gpiod_get_raw_value(desc) << i' be a 64 bit type? This is due the fact that *value is of type u64 and gpiod_get_raw_value() returns int. Since i can be larger than 31, it is possible that the value returned gets wrapped. Fix this by casting the return of gpiod_get_raw_value() to u64 first before shift. Reported-by: Dan Carpenter Signed-off-by: Mika Westerberg Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-acpi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c index d5be56fe689..401add28933 100644 --- a/drivers/gpio/gpiolib-acpi.c +++ b/drivers/gpio/gpiolib-acpi.c @@ -451,7 +451,7 @@ acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address, if (function == ACPI_WRITE) gpiod_set_raw_value(desc, !!((1 << i) & *value)); else - *value |= gpiod_get_raw_value(desc) << i; + *value |= (u64)gpiod_get_raw_value(desc) << i; } out: -- cgit v1.2.3-70-g09d2 From 2ec8e3787ae6957f738bb133e755213b9d7c066e Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Wed, 2 Apr 2014 11:37:06 +0300 Subject: drm/omap: fix output enable/disable sequence At the moment it's quite easy to get the following errors when the HDMI output is enabled or disabled: [drm:omap_crtc_error_irq] *ERROR* tv: errors: 00008000 The reason for the errors is that the omapdrm driver doesn't properly handle the sync-lost irqs that happen when enabling the DIGIT crtc, which is used for HDMI and analog TV. The driver does disable the sync-lost irq properly, but it fails to wait until the output has been fully enabled (i.e. the first vsync), so the sync-lost errors are still seen occasionally. This patch makes the omapdrm act the same way as the omapfb does: - When enabling a display, we'll wait for the first vsync. - When disabling a display, we'll wait for framedone if available, or odd and even vsyncs. These changes make sure the output is fully enabled or disabled at the end of the function. Signed-off-by: Tomi Valkeinen Reported-by: Sanjay Singh Rawat Reviewed-by: Rob Clark --- drivers/gpu/drm/omapdrm/omap_crtc.c | 46 ++++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c index 355157e4f78..0acbe62901d 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.c +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c @@ -528,38 +528,46 @@ static void set_enabled(struct drm_crtc *crtc, bool enable) struct drm_device *dev = crtc->dev; struct omap_crtc *omap_crtc = to_omap_crtc(crtc); enum omap_channel channel = omap_crtc->channel; - struct omap_irq_wait *wait = NULL; + struct omap_irq_wait *wait; + u32 framedone_irq, vsync_irq; + int ret; if (dispc_mgr_is_enabled(channel) == enable) return; - /* ignore sync-lost irqs during enable/disable */ + /* + * Digit output produces some sync lost interrupts during the first + * frame when enabling, so we need to ignore those. + */ omap_irq_unregister(crtc->dev, &omap_crtc->error_irq); - if (dispc_mgr_get_framedone_irq(channel)) { - if (!enable) { - wait = omap_irq_wait_init(dev, - dispc_mgr_get_framedone_irq(channel), 1); - } + framedone_irq = dispc_mgr_get_framedone_irq(channel); + vsync_irq = dispc_mgr_get_vsync_irq(channel); + + if (enable) { + wait = omap_irq_wait_init(dev, vsync_irq, 1); } else { /* - * When we disable digit output, we need to wait until fields - * are done. Otherwise the DSS is still working, and turning - * off the clocks prevents DSS from going to OFF mode. And when - * enabling, we need to wait for the extra sync losts + * When we disable the digit output, we need to wait for + * FRAMEDONE to know that DISPC has finished with the output. + * + * OMAP2/3 does not have FRAMEDONE irq for digit output, and in + * that case we need to use vsync interrupt, and wait for both + * even and odd frames. */ - wait = omap_irq_wait_init(dev, - dispc_mgr_get_vsync_irq(channel), 2); + + if (framedone_irq) + wait = omap_irq_wait_init(dev, framedone_irq, 1); + else + wait = omap_irq_wait_init(dev, vsync_irq, 2); } dispc_mgr_enable(channel, enable); - if (wait) { - int ret = omap_irq_wait(dev, wait, msecs_to_jiffies(100)); - if (ret) { - dev_err(dev->dev, "%s: timeout waiting for %s\n", - omap_crtc->name, enable ? "enable" : "disable"); - } + ret = omap_irq_wait(dev, wait, msecs_to_jiffies(100)); + if (ret) { + dev_err(dev->dev, "%s: timeout waiting for %s\n", + omap_crtc->name, enable ? "enable" : "disable"); } omap_irq_register(crtc->dev, &omap_crtc->error_irq); -- cgit v1.2.3-70-g09d2 From 707cf58a0a847f60f849b44bfb9b85dcc17c599d Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Wed, 2 Apr 2014 13:47:43 +0300 Subject: drm/omap: fix uninit order in pdev_remove() When unloading omapdrm driver, the omapdrm platform device is uninitialized last, after the displays have been disconnected omap_crtc callbacks have been removed. As the omapdrm pdev uninitialization needs the features uninitialized in earlier steps, a crash is guaranteed. This patch fixes the uninitialize order so that the omapdrm pdev is removed first. Signed-off-by: Tomi Valkeinen Reviewed-by: Rob Clark --- drivers/gpu/drm/omapdrm/omap_drv.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index bf39fcc49e0..df3e66416a3 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c @@ -696,10 +696,11 @@ static int pdev_remove(struct platform_device *device) { DBG(""); + drm_put_dev(platform_get_drvdata(device)); + omap_disconnect_dssdevs(); omap_crtc_pre_uninit(); - drm_put_dev(platform_get_drvdata(device)); return 0; } -- cgit v1.2.3-70-g09d2 From ea7e3a662814447cd329390feddd04b9ec0a4b82 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Wed, 2 Apr 2014 14:31:50 +0300 Subject: drm/omap: fix DMM driver (un)registration At the moment the DMM driver is never unregistered, even if it's registered in the omapdrm module's init function. This means we'll get errors when reloading the omapdrm module. Fix this by unregistering the DMM driver properly, and also change the module init to fail if DMM driver cannot be registered, simplifying the unregister path as we don't need to keep the state whether we registered the DMM driver or not. Signed-off-by: Tomi Valkeinen Reviewed-by: Rob Clark --- drivers/gpu/drm/omapdrm/omap_drv.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index df3e66416a3..f16a07d1668 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c @@ -727,18 +727,33 @@ static struct platform_driver pdev = { static int __init omap_drm_init(void) { + int r; + DBG("init"); - if (platform_driver_register(&omap_dmm_driver)) { - /* we can continue on without DMM.. so not fatal */ - dev_err(NULL, "DMM registration failed\n"); + + r = platform_driver_register(&omap_dmm_driver); + if (r) { + pr_err("DMM driver registration failed\n"); + return r; } - return platform_driver_register(&pdev); + + r = platform_driver_register(&pdev); + if (r) { + pr_err("omapdrm driver registration failed\n"); + platform_driver_unregister(&omap_dmm_driver); + return r; + } + + return 0; } static void __exit omap_drm_fini(void) { DBG("fini"); + platform_driver_unregister(&pdev); + + platform_driver_unregister(&omap_dmm_driver); } /* need late_initcall() so we load after dss_driver's are loaded */ -- cgit v1.2.3-70-g09d2 From e2f8fd74ec1bf15cb2abc1b11f7d9fa09581024e Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Wed, 2 Apr 2014 14:31:57 +0300 Subject: drm/omap: fix race issue when unloading omapdrm At module unload, omap_fbdev_free() gets called which releases the framebuffers. However, the framebuffers are still used by crtcs, and will be released only later at vsync. The driver doesn't wait for this, and goes on to release the rest of the resources, which often causes a crash. This patchs adds a omap_crtc_flush() function which waits until the crtc has finished with its apply queue and page flips. The function utilizes a simple polling while-loop, as the performance is not an issue here. Signed-off-by: Tomi Valkeinen Reviewed-by: Rob Clark --- drivers/gpu/drm/omapdrm/omap_crtc.c | 19 +++++++++++++++++++ drivers/gpu/drm/omapdrm/omap_drv.c | 6 ++++++ drivers/gpu/drm/omapdrm/omap_drv.h | 1 + 3 files changed, 26 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c index 0acbe62901d..161a74a3ac5 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.c +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c @@ -621,6 +621,25 @@ static void omap_crtc_post_apply(struct omap_drm_apply *apply) /* nothing needed for post-apply */ } +void omap_crtc_flush(struct drm_crtc *crtc) +{ + struct omap_crtc *omap_crtc = to_omap_crtc(crtc); + int loops = 0; + + while (!list_empty(&omap_crtc->pending_applies) || + !list_empty(&omap_crtc->queued_applies) || + omap_crtc->event || omap_crtc->old_fb) { + + if (++loops > 10) { + dev_err(crtc->dev->dev, + "omap_crtc_flush() timeout\n"); + break; + } + + schedule_timeout_uninterruptible(msecs_to_jiffies(20)); + } +} + static const char *channel_names[] = { [OMAP_DSS_CHANNEL_LCD] = "lcd", [OMAP_DSS_CHANNEL_DIGIT] = "tv", diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index f16a07d1668..c8270e4b26f 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c @@ -513,12 +513,18 @@ static int dev_load(struct drm_device *dev, unsigned long flags) static int dev_unload(struct drm_device *dev) { struct omap_drm_private *priv = dev->dev_private; + int i; DBG("unload: dev=%p", dev); drm_kms_helper_poll_fini(dev); omap_fbdev_free(dev); + + /* flush crtcs so the fbs get released */ + for (i = 0; i < priv->num_crtcs; i++) + omap_crtc_flush(priv->crtcs[i]); + omap_modeset_free(dev); omap_gem_deinit(dev); diff --git a/drivers/gpu/drm/omapdrm/omap_drv.h b/drivers/gpu/drm/omapdrm/omap_drv.h index 428b2981fd6..284b80fc3c5 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.h +++ b/drivers/gpu/drm/omapdrm/omap_drv.h @@ -163,6 +163,7 @@ void omap_crtc_pre_init(void); void omap_crtc_pre_uninit(void); struct drm_crtc *omap_crtc_init(struct drm_device *dev, struct drm_plane *plane, enum omap_channel channel, int id); +void omap_crtc_flush(struct drm_crtc *crtc); struct drm_plane *omap_plane_init(struct drm_device *dev, int plane_id, bool private_plane); -- cgit v1.2.3-70-g09d2 From c7aef12f344459961eb1e0ba10d184816ed42d99 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 3 Apr 2014 16:30:03 +0300 Subject: drm/omap: fix missing disable for unused encoder When an encoder is no longer connected to a crtc, the driver will leave the encoder enabled. This patch adds code to track the encoder used for a crtc, and when the encoder changes, the old one is disabled. Signed-off-by: Tomi Valkeinen Reviewed-by: Rob Clark --- drivers/gpu/drm/omapdrm/omap_crtc.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c index 161a74a3ac5..61d1c4897a4 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.c +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c @@ -33,6 +33,7 @@ struct omap_crtc { int pipe; enum omap_channel channel; struct omap_overlay_manager_info info; + struct drm_encoder *current_encoder; /* * Temporary: eventually this will go away, but it is needed @@ -594,6 +595,11 @@ static void omap_crtc_pre_apply(struct omap_drm_apply *apply) } } + if (omap_crtc->current_encoder && encoder != omap_crtc->current_encoder) + omap_encoder_set_enabled(omap_crtc->current_encoder, false); + + omap_crtc->current_encoder = encoder; + if (!omap_crtc->enabled) { set_enabled(&omap_crtc->base, false); if (encoder) -- cgit v1.2.3-70-g09d2 From 506096a113832239ce763d20fab8e94f76d56266 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 3 Apr 2014 13:11:54 +0300 Subject: drm/omap: fix enabling/disabling of video pipeline At the moment the omap_crtc_pre_apply() handles the enabling, disabling and configuring of encoders and panels separately from the CRTC (i.e. the overlay manager). However, this doesn't work correctly. The encoder driver has to be in control of its video input (i.e. the crtc) for correct operation. This problem causes bugs with (at least) HDMI: the HDMI encoder supplies pixel clock for DISPC, and DISPC supplies video stream for HDMI. The current code first enables the HDMI encoder, and CRTC after that. However, the encoder expects the video stream to start during the encoder's enable, and if it doesn't, there will be sync lost errors. The encoder enables its video source by calling src->enable(), and this call goes to omapdrm (omap_crtc_enable), but omapdrm doesn't do anything in that function. Similarly for disable, which goes to omap_crtc_disable(). This patch moves the code to setup and enable/disable the crtc to omap_crtc_enable. and omap_crtc_disable(). Signed-off-by: Tomi Valkeinen Reviewed-by: Rob Clark --- drivers/gpu/drm/omapdrm/omap_crtc.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c index 61d1c4897a4..f59ef9359e6 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.c +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c @@ -121,13 +121,25 @@ static void omap_crtc_start_update(struct omap_overlay_manager *mgr) { } +static void set_enabled(struct drm_crtc *crtc, bool enable); + static int omap_crtc_enable(struct omap_overlay_manager *mgr) { + struct omap_crtc *omap_crtc = omap_crtcs[mgr->id]; + + dispc_mgr_setup(omap_crtc->channel, &omap_crtc->info); + dispc_mgr_set_timings(omap_crtc->channel, + &omap_crtc->timings); + set_enabled(&omap_crtc->base, true); + return 0; } static void omap_crtc_disable(struct omap_overlay_manager *mgr) { + struct omap_crtc *omap_crtc = omap_crtcs[mgr->id]; + + set_enabled(&omap_crtc->base, false); } static void omap_crtc_set_timings(struct omap_overlay_manager *mgr, @@ -601,7 +613,6 @@ static void omap_crtc_pre_apply(struct omap_drm_apply *apply) omap_crtc->current_encoder = encoder; if (!omap_crtc->enabled) { - set_enabled(&omap_crtc->base, false); if (encoder) omap_encoder_set_enabled(encoder, false); } else { @@ -610,13 +621,7 @@ static void omap_crtc_pre_apply(struct omap_drm_apply *apply) omap_encoder_update(encoder, omap_crtc->mgr, &omap_crtc->timings); omap_encoder_set_enabled(encoder, true); - omap_crtc->full_update = false; } - - dispc_mgr_setup(omap_crtc->channel, &omap_crtc->info); - dispc_mgr_set_timings(omap_crtc->channel, - &omap_crtc->timings); - set_enabled(&omap_crtc->base, true); } omap_crtc->full_update = false; -- cgit v1.2.3-70-g09d2 From d4586604acbd2e58921e0363533b9797b0235275 Mon Sep 17 00:00:00 2001 From: Grazvydas Ignotas Date: Sat, 5 Apr 2014 21:33:51 +0300 Subject: drm/omap: fix plane rotation Plane rotation with omapdrm is currently broken. It seems omap_plane_mode_set() expects width and height in screen coordinates, so pass it like that. Signed-off-by: Grazvydas Ignotas Reviewed-by: Rob Clark Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/omap_plane.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/omap_plane.c b/drivers/gpu/drm/omapdrm/omap_plane.c index 046d5e660c0..df1725247cc 100644 --- a/drivers/gpu/drm/omapdrm/omap_plane.c +++ b/drivers/gpu/drm/omapdrm/omap_plane.c @@ -246,6 +246,14 @@ static int omap_plane_update(struct drm_plane *plane, drm_framebuffer_reference(fb); + /* omap_plane_mode_set() takes adjusted src */ + switch (omap_plane->win.rotation & 0xf) { + case BIT(DRM_ROTATE_90): + case BIT(DRM_ROTATE_270): + swap(src_w, src_h); + break; + } + return omap_plane_mode_set(plane, crtc, fb, crtc_x, crtc_y, crtc_w, crtc_h, src_x, src_y, src_w, src_h, -- cgit v1.2.3-70-g09d2 From 5e19c06d0e570a347669acc2b850c2f730090b60 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Tue, 8 Apr 2014 15:25:34 +0300 Subject: drm/omap: fix missing unref to fb's buf object omap_fbdev_create() takes a reference to the fb's gem object with omap_gem_get_paddr(). However, it never releases it with omap_gem_put_paddr(). This patch adds the missing omap_gem_put_paddr() to omap_fbdev_free(). Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/omap_fbdev.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/omap_fbdev.c b/drivers/gpu/drm/omapdrm/omap_fbdev.c index 002988d0902..1388ca7f87e 100644 --- a/drivers/gpu/drm/omapdrm/omap_fbdev.c +++ b/drivers/gpu/drm/omapdrm/omap_fbdev.c @@ -371,6 +371,9 @@ void omap_fbdev_free(struct drm_device *dev) fbdev = to_omap_fbdev(priv->fbdev); + /* release the ref taken in omap_fbdev_create() */ + omap_gem_put_paddr(fbdev->bo); + /* this will free the backing object */ if (fbdev->fb) { drm_framebuffer_unregister_private(fbdev->fb); -- cgit v1.2.3-70-g09d2 From 8d018647e00876e0c0e8dba13c52c882be4e1678 Mon Sep 17 00:00:00 2001 From: Jon Ringle Date: Tue, 1 Apr 2014 08:39:34 -0400 Subject: video: da8xx-fb: Fix casting of info->pseudo_palette The casting to (u16 *) on info->pseudo_palette is wrong and causes the display to show a blue (garbage) vertical line on every other pixel column Signed-off-by: Jon Ringle Signed-off-by: Tomi Valkeinen --- drivers/video/da8xx-fb.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c index 0c0ba920ea4..6b23508ff0a 100644 --- a/drivers/video/da8xx-fb.c +++ b/drivers/video/da8xx-fb.c @@ -663,15 +663,7 @@ static int fb_setcolreg(unsigned regno, unsigned red, unsigned green, (green << info->var.green.offset) | (blue << info->var.blue.offset); - switch (info->var.bits_per_pixel) { - case 16: - ((u16 *) (info->pseudo_palette))[regno] = v; - break; - case 24: - case 32: - ((u32 *) (info->pseudo_palette))[regno] = v; - break; - } + ((u32 *) (info->pseudo_palette))[regno] = v; if (palette[0] != 0x4000) { update_hw = 1; palette[0] = 0x4000; -- cgit v1.2.3-70-g09d2 From d0e224f9963b79610850b2a10622182176658022 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 13 Feb 2014 11:36:22 +0200 Subject: OMAPDSS: fix rounding when calculating fclk rate "clk: divider: fix rate calculation for fractional rates" patch (and similar for TI specific divider) fixes the clk-divider's rounding. This patch updates the DSS driver to round the rates accordingly. This fixes the DSS's warnings about clock rate mismatch, and also fixes the wrong fclk rate being set. Signed-off-by: Tomi Valkeinen Tested-by: Christoph Fritz Tested-by: Marek Belisko --- drivers/video/omap2/dss/dss.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index 825c019ddee..d55266c0e02 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c @@ -457,7 +457,7 @@ bool dss_div_calc(unsigned long pck, unsigned long fck_min, fckd_stop = max(DIV_ROUND_UP(prate * m, fck_hw_max), 1ul); for (fckd = fckd_start; fckd >= fckd_stop; --fckd) { - fck = prate / fckd * m; + fck = DIV_ROUND_UP(prate, fckd) * m; if (func(fck, data)) return true; @@ -506,7 +506,7 @@ static int dss_setup_default_clock(void) fck_div = DIV_ROUND_UP(prate * dss.feat->dss_fck_multiplier, max_dss_fck); - fck = prate / fck_div * dss.feat->dss_fck_multiplier; + fck = DIV_ROUND_UP(prate, fck_div) * dss.feat->dss_fck_multiplier; } r = dss_set_fck_rate(fck); -- cgit v1.2.3-70-g09d2 From 25e475e11d8acff1b7c2febbf1d170e95033ba2e Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Thu, 20 Mar 2014 10:58:31 +0400 Subject: video: imxfb: Select LCD_CLASS_DEVICE unconditionally FB driver uses lowlevel controls for LCD powering and contrast changing. Since LCD class cannot be used as an optional feature and should be compiled for using in the driver, this patch selects LCD_CLASS_DEVICE symbol for the driver. Signed-off-by: Alexander Shiyan Signed-off-by: Tomi Valkeinen --- drivers/video/Kconfig | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 6c793bc683d..3ad7ebe2a96 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -359,6 +359,8 @@ config FB_SA1100 config FB_IMX tristate "Freescale i.MX1/21/25/27 LCD support" depends on FB && ARCH_MXC + select BACKLIGHT_LCD_SUPPORT + select LCD_CLASS_DEVICE select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT -- cgit v1.2.3-70-g09d2 From 0925afc9a4851c2592f1d45a17aeb7e1ffe188b7 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Fri, 11 Apr 2014 13:49:55 +0300 Subject: OMAPDSS: fix shared irq handlers DSS uses shared irq handlers for DISPC and DSI, because on OMAP3, the DISPC and DSI share the same irq line. However, the irq handlers presume that the hardware is enabled, which, in theory, may not be the case with shared irq handlers. So if an interrupt happens while the DISPC/DSI is off, the kernel will halt as the irq handler tries to access the DISPC/DSI registers. In practice that should never happen, as both DSI and DISPC are in the same power domain. So if there's an IRQ for one of them, the other is also enabled. However, if CONFIG_DEBUG_SHIRQ is enabled, the kernel will generate a spurious IRQ, which then causes the problem. This patch adds an is_enabled field for both DISPC and DSI, which is used to track if the HW is enabled. For DISPC the code is slightly more complex, as the users of DISPC can register the interrupt handler, and we want to hide the is_enabled handling from the users of DISPC. Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dispc.c | 55 +++++++++++++++++++++++++++++++++++------ drivers/video/omap2/dss/dsi.c | 20 +++++++++++++++ 2 files changed, 68 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index 2bbdb7ff7da..b37e3fbf60c 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -101,6 +101,8 @@ static struct { void __iomem *base; int irq; + irq_handler_t user_handler; + void *user_data; unsigned long core_clk_rate; unsigned long tv_pclk_rate; @@ -113,6 +115,8 @@ static struct { u32 ctx[DISPC_SZ_REGS / sizeof(u32)]; const struct dispc_features *feat; + + bool is_enabled; } dispc; enum omap_color_component { @@ -3669,16 +3673,44 @@ static int __init dispc_init_features(struct platform_device *pdev) return 0; } +static irqreturn_t dispc_irq_handler(int irq, void *arg) +{ + if (!dispc.is_enabled) + return IRQ_NONE; + + return dispc.user_handler(irq, dispc.user_data); +} + int dispc_request_irq(irq_handler_t handler, void *dev_id) { - return devm_request_irq(&dispc.pdev->dev, dispc.irq, handler, - IRQF_SHARED, "OMAP DISPC", dev_id); + int r; + + if (dispc.user_handler != NULL) + return -EBUSY; + + dispc.user_handler = handler; + dispc.user_data = dev_id; + + /* ensure the dispc_irq_handler sees the values above */ + smp_wmb(); + + r = devm_request_irq(&dispc.pdev->dev, dispc.irq, dispc_irq_handler, + IRQF_SHARED, "OMAP DISPC", &dispc); + if (r) { + dispc.user_handler = NULL; + dispc.user_data = NULL; + } + + return r; } EXPORT_SYMBOL(dispc_request_irq); void dispc_free_irq(void *dev_id) { - devm_free_irq(&dispc.pdev->dev, dispc.irq, dev_id); + devm_free_irq(&dispc.pdev->dev, dispc.irq, &dispc); + + dispc.user_handler = NULL; + dispc.user_data = NULL; } EXPORT_SYMBOL(dispc_free_irq); @@ -3750,6 +3782,12 @@ static int __exit omap_dispchw_remove(struct platform_device *pdev) static int dispc_runtime_suspend(struct device *dev) { + dispc.is_enabled = false; + /* ensure the dispc_irq_handler sees the is_enabled value */ + smp_wmb(); + /* wait for current handler to finish before turning the DISPC off */ + synchronize_irq(dispc.irq); + dispc_save_context(); return 0; @@ -3763,12 +3801,15 @@ static int dispc_runtime_resume(struct device *dev) * _omap_dispc_initial_config(). We can thus use it to detect if * we have lost register context. */ - if (REG_GET(DISPC_CONFIG, 2, 1) == OMAP_DSS_LOAD_FRAME_ONLY) - return 0; + if (REG_GET(DISPC_CONFIG, 2, 1) != OMAP_DSS_LOAD_FRAME_ONLY) { + _omap_dispc_initial_config(); - _omap_dispc_initial_config(); + dispc_restore_context(); + } - dispc_restore_context(); + dispc.is_enabled = true; + /* ensure the dispc_irq_handler sees the is_enabled value */ + smp_wmb(); return 0; } diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 121d1049d0b..8be9b04d884 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -297,6 +297,8 @@ struct dsi_data { int irq; + bool is_enabled; + struct clk *dss_clk; struct clk *sys_clk; @@ -795,6 +797,9 @@ static irqreturn_t omap_dsi_irq_handler(int irq, void *arg) dsidev = (struct platform_device *) arg; dsi = dsi_get_dsidrv_data(dsidev); + if (!dsi->is_enabled) + return IRQ_NONE; + spin_lock(&dsi->irq_lock); irqstatus = dsi_read_reg(dsidev, DSI_IRQSTATUS); @@ -5671,6 +5676,15 @@ static int __exit omap_dsihw_remove(struct platform_device *dsidev) static int dsi_runtime_suspend(struct device *dev) { + struct platform_device *pdev = to_platform_device(dev); + struct dsi_data *dsi = dsi_get_dsidrv_data(pdev); + + dsi->is_enabled = false; + /* ensure the irq handler sees the is_enabled value */ + smp_wmb(); + /* wait for current handler to finish before turning the DSI off */ + synchronize_irq(dsi->irq); + dispc_runtime_put(); return 0; @@ -5678,12 +5692,18 @@ static int dsi_runtime_suspend(struct device *dev) static int dsi_runtime_resume(struct device *dev) { + struct platform_device *pdev = to_platform_device(dev); + struct dsi_data *dsi = dsi_get_dsidrv_data(pdev); int r; r = dispc_runtime_get(); if (r) return r; + dsi->is_enabled = true; + /* ensure the irq handler sees the is_enabled value */ + smp_wmb(); + return 0; } -- cgit v1.2.3-70-g09d2 From a57a22c817fbcb69d41ae517e02933618482f42d Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Fri, 11 Apr 2014 16:25:07 +0300 Subject: OMAPDSS: Take pixelclock unit change into account in hdmi_compute_acr() Pixelclock unit change from kHz to Hz should be taken into account in CTS value calculations in hdmi_compute_acr(). Signed-off-by: Jyri Sarha Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/hdmi_common.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/hdmi_common.c b/drivers/video/omap2/dss/hdmi_common.c index b11afac8e06..0b12a3f62fe 100644 --- a/drivers/video/omap2/dss/hdmi_common.c +++ b/drivers/video/omap2/dss/hdmi_common.c @@ -347,17 +347,17 @@ int hdmi_compute_acr(u32 pclk, u32 sample_freq, u32 *n, u32 *cts) case 96000: case 192000: if (deep_color == 125) - if (pclk == 27027 || pclk == 74250) + if (pclk == 27027000 || pclk == 74250000) deep_color_correct = true; if (deep_color == 150) - if (pclk == 27027) + if (pclk == 27027000) deep_color_correct = true; break; case 44100: case 88200: case 176400: if (deep_color == 125) - if (pclk == 27027) + if (pclk == 27027000) deep_color_correct = true; break; default: @@ -418,7 +418,7 @@ int hdmi_compute_acr(u32 pclk, u32 sample_freq, u32 *n, u32 *cts) } } /* Calculate CTS. See HDMI 1.3a or 1.4a specifications */ - *cts = pclk * (*n / 128) * deep_color / (sample_freq / 10); + *cts = (pclk/1000) * (*n / 128) * deep_color / (sample_freq / 10); return 0; } -- cgit v1.2.3-70-g09d2 From 5c348ba96cdfd2db6a254de259b54cc20fa7d78a Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Fri, 11 Apr 2014 16:25:06 +0300 Subject: OMAPDSS: Change struct reg_field to dispc_reg_field Avoid colision with regmap's struct reg_field definition by renaming omapdss's struct reg_field to dispc_reg_field, and moving it inside dispc.c as that's the only place it is used. Signed-off-by: Jyri Sarha Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dispc.c | 12 +++++++++--- drivers/video/omap2/dss/dss.h | 6 ------ 2 files changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index b37e3fbf60c..f18397c33e8 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -145,12 +145,18 @@ enum mgr_reg_fields { DISPC_MGR_FLD_NUM, }; +struct dispc_reg_field { + u16 reg; + u8 high; + u8 low; +}; + static const struct { const char *name; u32 vsync_irq; u32 framedone_irq; u32 sync_lost_irq; - struct reg_field reg_desc[DISPC_MGR_FLD_NUM]; + struct dispc_reg_field reg_desc[DISPC_MGR_FLD_NUM]; } mgr_desc[] = { [OMAP_DSS_CHANNEL_LCD] = { .name = "LCD", @@ -242,13 +248,13 @@ static inline u32 dispc_read_reg(const u16 idx) static u32 mgr_fld_read(enum omap_channel channel, enum mgr_reg_fields regfld) { - const struct reg_field rfld = mgr_desc[channel].reg_desc[regfld]; + const struct dispc_reg_field rfld = mgr_desc[channel].reg_desc[regfld]; return REG_GET(rfld.reg, rfld.high, rfld.low); } static void mgr_fld_write(enum omap_channel channel, enum mgr_reg_fields regfld, int val) { - const struct reg_field rfld = mgr_desc[channel].reg_desc[regfld]; + const struct dispc_reg_field rfld = mgr_desc[channel].reg_desc[regfld]; REG_FLD_MOD(rfld.reg, val, rfld.high, rfld.low); } diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index 918fec18242..560078fcb19 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -131,12 +131,6 @@ struct dsi_clock_info { u16 lp_clk_div; }; -struct reg_field { - u16 reg; - u8 high; - u8 low; -}; - struct dss_lcd_mgr_config { enum dss_io_pad_mode io_pad_mode; -- cgit v1.2.3-70-g09d2 From 77d149c4eb8964b6bd4a929b102a867505add612 Mon Sep 17 00:00:00 2001 From: Daniel J Blueman Date: Fri, 11 Apr 2014 16:14:26 +0800 Subject: bnx2: Don't build unused suspend/resume functions not enabled When CONFIG_PM_SLEEP isn't enabled, bnx2_suspend/resume are unused; don't build them when they aren't used. Signed-off-by: Daniel J Blueman Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/broadcom/bnx2.c b/drivers/net/ethernet/broadcom/bnx2.c index a8efb18e42f..0ab83708b6a 100644 --- a/drivers/net/ethernet/broadcom/bnx2.c +++ b/drivers/net/ethernet/broadcom/bnx2.c @@ -8627,6 +8627,7 @@ bnx2_remove_one(struct pci_dev *pdev) pci_disable_device(pdev); } +#ifdef CONFIG_PM_SLEEP static int bnx2_suspend(struct device *device) { @@ -8665,7 +8666,6 @@ bnx2_resume(struct device *device) return 0; } -#ifdef CONFIG_PM_SLEEP static SIMPLE_DEV_PM_OPS(bnx2_pm_ops, bnx2_suspend, bnx2_resume); #define BNX2_PM_OPS (&bnx2_pm_ops) -- cgit v1.2.3-70-g09d2 From e1a5ddc5069a0c7589a139e0422200672d965581 Mon Sep 17 00:00:00 2001 From: Amir Vadai Date: Mon, 14 Apr 2014 11:17:22 +0300 Subject: net/mlx4_core: Defer VF initialization till PF is fully initialized Fix in commit [1] is not sufficient since a deferred VF initialization could happen after pci_enable_sriov() is finished, but before the PF is fully initialized. Need to prevent VFs from initializing till the PF is fully ready and comm channel is operational. [1] - 9798935 "net/mlx4_core: mlx4_init_slave() shouldn't access comm channel before PF is ready" CC: Stuart Hayes Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/main.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index 4b86c7af2a7..cef267e24f9 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -2369,10 +2369,10 @@ static int __mlx4_init_one(struct pci_dev *pdev, int pci_dev_data) } else { atomic_inc(&pf_loading); err = pci_enable_sriov(pdev, total_vfs); - atomic_dec(&pf_loading); if (err) { mlx4_err(dev, "Failed to enable SR-IOV, continuing without SR-IOV (err = %d).\n", err); + atomic_dec(&pf_loading); err = 0; } else { mlx4_warn(dev, "Running in master mode\n"); @@ -2532,6 +2532,9 @@ slave_start: priv->removed = 0; + if (mlx4_is_master(dev) && dev->num_vfs) + atomic_dec(&pf_loading); + return 0; err_port: @@ -2582,6 +2585,9 @@ err_rel_own: if (!mlx4_is_slave(dev)) mlx4_free_ownership(dev); + if (mlx4_is_master(dev) && dev->num_vfs) + atomic_dec(&pf_loading); + kfree(priv->dev.dev_vfs); err_free_dev: @@ -2675,6 +2681,7 @@ static void __mlx4_remove_one(struct pci_dev *pdev) if (dev->flags & MLX4_FLAG_SRIOV) { mlx4_warn(dev, "Disabling SR-IOV\n"); pci_disable_sriov(pdev); + dev->num_vfs = 0; } if (!mlx4_is_slave(dev)) -- cgit v1.2.3-70-g09d2 From 5b6241185e2cded07ca3f5f646b55c641928ba4e Mon Sep 17 00:00:00 2001 From: Xiubo Li Date: Tue, 8 Apr 2014 13:48:07 +0800 Subject: of: Fix the section mismatch warnings. In tag next-20140407, building with CONFIG_DEBUG_SECTION_MISMATCH enabled, the following WARNING is occured: WARNING: drivers/built-in.o(.text.unlikely+0x2220): Section mismatch in reference from the function __reserved_mem_check_root() to the function .init.text:of_get_flat_dt_prop() The function __reserved_mem_check_root() references the function __init of_get_flat_dt_prop(). This is often because __reserved_mem_check_root lacks a __init annotation or the annotation of of_get_flat_dt_prop is wrong. WARNING: vmlinux.o(.text.unlikely+0xb9d0): Section mismatch in reference from the function __reserved_mem_check_root() to the (unknown reference) .init.data:(unknown) The function __reserved_mem_check_root() references the (unknown reference) __initdata (unknown). This is often because __reserved_mem_check_root lacks a __initdata annotation or the annotation of (unknown) is wrong. This is cause by : 'drivers: of: add initialization code for dynamic reserved memory'. Signed-off-by: Xiubo Li Signed-off-by: Rob Herring --- drivers/of/fdt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index fa16a912a92..7a2ef7bb802 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -491,7 +491,7 @@ static int __init __reserved_mem_reserve_reg(unsigned long node, * in /reserved-memory matches the values supported by the current implementation, * also check if ranges property has been provided */ -static int __reserved_mem_check_root(unsigned long node) +static int __init __reserved_mem_check_root(unsigned long node) { __be32 *prop; -- cgit v1.2.3-70-g09d2 From 1a3d0717f68345730ae939b74b952200fb165f45 Mon Sep 17 00:00:00 2001 From: Vasundhara Volam Date: Mon, 14 Apr 2014 16:12:40 +0530 Subject: be2net: Fix to reap TX compls till HW doesn't respond for some time be_close() currently waits for a max of 200ms to receive all pending TX compls. This timeout value was roughly calculated based on 10G transmission speeds and the TX queue depth. This timeout may not be enough when the link is operating at lower speeds or in multi-channel/SR-IOV configs with TX-rate limiting setting. It is hard to calculate a "proper timeout value" that works in all configurations. This patch solves this problem by continuing to reap TX completions till the HW is completely silent for a period of 10ms or a HW error is detected. v2: implements the new scheme (as suggested by David Laight) instead of just waiting longer than 200ms for reaping all completions. Signed-off-by: Vasundhara Volam Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_main.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 3e6df47b697..80f754d7cf6 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -2033,11 +2033,13 @@ static void be_tx_compl_clean(struct be_adapter *adapter) bool dummy_wrb; int i, pending_txqs; - /* Wait for a max of 200ms for all the tx-completions to arrive. */ + /* Stop polling for compls when HW has been silent for 10ms */ do { pending_txqs = adapter->num_tx_qs; for_all_tx_queues(adapter, txo, i) { + cmpl = 0; + num_wrbs = 0; txq = &txo->q; while ((txcp = be_tx_compl_get(&txo->cq))) { end_idx = @@ -2050,14 +2052,13 @@ static void be_tx_compl_clean(struct be_adapter *adapter) if (cmpl) { be_cq_notify(adapter, txo->cq.id, false, cmpl); atomic_sub(num_wrbs, &txq->used); - cmpl = 0; - num_wrbs = 0; + timeo = 0; } if (atomic_read(&txq->used) == 0) pending_txqs--; } - if (pending_txqs == 0 || ++timeo > 200) + if (pending_txqs == 0 || ++timeo > 10 || be_hw_error(adapter)) break; mdelay(1); -- cgit v1.2.3-70-g09d2 From e1ad8e33d2e57ca64d9862b63d986fc296a7b876 Mon Sep 17 00:00:00 2001 From: Kalesh AP Date: Mon, 14 Apr 2014 16:12:41 +0530 Subject: be2net: Fix invocation of be_close() after be_clear() In the EEH error recovery path, when a permanent failure occurs, we clean up adapter structure (i.e. destroy queues etc) by calling be_clear() and return PCI_ERS_RESULT_DISCONNECT. After this the stack tries to remove device from bus and calls be_remove() which invokes netdev_unregister()->be_close(). be_close() operating on destroyed queues results in a NULL dereference. This patch fixes this problem by introducing a flag to keep track of the setup state. Signed-off-by: Kalesh AP Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be.h | 1 + drivers/net/ethernet/emulex/benet/be_main.c | 8 ++++++++ 2 files changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h index 8ccaa2520dc..97db5a7179d 100644 --- a/drivers/net/ethernet/emulex/benet/be.h +++ b/drivers/net/ethernet/emulex/benet/be.h @@ -374,6 +374,7 @@ enum vf_state { #define BE_FLAGS_NAPI_ENABLED (1 << 9) #define BE_FLAGS_QNQ_ASYNC_EVT_RCVD (1 << 11) #define BE_FLAGS_VXLAN_OFFLOADS (1 << 12) +#define BE_FLAGS_SETUP_DONE (1 << 13) #define BE_UC_PMAC_COUNT 30 #define BE_VF_UC_PMAC_COUNT 2 diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 80f754d7cf6..a18645407d2 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -2726,6 +2726,12 @@ static int be_close(struct net_device *netdev) struct be_eq_obj *eqo; int i; + /* This protection is needed as be_close() may be called even when the + * adapter is in cleared state (after eeh perm failure) + */ + if (!(adapter->flags & BE_FLAGS_SETUP_DONE)) + return 0; + be_roce_dev_close(adapter); if (adapter->flags & BE_FLAGS_NAPI_ENABLED) { @@ -3056,6 +3062,7 @@ static int be_clear(struct be_adapter *adapter) be_clear_queues(adapter); be_msix_disable(adapter); + adapter->flags &= ~BE_FLAGS_SETUP_DONE; return 0; } @@ -3560,6 +3567,7 @@ static int be_setup(struct be_adapter *adapter) adapter->phy.fc_autoneg = 1; be_schedule_worker(adapter); + adapter->flags |= BE_FLAGS_SETUP_DONE; return 0; err: be_clear(adapter); -- cgit v1.2.3-70-g09d2 From 463518a0cbd396aac83ee3d196897d585e173796 Mon Sep 17 00:00:00 2001 From: Sucheta Chakraborty Date: Mon, 14 Apr 2014 10:02:18 -0400 Subject: qlcnic: Fix panic due to uninitialzed delayed_work struct in use. o AEN event was being received before initializing delayed_work struct and handlers for it. This was resulting in crash. This patch fixes it. Signed-off-by: Sucheta Chakraborty Signed-off-by: Shahed Shaikh Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c index b48737dcd3c..d211af70c7e 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c @@ -2348,14 +2348,13 @@ int qlcnic_83xx_init(struct qlcnic_adapter *adapter, int pci_using_dac) goto disable_intr; } + INIT_DELAYED_WORK(&adapter->idc_aen_work, qlcnic_83xx_idc_aen_work); + err = qlcnic_83xx_setup_mbx_intr(adapter); if (err) goto disable_mbx_intr; qlcnic_83xx_clear_function_resources(adapter); - - INIT_DELAYED_WORK(&adapter->idc_aen_work, qlcnic_83xx_idc_aen_work); - qlcnic_83xx_initialize_nic(adapter, 1); /* Configure default, SR-IOV or Virtual NIC mode of operation */ -- cgit v1.2.3-70-g09d2 From 4d52e1e8d1e198962dcbfabf9c06425c38eb23d0 Mon Sep 17 00:00:00 2001 From: Sucheta Chakraborty Date: Mon, 14 Apr 2014 10:02:19 -0400 Subject: qlcnic: Fix to send INIT_NIC_FUNC as first mailbox. o INIT_NIC_FUNC should be first mailbox sent. Sending DCB capability and parameter query commands after that command. Signed-off-by: Sucheta Chakraborty Signed-off-by: Shahed Shaikh Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c | 2 ++ drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.c | 2 -- drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c | 5 +++-- 3 files changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c index d211af70c7e..3ca3118efb3 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c @@ -2355,7 +2355,9 @@ int qlcnic_83xx_init(struct qlcnic_adapter *adapter, int pci_using_dac) goto disable_mbx_intr; qlcnic_83xx_clear_function_resources(adapter); + qlcnic_dcb_enable(adapter->dcb); qlcnic_83xx_initialize_nic(adapter, 1); + qlcnic_dcb_get_info(adapter->dcb); /* Configure default, SR-IOV or Virtual NIC mode of operation */ err = qlcnic_83xx_configure_opmode(adapter); diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.c index 7d4f54912ba..a51fe18f09a 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.c @@ -330,8 +330,6 @@ static int __qlcnic_dcb_attach(struct qlcnic_dcb *dcb) goto out_free_cfg; } - qlcnic_dcb_get_info(dcb); - return 0; out_free_cfg: kfree(dcb->cfg); diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c index 309d0564088..84d011ed7ec 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c @@ -2528,8 +2528,6 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_out_free_hw; } - qlcnic_dcb_enable(adapter->dcb); - if (qlcnic_read_mac_addr(adapter)) dev_warn(&pdev->dev, "failed to read mac addr\n"); @@ -2549,7 +2547,10 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) "Device does not support MSI interrupts\n"); if (qlcnic_82xx_check(adapter)) { + qlcnic_dcb_enable(adapter->dcb); + qlcnic_dcb_get_info(adapter->dcb); err = qlcnic_setup_intr(adapter); + if (err) { dev_err(&pdev->dev, "Failed to setup interrupt\n"); goto err_out_disable_msi; -- cgit v1.2.3-70-g09d2 From 7b546842b1e87f5b7929cf15e9cd1ac861b14de3 Mon Sep 17 00:00:00 2001 From: Shahed Shaikh Date: Mon, 14 Apr 2014 10:02:20 -0400 Subject: qlcnic: Fix max ring count calculation Do not read max rings count from qlcnic_get_nic_info(). Use driver defined values for 82xx adapters. In case of 83xx adapters, use minimum of firmware provided and driver defined values. Signed-off-by: Shahed Shaikh Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c | 14 ++++++++------ drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c | 2 -- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c index 3ca3118efb3..ba20c721ee9 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c @@ -2139,8 +2139,6 @@ static int qlcnic_83xx_get_nic_configuration(struct qlcnic_adapter *adapter) ahw->max_mac_filters = nic_info.max_mac_filters; ahw->max_mtu = nic_info.max_mtu; - adapter->max_tx_rings = ahw->max_tx_ques; - adapter->max_sds_rings = ahw->max_rx_ques; /* eSwitch capability indicates vNIC mode. * vNIC and SRIOV are mutually exclusive operational modes. * If SR-IOV capability is detected, SR-IOV physical function @@ -2161,6 +2159,7 @@ static int qlcnic_83xx_get_nic_configuration(struct qlcnic_adapter *adapter) int qlcnic_83xx_configure_opmode(struct qlcnic_adapter *adapter) { struct qlcnic_hardware_context *ahw = adapter->ahw; + u16 max_sds_rings, max_tx_rings; int ret; ret = qlcnic_83xx_get_nic_configuration(adapter); @@ -2173,18 +2172,21 @@ int qlcnic_83xx_configure_opmode(struct qlcnic_adapter *adapter) if (qlcnic_83xx_config_vnic_opmode(adapter)) return -EIO; - adapter->max_sds_rings = QLCNIC_MAX_VNIC_SDS_RINGS; - adapter->max_tx_rings = QLCNIC_MAX_VNIC_TX_RINGS; + max_sds_rings = QLCNIC_MAX_VNIC_SDS_RINGS; + max_tx_rings = QLCNIC_MAX_VNIC_TX_RINGS; } else if (ret == QLC_83XX_DEFAULT_OPMODE) { ahw->nic_mode = QLCNIC_DEFAULT_MODE; adapter->nic_ops->init_driver = qlcnic_83xx_init_default_driver; ahw->idc.state_entry = qlcnic_83xx_idc_ready_state_entry; - adapter->max_sds_rings = QLCNIC_MAX_SDS_RINGS; - adapter->max_tx_rings = QLCNIC_MAX_TX_RINGS; + max_sds_rings = QLCNIC_MAX_SDS_RINGS; + max_tx_rings = QLCNIC_MAX_TX_RINGS; } else { return -EIO; } + adapter->max_sds_rings = min(ahw->max_rx_ques, max_sds_rings); + adapter->max_tx_rings = min(ahw->max_tx_ques, max_tx_rings); + return 0; } diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c index 64dcbf33d8f..a81ad5088b0 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c @@ -883,8 +883,6 @@ int qlcnic_82xx_get_nic_info(struct qlcnic_adapter *adapter, npar_info->max_rx_ques = le16_to_cpu(nic_info->max_rx_ques); npar_info->capabilities = le32_to_cpu(nic_info->capabilities); npar_info->max_mtu = le16_to_cpu(nic_info->max_mtu); - adapter->max_tx_rings = npar_info->max_tx_ques; - adapter->max_sds_rings = npar_info->max_rx_ques; } qlcnic_free_mbx_args(&cmd); -- cgit v1.2.3-70-g09d2 From a78b6da89f52d03997619f5a78a5325bec865977 Mon Sep 17 00:00:00 2001 From: Jitendra Kalsaria Date: Mon, 14 Apr 2014 10:02:21 -0400 Subject: qlcnic: Fix PVID configuration on eSwitch port. Clear older PVID before adding a newer PVID to the eSwicth port Signed-off-by: Jitendra Kalsaria Signed-off-by: Shahed Shaikh Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c index a81ad5088b0..c1e11f5715b 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c @@ -1354,6 +1354,7 @@ int qlcnic_config_switch_port(struct qlcnic_adapter *adapter, arg2 &= ~BIT_3; break; case QLCNIC_ADD_VLAN: + arg1 &= ~(0x0ffff << 16); arg1 |= (BIT_2 | BIT_5); arg1 |= (esw_cfg->vlan_id << 16); break; -- cgit v1.2.3-70-g09d2 From 4f0302277718810494f8c618f28d1edb33af859a Mon Sep 17 00:00:00 2001 From: Jitendra Kalsaria Date: Mon, 14 Apr 2014 10:02:22 -0400 Subject: qlcnic: Fix QLogic application/driver interface for virtual NIC configuration o Application expect vNIC number as the array index but driver interface return configuration in array index form. o Pack the vNIC information array in the buffer such that application can access it using vNIC number as the array index. Signed-off-by: Jitendra Kalsaria Signed-off-by: Shahed Shaikh Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c | 31 +++++++++++++---------- 1 file changed, 17 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c index 448d156c3d0..cd346e27f2e 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c @@ -354,7 +354,7 @@ int qlcnic_is_valid_nic_func(struct qlcnic_adapter *adapter, u8 pci_func) { int i; - for (i = 0; i < adapter->ahw->max_vnic_func; i++) { + for (i = 0; i < adapter->ahw->total_nic_func; i++) { if (adapter->npars[i].pci_func == pci_func) return i; } @@ -720,6 +720,7 @@ static ssize_t qlcnic_sysfs_read_npar_config(struct file *file, struct qlcnic_adapter *adapter = dev_get_drvdata(dev); struct qlcnic_npar_func_cfg *np_cfg; struct qlcnic_info nic_info; + u8 pci_func; int i, ret; u32 count; @@ -729,26 +730,28 @@ static ssize_t qlcnic_sysfs_read_npar_config(struct file *file, count = size / sizeof(struct qlcnic_npar_func_cfg); for (i = 0; i < adapter->ahw->total_nic_func; i++) { - if (qlcnic_is_valid_nic_func(adapter, i) < 0) - continue; if (adapter->npars[i].pci_func >= count) { dev_dbg(dev, "%s: Total nic functions[%d], App sent function count[%d]\n", __func__, adapter->ahw->total_nic_func, count); continue; } - ret = qlcnic_get_nic_info(adapter, &nic_info, i); - if (ret) - return ret; if (!adapter->npars[i].eswitch_status) continue; - np_cfg[i].pci_func = i; - np_cfg[i].op_mode = (u8)nic_info.op_mode; - np_cfg[i].port_num = nic_info.phys_port; - np_cfg[i].fw_capab = nic_info.capabilities; - np_cfg[i].min_bw = nic_info.min_tx_bw; - np_cfg[i].max_bw = nic_info.max_tx_bw; - np_cfg[i].max_tx_queues = nic_info.max_tx_ques; - np_cfg[i].max_rx_queues = nic_info.max_rx_ques; + pci_func = adapter->npars[i].pci_func; + if (qlcnic_is_valid_nic_func(adapter, pci_func) < 0) + continue; + ret = qlcnic_get_nic_info(adapter, &nic_info, pci_func); + if (ret) + return ret; + + np_cfg[pci_func].pci_func = pci_func; + np_cfg[pci_func].op_mode = (u8)nic_info.op_mode; + np_cfg[pci_func].port_num = nic_info.phys_port; + np_cfg[pci_func].fw_capab = nic_info.capabilities; + np_cfg[pci_func].min_bw = nic_info.min_tx_bw; + np_cfg[pci_func].max_bw = nic_info.max_tx_bw; + np_cfg[pci_func].max_tx_queues = nic_info.max_tx_ques; + np_cfg[pci_func].max_rx_queues = nic_info.max_rx_ques; } return size; } -- cgit v1.2.3-70-g09d2 From 696f1943a1538bb448c5bf55a18793ad410da00b Mon Sep 17 00:00:00 2001 From: Manish Chopra Date: Mon, 14 Apr 2014 10:02:23 -0400 Subject: qlcnic: Do not disable SR-IOV when VFs are assigned to VMs o While disabling SR-IOV when VFs are assigned to VMs causes host crash so return -EPERM when user request to disable SR-IOV using pci sysfs in case of VFs are assigned to VMs. Signed-off-by: Manish Chopra Signed-off-by: Shahed Shaikh Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c index 14f748cbf0d..28013799154 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c @@ -461,6 +461,16 @@ static int qlcnic_pci_sriov_disable(struct qlcnic_adapter *adapter) { struct net_device *netdev = adapter->netdev; + if (pci_vfs_assigned(adapter->pdev)) { + netdev_err(adapter->netdev, + "SR-IOV VFs belonging to port %d are assigned to VMs. SR-IOV can not be disabled on this port\n", + adapter->portnum); + netdev_info(adapter->netdev, + "Please detach SR-IOV VFs belonging to port %d from VMs, and then try to disable SR-IOV on this port\n", + adapter->portnum); + return -EPERM; + } + rtnl_lock(); if (netif_running(netdev)) __qlcnic_down(adapter, netdev); -- cgit v1.2.3-70-g09d2 From 151eea367c720db8a0768caf47894c32991aa02a Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Mon, 14 Apr 2014 18:01:47 +0200 Subject: pata_arasan_cf: fix ata_host_activate() failure handling Add missing cf_exit() and clk_put() calls to ata_host_activate() failure path. Cc: Viresh Kumar Cc: Shiraz Hashim Signed-off-by: Bartlomiej Zolnierkiewicz Acked-by: Viresh Kumar Signed-off-by: Tejun Heo --- drivers/ata/pata_arasan_cf.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/pata_arasan_cf.c b/drivers/ata/pata_arasan_cf.c index 6fac524c2f5..4edb1a81f63 100644 --- a/drivers/ata/pata_arasan_cf.c +++ b/drivers/ata/pata_arasan_cf.c @@ -898,9 +898,12 @@ static int arasan_cf_probe(struct platform_device *pdev) cf_card_detect(acdev, 0); - return ata_host_activate(host, acdev->irq, irq_handler, 0, - &arasan_cf_sht); + ret = ata_host_activate(host, acdev->irq, irq_handler, 0, + &arasan_cf_sht); + if (!ret) + return 0; + cf_exit(acdev); free_clk: clk_put(acdev->clk); return ret; -- cgit v1.2.3-70-g09d2 From af64dc7474a43fb653255ecf8ae879c8227feab2 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Sun, 6 Apr 2014 15:30:39 +0200 Subject: rsi: Add missing initialization of ii MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/net/wireless/rsi/rsi_91x_core.c: In function ‘rsi_core_determine_hal_queue’: drivers/net/wireless/rsi/rsi_91x_core.c:91: warning: ‘ii’ may be used uninitialized in this function Signed-off-by: Geert Uytterhoeven Signed-off-by: John W. Linville --- drivers/net/wireless/rsi/rsi_91x_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rsi/rsi_91x_core.c b/drivers/net/wireless/rsi/rsi_91x_core.c index 1a8d3213859..cf61d6e3eaa 100644 --- a/drivers/net/wireless/rsi/rsi_91x_core.c +++ b/drivers/net/wireless/rsi/rsi_91x_core.c @@ -88,7 +88,7 @@ static u8 rsi_core_determine_hal_queue(struct rsi_common *common) bool recontend_queue = false; u32 q_len = 0; u8 q_num = INVALID_QUEUE; - u8 ii, min = 0; + u8 ii = 0, min = 0; if (skb_queue_len(&common->tx_queue[MGMT_SOFT_Q])) { if (!common->mgmt_q_block) -- cgit v1.2.3-70-g09d2 From 98ddcbe03366c19b6da9b75a00f9c8d0a7c2dc6d Mon Sep 17 00:00:00 2001 From: Christian Engelmayer Date: Wed, 9 Apr 2014 21:28:54 +0200 Subject: rsi: Fix a potential memory leak in rsi_set_channel() Fix a potential memory leak in function rsi_set_channel() that is used to program channel changes. The channel check block for the frequency bands directly exits the function in case of an error, thus leaving an already allocated skb unreferenced. Move the checks above allocating the skb. Detected by Coverity: CID 1195576. Signed-off-by: Christian Engelmayer Signed-off-by: John W. Linville --- drivers/net/wireless/rsi/rsi_91x_mgmt.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c index 73694295648..3a030b9d0fe 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c +++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c @@ -841,16 +841,6 @@ int rsi_set_channel(struct rsi_common *common, u16 channel) rsi_dbg(MGMT_TX_ZONE, "%s: Sending scan req frame\n", __func__); - skb = dev_alloc_skb(FRAME_DESC_SZ); - if (!skb) { - rsi_dbg(ERR_ZONE, "%s: Failed in allocation of skb\n", - __func__); - return -ENOMEM; - } - - memset(skb->data, 0, FRAME_DESC_SZ); - mgmt_frame = (struct rsi_mac_frame *)skb->data; - if (common->band == IEEE80211_BAND_5GHZ) { if ((channel >= 36) && (channel <= 64)) channel = ((channel - 32) / 4); @@ -868,6 +858,16 @@ int rsi_set_channel(struct rsi_common *common, u16 channel) } } + skb = dev_alloc_skb(FRAME_DESC_SZ); + if (!skb) { + rsi_dbg(ERR_ZONE, "%s: Failed in allocation of skb\n", + __func__); + return -ENOMEM; + } + + memset(skb->data, 0, FRAME_DESC_SZ); + mgmt_frame = (struct rsi_mac_frame *)skb->data; + mgmt_frame->desc_word[0] = cpu_to_le16(RSI_WIFI_MGMT_Q << 12); mgmt_frame->desc_word[1] = cpu_to_le16(SCAN_REQUEST); mgmt_frame->desc_word[4] = cpu_to_le16(channel); -- cgit v1.2.3-70-g09d2 From 69aa167583a9e6d36ac1957c0bc51136c7a770fa Mon Sep 17 00:00:00 2001 From: Luciano Coelho Date: Thu, 10 Apr 2014 10:01:37 +0300 Subject: wlcore: ignore dummy packet events in PLT mode Sometimes the firmware sends a dummy packet event while we are in PLT mode. This doesn't make sense, it's a firmware bug. Fix this by ignoring dummy packet events when we're PLT mode. Reported-by: Yegor Yefremov Reported-by: Arik Nemtsov Signed-off-by: Luciano Coelho Signed-off-by: John W. Linville --- drivers/net/wireless/ti/wlcore/event.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ti/wlcore/event.c b/drivers/net/wireless/ti/wlcore/event.c index 1f9a36031b0..16d10281798 100644 --- a/drivers/net/wireless/ti/wlcore/event.c +++ b/drivers/net/wireless/ti/wlcore/event.c @@ -158,6 +158,11 @@ EXPORT_SYMBOL_GPL(wlcore_event_channel_switch); void wlcore_event_dummy_packet(struct wl1271 *wl) { + if (wl->plt) { + wl1271_info("Got DUMMY_PACKET event in PLT mode. FW bug, ignoring."); + return; + } + wl1271_debug(DEBUG_EVENT, "DUMMY_PACKET_ID_EVENT_ID"); wl1271_tx_dummy_packet(wl); } -- cgit v1.2.3-70-g09d2 From 2004dabaac4104e9aa067e3fe9326d3958b27ca1 Mon Sep 17 00:00:00 2001 From: Frederic Danis Date: Thu, 10 Apr 2014 11:36:38 +0200 Subject: cw1200: Fix cw1200_debug_link_id This array is used in debug string to display cw1200_link_status defined in drivers/net/wireless/cw1200/cw1200.h. Add missing strings for CW1200_LINK_RESET and CW1200_LINK_RESET_REMAP. Signed-off-by: Frederic Danis Signed-off-by: John W. Linville --- drivers/net/wireless/cw1200/debug.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/cw1200/debug.c b/drivers/net/wireless/cw1200/debug.c index e323b4d5433..34f97c31eec 100644 --- a/drivers/net/wireless/cw1200/debug.c +++ b/drivers/net/wireless/cw1200/debug.c @@ -41,6 +41,8 @@ static const char * const cw1200_debug_link_id[] = { "REQ", "SOFT", "HARD", + "RESET", + "RESET_REMAP", }; static const char *cw1200_debug_mode(int mode) -- cgit v1.2.3-70-g09d2 From 61698b7e222c33e1d38996519b38dd34cbcb8634 Mon Sep 17 00:00:00 2001 From: Christian Engelmayer Date: Thu, 10 Apr 2014 20:37:53 +0200 Subject: rsi: Fix a potential memory leak in rsi_send_auto_rate_request() Fix a potential memory leak in the error path of function rsi_send_auto_rate_request(). In case memory allocation for array 'selected_rates' fails, the error path exits and leaves the previously allocated skb in place. Detected by Coverity: CID 1195575. Signed-off-by: Christian Engelmayer Signed-off-by: John W. Linville --- drivers/net/wireless/rsi/rsi_91x_mgmt.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c index 3a030b9d0fe..1b28cda6ca8 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c +++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c @@ -966,6 +966,7 @@ static int rsi_send_auto_rate_request(struct rsi_common *common) if (!selected_rates) { rsi_dbg(ERR_ZONE, "%s: Failed in allocation of mem\n", __func__); + dev_kfree_skb(skb); return -ENOMEM; } -- cgit v1.2.3-70-g09d2 From c0da71ff4d2cbf113465bff9a7c413154be25a89 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Sun, 13 Apr 2014 16:33:51 +0300 Subject: wl18xx: align event mailbox with current fw Some fields are missing from the event mailbox struct definitions, which cause issues when trying to handle some events. Add the missing fields in order to align the struct size (without adding actual support for the new fields). Reported-and-tested-by: Imre Kaloz Cc: stable@vger.kernel.org # 3.14+ Fixes: 028e724 ("wl18xx: move to new firmware (wl18xx-fw-3.bin)") Signed-off-by: Eliad Peller Signed-off-by: John W. Linville --- drivers/net/wireless/ti/wl18xx/event.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'drivers') diff --git a/drivers/net/wireless/ti/wl18xx/event.h b/drivers/net/wireless/ti/wl18xx/event.h index 398f3d2c0a6..a76e98eb837 100644 --- a/drivers/net/wireless/ti/wl18xx/event.h +++ b/drivers/net/wireless/ti/wl18xx/event.h @@ -68,6 +68,26 @@ struct wl18xx_event_mailbox { /* bitmap of inactive stations (by HLID) */ __le32 inactive_sta_bitmap; + + /* rx BA win size indicated by RX_BA_WIN_SIZE_CHANGE_EVENT_ID */ + u8 rx_ba_role_id; + u8 rx_ba_link_id; + u8 rx_ba_win_size; + u8 padding; + + /* smart config */ + u8 sc_ssid_len; + u8 sc_pwd_len; + u8 sc_token_len; + u8 padding1; + u8 sc_ssid[32]; + u8 sc_pwd[32]; + u8 sc_token[32]; + + /* smart config sync channel */ + u8 sc_sync_channel; + u8 sc_sync_band; + u8 padding2[2]; } __packed; int wl18xx_wait_for_event(struct wl1271 *wl, enum wlcore_wait_event event, -- cgit v1.2.3-70-g09d2 From e8304d04ac88c21b2a68d189f01678d71479a803 Mon Sep 17 00:00:00 2001 From: Steven Miao Date: Sat, 12 Apr 2014 09:23:24 +0800 Subject: spi: bfin5xx: fix build error should include linux/gpio.h Signed-off-by: Steven Miao Signed-off-by: Mark Brown --- drivers/spi/spi-bfin5xx.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/spi/spi-bfin5xx.c b/drivers/spi/spi-bfin5xx.c index 55e57c3eb9b..ebf720b88a2 100644 --- a/drivers/spi/spi-bfin5xx.c +++ b/drivers/spi/spi-bfin5xx.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include -- cgit v1.2.3-70-g09d2 From 818e91625aa17161cd6b39a4d08b77c984f0f485 Mon Sep 17 00:00:00 2001 From: Qipan Li Date: Mon, 14 Apr 2014 14:29:57 +0800 Subject: spi: sirf: correct TXFIFO empty interrupt status bit the old code uses wrong marco - SIRFSOC_SPI_FIFO_FULL is not for FIFO interrupt status, it is for FIFO status. here in the ISR, SIRFSOC_SPI_TXFIFO_EMPTY is the right bit for SPI TXFIFO interrupt status. Signed-off-by: Qipan Li Signed-off-by: Barry Song Signed-off-by: Mark Brown --- drivers/spi/spi-sirf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-sirf.c b/drivers/spi/spi-sirf.c index 1a77ad52812..51d7c988d3a 100644 --- a/drivers/spi/spi-sirf.c +++ b/drivers/spi/spi-sirf.c @@ -287,8 +287,8 @@ static irqreturn_t spi_sirfsoc_irq(int irq, void *dev_id) sspi->left_rx_word) sspi->rx_word(sspi); - if (spi_stat & (SIRFSOC_SPI_FIFO_EMPTY - | SIRFSOC_SPI_TXFIFO_THD_REACH)) + if (spi_stat & (SIRFSOC_SPI_TXFIFO_EMPTY | + SIRFSOC_SPI_TXFIFO_THD_REACH)) while (!((readl(sspi->base + SIRFSOC_SPI_TXFIFO_STATUS) & SIRFSOC_SPI_FIFO_FULL)) && sspi->left_tx_word) -- cgit v1.2.3-70-g09d2 From 625227a4e916fa87f1dd84bde518ef403c3f708a Mon Sep 17 00:00:00 2001 From: Qipan Li Date: Mon, 14 Apr 2014 14:29:58 +0800 Subject: spi: sirf: set SPI controller in RISC IO chipselect mode SPI bitbang supply "chipselect" interface for change chip-select line , in the SiRFSoC SPI controller, we need to enable "SPI_CS_IO_MODE", otherwise, spi_sirfsoc_chipselect() has no effect. now the driver is working is because SPI controller will control CS automatically without SPI_CS_IO_MODE. this patch makes the CS controller really controlled by software. Signed-off-by: Qipan Li Signed-off-by: Barry Song Signed-off-by: Mark Brown --- drivers/spi/spi-sirf.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/spi/spi-sirf.c b/drivers/spi/spi-sirf.c index 51d7c988d3a..9b30743d816 100644 --- a/drivers/spi/spi-sirf.c +++ b/drivers/spi/spi-sirf.c @@ -559,6 +559,11 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t) regval &= ~SIRFSOC_SPI_CMD_MODE; sspi->tx_by_cmd = false; } + /* + * set spi controller in RISC chipselect mode, we are controlling CS by + * software BITBANG_CS_ACTIVE and BITBANG_CS_INACTIVE. + */ + regval |= SIRFSOC_SPI_CS_IO_MODE; writel(regval, sspi->base + SIRFSOC_SPI_CTRL); if (IS_DMA_VALID(t)) { -- cgit v1.2.3-70-g09d2 From 6ee8a2f7d5e78700b6e64799b5e9976b21cfad79 Mon Sep 17 00:00:00 2001 From: Qipan Li Date: Mon, 14 Apr 2014 14:29:59 +0800 Subject: spi: sirf: make GPIO chipselect function work well orignal GPIO chipslect is not standard because it don't take care to the chipselect signal: BITBANG_CS_ACTIVE and BITBANG_CS_INACTIVE. Signed-off-by: Qipan Li Signed-off-by: Barry Song Signed-off-by: Mark Brown --- drivers/spi/spi-sirf.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/spi/spi-sirf.c b/drivers/spi/spi-sirf.c index 9b30743d816..67d8909dcf3 100644 --- a/drivers/spi/spi-sirf.c +++ b/drivers/spi/spi-sirf.c @@ -470,7 +470,16 @@ static void spi_sirfsoc_chipselect(struct spi_device *spi, int value) writel(regval, sspi->base + SIRFSOC_SPI_CTRL); } else { int gpio = sspi->chipselect[spi->chip_select]; - gpio_direction_output(gpio, spi->mode & SPI_CS_HIGH ? 0 : 1); + switch (value) { + case BITBANG_CS_ACTIVE: + gpio_direction_output(gpio, + spi->mode & SPI_CS_HIGH ? 1 : 0); + break; + case BITBANG_CS_INACTIVE: + gpio_direction_output(gpio, + spi->mode & SPI_CS_HIGH ? 0 : 1); + break; + } } } -- cgit v1.2.3-70-g09d2 From 4a4dd7d80e11f62cacf49bd90d9448a218188af7 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Mon, 14 Apr 2014 10:41:38 +0900 Subject: spi: sh-hspi: Do not specifically request shyway_clk clock Rather than requesting the shyway_clk call clk_get with the device and a NULL con_id. This is in keeping with the way that clk_get() is called on other drivers used by Renesas Gen 1 SoCs. And I believe it is compatible with supplying clocks via DT, unlike the current code. It appears to me that the two uses of this driver are the r8a7778 and r8a7779 SoCs. The r8a7779 already has clocks setup to allow this driver to continue to work with this change applied. The r8a7778 has clocks incorrectly setup to allow this driver to continue to work with this change applied. This problem is addressed in "ARM: shmobile: r8a7778: Use clks as MSTP007 parent" which is thus a pre-requisite of this patch. Signed-off-by: Simon Horman Signed-off-by: Mark Brown --- drivers/spi/spi-sh-hspi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-sh-hspi.c b/drivers/spi/spi-sh-hspi.c index 9009456bdf4..c8e795ef2e1 100644 --- a/drivers/spi/spi-sh-hspi.c +++ b/drivers/spi/spi-sh-hspi.c @@ -244,9 +244,9 @@ static int hspi_probe(struct platform_device *pdev) return -ENOMEM; } - clk = clk_get(NULL, "shyway_clk"); + clk = clk_get(&pdev->dev, NULL); if (IS_ERR(clk)) { - dev_err(&pdev->dev, "shyway_clk is required\n"); + dev_err(&pdev->dev, "couldn't get clock\n"); ret = -EINVAL; goto error0; } -- cgit v1.2.3-70-g09d2 From bfae23249955819a42aa6c23d93708c818eff5c9 Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Mon, 14 Apr 2014 14:22:43 -0500 Subject: cxgb4: Save the correct mac addr for hw-loopback connections in the L2T Hardware needs the local device mac address to support hw loopback for rdma loopback connections. Signed-off-by: Steve Wise Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/l2t.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/chelsio/cxgb4/l2t.c b/drivers/net/ethernet/chelsio/cxgb4/l2t.c index 81e8402a74b..8a96572fdde 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/l2t.c +++ b/drivers/net/ethernet/chelsio/cxgb4/l2t.c @@ -154,7 +154,7 @@ static int write_l2e(struct adapter *adap, struct l2t_entry *e, int sync) req->params = htons(L2T_W_PORT(e->lport) | L2T_W_NOREPLY(!sync)); req->l2t_idx = htons(e->idx); req->vlan = htons(e->vlan); - if (e->neigh) + if (e->neigh && !(e->neigh->dev->flags & IFF_LOOPBACK)) memcpy(e->dmac, e->neigh->ha, sizeof(e->dmac)); memcpy(req->dst_mac, e->dmac, sizeof(req->dst_mac)); @@ -394,6 +394,8 @@ struct l2t_entry *cxgb4_l2t_get(struct l2t_data *d, struct neighbour *neigh, if (e) { spin_lock(&e->lock); /* avoid race with t4_l2t_free */ e->state = L2T_STATE_RESOLVING; + if (neigh->dev->flags & IFF_LOOPBACK) + memcpy(e->dmac, physdev->dev_addr, sizeof(e->dmac)); memcpy(e->addr, addr, addr_len); e->ifindex = ifidx; e->hash = hash; -- cgit v1.2.3-70-g09d2 From 1cb7b43f6796ad0bc62669fa52d1005916911d27 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 8 Mar 2014 11:55:29 +0800 Subject: regulator: pbias: Fix is_enabled callback implementation The is_enabled implementation is wrong in some cases: e.g. for pbias_mmc_omap5: enable_mask is : BIT(27) | BIT(25) | BIT(26) However, pbias_regulator_enable() only sets BIT(27) | BIT(26) bits. So is_enabled callback will always return false in this case. Fix the logic to compare the register value with info->enable rather than info->enable_mask. Signed-off-by: Axel Lin Acked-by: Balaji T K Signed-off-by: Mark Brown --- drivers/regulator/pbias-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/regulator/pbias-regulator.c b/drivers/regulator/pbias-regulator.c index ded3b357420..d89a1d8615c 100644 --- a/drivers/regulator/pbias-regulator.c +++ b/drivers/regulator/pbias-regulator.c @@ -108,7 +108,7 @@ static int pbias_regulator_is_enable(struct regulator_dev *rdev) regmap_read(data->syscon, data->pbias_reg, &value); - return (value & info->enable_mask) == info->enable_mask; + return (value & info->enable_mask) == info->enable; } static struct regulator_ops pbias_regulator_voltage_ops = { -- cgit v1.2.3-70-g09d2 From 60e8c1e34d3ab74556fb9b25f26fa34b9879ee30 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 8 Mar 2014 11:56:47 +0800 Subject: regulator: pbias: Convert to use regmap helper functions This patch converts this driver to use the regmap helper functions provided by regulator core. Signed-off-by: Axel Lin Acked-by: Balaji T K Signed-off-by: Mark Brown --- drivers/regulator/pbias-regulator.c | 74 ++++++++++--------------------------- 1 file changed, 19 insertions(+), 55 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/pbias-regulator.c b/drivers/regulator/pbias-regulator.c index d89a1d8615c..6d38be3d970 100644 --- a/drivers/regulator/pbias-regulator.c +++ b/drivers/regulator/pbias-regulator.c @@ -38,66 +38,24 @@ struct pbias_reg_info { struct pbias_regulator_data { struct regulator_desc desc; void __iomem *pbias_addr; - unsigned int pbias_reg; struct regulator_dev *dev; struct regmap *syscon; const struct pbias_reg_info *info; int voltage; }; -static int pbias_regulator_set_voltage(struct regulator_dev *dev, - int min_uV, int max_uV, unsigned *selector) -{ - struct pbias_regulator_data *data = rdev_get_drvdata(dev); - const struct pbias_reg_info *info = data->info; - int ret, vmode; - - if (min_uV <= 1800000) - vmode = 0; - else if (min_uV > 1800000) - vmode = info->vmode; - - ret = regmap_update_bits(data->syscon, data->pbias_reg, - info->vmode, vmode); - - return ret; -} - -static int pbias_regulator_get_voltage(struct regulator_dev *rdev) -{ - struct pbias_regulator_data *data = rdev_get_drvdata(rdev); - const struct pbias_reg_info *info = data->info; - int value, voltage; - - regmap_read(data->syscon, data->pbias_reg, &value); - value &= info->vmode; - - voltage = value ? 3000000 : 1800000; - - return voltage; -} +static const unsigned int pbias_volt_table[] = { + 1800000, + 3000000 +}; static int pbias_regulator_enable(struct regulator_dev *rdev) { struct pbias_regulator_data *data = rdev_get_drvdata(rdev); const struct pbias_reg_info *info = data->info; - int ret; - - ret = regmap_update_bits(data->syscon, data->pbias_reg, - info->enable_mask, info->enable); - - return ret; -} - -static int pbias_regulator_disable(struct regulator_dev *rdev) -{ - struct pbias_regulator_data *data = rdev_get_drvdata(rdev); - const struct pbias_reg_info *info = data->info; - int ret; - ret = regmap_update_bits(data->syscon, data->pbias_reg, - info->enable_mask, 0); - return ret; + return regmap_update_bits(data->syscon, rdev->desc->enable_reg, + info->enable_mask, info->enable); } static int pbias_regulator_is_enable(struct regulator_dev *rdev) @@ -106,17 +64,18 @@ static int pbias_regulator_is_enable(struct regulator_dev *rdev) const struct pbias_reg_info *info = data->info; int value; - regmap_read(data->syscon, data->pbias_reg, &value); + regmap_read(data->syscon, rdev->desc->enable_reg, &value); return (value & info->enable_mask) == info->enable; } static struct regulator_ops pbias_regulator_voltage_ops = { - .set_voltage = pbias_regulator_set_voltage, - .get_voltage = pbias_regulator_get_voltage, - .enable = pbias_regulator_enable, - .disable = pbias_regulator_disable, - .is_enabled = pbias_regulator_is_enable, + .list_voltage = regulator_list_voltage_table, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .enable = pbias_regulator_enable, + .disable = regulator_disable_regmap, + .is_enabled = pbias_regulator_is_enable, }; static const struct pbias_reg_info pbias_mmc_omap2430 = { @@ -192,6 +151,7 @@ static int pbias_regulator_probe(struct platform_device *pdev) if (IS_ERR(syscon)) return PTR_ERR(syscon); + cfg.regmap = syscon; cfg.dev = &pdev->dev; for (idx = 0; idx < PBIAS_NUM_REGS && data_idx < count; idx++) { @@ -207,15 +167,19 @@ static int pbias_regulator_probe(struct platform_device *pdev) if (!res) return -EINVAL; - drvdata[data_idx].pbias_reg = res->start; drvdata[data_idx].syscon = syscon; drvdata[data_idx].info = info; drvdata[data_idx].desc.name = info->name; drvdata[data_idx].desc.owner = THIS_MODULE; drvdata[data_idx].desc.type = REGULATOR_VOLTAGE; drvdata[data_idx].desc.ops = &pbias_regulator_voltage_ops; + drvdata[data_idx].desc.volt_table = pbias_volt_table; drvdata[data_idx].desc.n_voltages = 2; drvdata[data_idx].desc.enable_time = info->enable_time; + drvdata[data_idx].desc.vsel_reg = res->start; + drvdata[data_idx].desc.vsel_mask = info->vmode; + drvdata[data_idx].desc.enable_reg = res->start; + drvdata[data_idx].desc.enable_mask = info->enable_mask; cfg.init_data = pbias_matches[idx].init_data; cfg.driver_data = &drvdata[data_idx]; -- cgit v1.2.3-70-g09d2 From ea05df4e8f5d2466dbbf2e46956e9e202a22232b Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 14 Apr 2014 15:38:49 +0200 Subject: net: cadence: Add architecture dependencies The Cadence ethernet chipsets are only used on specific ARM architectures. Add Kconfig dependencies so that drivers for these chipsets are only buildable on the relevant architectures. Signed-off-by: Jean Delvare Cc: Nicolas Ferre Signed-off-by: David S. Miller --- drivers/net/ethernet/cadence/Kconfig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/cadence/Kconfig b/drivers/net/ethernet/cadence/Kconfig index 751d5c7b312..7e49c43b7af 100644 --- a/drivers/net/ethernet/cadence/Kconfig +++ b/drivers/net/ethernet/cadence/Kconfig @@ -4,7 +4,7 @@ config NET_CADENCE bool "Cadence devices" - depends on HAS_IOMEM + depends on HAS_IOMEM && (ARM || AVR32 || COMPILE_TEST) default y ---help--- If you have a network (Ethernet) card belonging to this class, say Y. @@ -22,7 +22,7 @@ if NET_CADENCE config ARM_AT91_ETHER tristate "AT91RM9200 Ethernet support" - depends on HAS_DMA + depends on HAS_DMA && (ARCH_AT91RM9200 || COMPILE_TEST) select MACB ---help--- If you wish to compile a kernel for the AT91RM9200 and enable @@ -30,7 +30,7 @@ config ARM_AT91_ETHER config MACB tristate "Cadence MACB/GEM support" - depends on HAS_DMA + depends on HAS_DMA && (PLATFORM_AT32AP || ARCH_AT91 || ARCH_PICOXCELL || ARCH_ZYNQ || COMPILE_TEST) select PHYLIB ---help--- The Cadence MACB ethernet interface is found on many Atmel AT32 and -- cgit v1.2.3-70-g09d2 From bb78864a0c3c55461fc757c0c4b674f409518325 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Mon, 14 Apr 2014 18:48:01 +0200 Subject: at86rf230: remove check if AVDD settled The AVDD regulator is only enabled when the RF section is active TX_ON (PLL_ON) state. Since commit 7dcbd22a97eb0689e6c583ad630ae0e7341e34c1 ("ieee802154: ensure that first RF212 state comes from TRX_OFF"). We are in TRX_OFF state at the time at86rf230_hw_init is run. Note that this test would only fail in case of a severe hardware malfunction (faulty/shorted power supply, etc.) so it wasn't all that useful in the first place. Signed-off-by: Alexander Aring Reviewed-by: Werner Almesberger Signed-off-by: David S. Miller --- drivers/net/ieee802154/at86rf230.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 430bb0db9bc..e102eef0b33 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -1025,14 +1025,6 @@ static int at86rf230_hw_init(struct at86rf230_local *lp) return -EINVAL; } - rc = at86rf230_read_subreg(lp, SR_AVDD_OK, &status); - if (rc) - return rc; - if (!status) { - dev_err(&lp->spi->dev, "AVDD error\n"); - return -EINVAL; - } - return 0; } -- cgit v1.2.3-70-g09d2 From 2168746cfc075d004fd7044be706054fceb24e59 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Mon, 14 Apr 2014 18:48:02 +0200 Subject: at86rf230: fix __at86rf230_read_subreg function The __at86rf230_read_subreg function don't mask and shift register contents which it should do. This patch adds the necessary masks and shift operations in this function. Since we have csma support this can make some trouble on state changes. Since CSMA support turned on some bits in the TRX_STATUS register that used to be zero, not masking broke checking of the TRX_STATUS field after commanding a state change. Signed-off-by: Alexander Aring Reviewed-by: Werner Almesberger Signed-off-by: David S. Miller --- drivers/net/ieee802154/at86rf230.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index e102eef0b33..e36f194673a 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -365,7 +365,7 @@ __at86rf230_read_subreg(struct at86rf230_local *lp, dev_vdbg(&lp->spi->dev, "buf[1] = %02x\n", buf[1]); if (status == 0) - *data = buf[1]; + *data = (buf[1] & mask) >> shift; return status; } -- cgit v1.2.3-70-g09d2 From 1dd333f470b4e1767c9c0a14b05b5104e56b2930 Mon Sep 17 00:00:00 2001 From: "Li, Zhen-Hua" Date: Tue, 15 Apr 2014 09:53:11 +0800 Subject: driver/net: cosa driver uses udelay incorrectly In cosa driver, udelay with more than 20000 may cause __bad_udelay. Use msleep for instead. Signed-off-by: Li, Zhen-Hua Signed-off-by: David S. Miller --- drivers/net/wan/cosa.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c index 84734a80509..83c39e2858b 100644 --- a/drivers/net/wan/cosa.c +++ b/drivers/net/wan/cosa.c @@ -1521,11 +1521,7 @@ static int cosa_reset_and_read_id(struct cosa_data *cosa, char *idstring) cosa_putstatus(cosa, 0); cosa_getdata8(cosa); cosa_putstatus(cosa, SR_RST); -#ifdef MODULE msleep(500); -#else - udelay(5*100000); -#endif /* Disable all IRQs from the card */ cosa_putstatus(cosa, 0); -- cgit v1.2.3-70-g09d2 From 9f05d3fb644bf178c169d9c70dcfe360e3a006ae Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Mon, 14 Apr 2014 22:01:30 -0700 Subject: iommu/vt-d: Fix get_domain_for_dev() handling of upstream PCIe bridges Commit 146922ec79 ("iommu/vt-d: Make get_domain_for_dev() take struct device") introduced new variables bridge_bus and bridge_devfn to identify the upstream PCIe to PCI bridge responsible for the given target device. Leaving the original bus/devfn variables to identify the target device itself, now that it is no longer assumed to be PCI and we can no longer trivially find that information. However, the patch failed to correctly use the new variables in all cases; instead using the as-yet-uninitialised 'bus' and 'devfn' variables. Reported-by: Alex Williamson Signed-off-by: David Woodhouse --- drivers/iommu/intel-iommu.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index 13dc2318e17..f256ffc02e2 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -2237,7 +2237,9 @@ static struct dmar_domain *get_domain_for_dev(struct device *dev, int gaw) bridge_devfn = dev_tmp->devfn; } spin_lock_irqsave(&device_domain_lock, flags); - info = dmar_search_domain_by_dev_info(segment, bus, devfn); + info = dmar_search_domain_by_dev_info(segment, + bridge_bus, + bridge_devfn); if (info) { iommu = info->iommu; domain = info->domain; -- cgit v1.2.3-70-g09d2 From 5ae0566a0fffa09a77ac5996e3854fe91cd87167 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Tue, 15 Apr 2014 10:35:35 +0800 Subject: iommu/vt-d: fix bug in matching PCI devices with DRHD/RMRR descriptors Commit "59ce0515cdaf iommu/vt-d: Update DRHD/RMRR/ATSR device scope caches when PCI hotplug happens" introduces a bug, which fails to match PCI devices with DMAR device scope entries if PCI path array in the entry has more than one level. For example, it fails to handle [1D2h 0466 1] Device Scope Entry Type : 01 [1D3h 0467 1] Entry Length : 0A [1D4h 0468 2] Reserved : 0000 [1D6h 0470 1] Enumeration ID : 00 [1D7h 0471 1] PCI Bus Number : 00 [1D8h 0472 2] PCI Path : 1C,04 [1DAh 0474 2] PCI Path : 00,02 And cause DMA failure on HP DL980 as: DMAR:[fault reason 02] Present bit in context entry is clear dmar: DRHD: handling fault status reg 602 dmar: DMAR:[DMA Read] Request device [02:00.2] fault addr 7f61e000 Reported-and-tested-by: Davidlohr Bueso Signed-off-by: Jiang Liu Signed-off-by: David Woodhouse --- drivers/iommu/dmar.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c index f445c10df8d..39f8b717fe8 100644 --- a/drivers/iommu/dmar.c +++ b/drivers/iommu/dmar.c @@ -152,7 +152,8 @@ dmar_alloc_pci_notify_info(struct pci_dev *dev, unsigned long event) info->seg = pci_domain_nr(dev->bus); info->level = level; if (event == BUS_NOTIFY_ADD_DEVICE) { - for (tmp = dev, level--; tmp; tmp = tmp->bus->self) { + for (tmp = dev; tmp; tmp = tmp->bus->self) { + level--; info->path[level].device = PCI_SLOT(tmp->devfn); info->path[level].function = PCI_FUNC(tmp->devfn); if (pci_is_root_bus(tmp->bus)) -- cgit v1.2.3-70-g09d2 From c26ef3eb3c11274bad1b64498d0a134f85755250 Mon Sep 17 00:00:00 2001 From: Steven Miao Date: Tue, 15 Apr 2014 15:17:19 +0800 Subject: video: bf54x-lq043fb: fix build error Fix build error by including linux/gpio.h. Also drop asm/gpio.h which is not needed. Signed-off-by: Steven Miao Signed-off-by: Tomi Valkeinen --- drivers/video/bf54x-lq043fb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/video/bf54x-lq043fb.c b/drivers/video/bf54x-lq043fb.c index 42b8f9d1101..e2c42ad8515 100644 --- a/drivers/video/bf54x-lq043fb.c +++ b/drivers/video/bf54x-lq043fb.c @@ -49,13 +49,13 @@ #include #include #include +#include #include #include #include #include #include -#include #include #include -- cgit v1.2.3-70-g09d2 From 5ac96345899be859529e05af42f708ae7bd65782 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Tue, 8 Apr 2014 16:18:41 +0300 Subject: drm/omap: print warning when rotating non-TILER fb Print a warning when the user tries to rotate a non-TILER framebuffer. Also set the rotation to 0, to avoid constant flood of the warnings in case of page flipping. Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/omap_fb.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/omap_fb.c b/drivers/gpu/drm/omapdrm/omap_fb.c index d2b8c49bfb4..8b019602ffe 100644 --- a/drivers/gpu/drm/omapdrm/omap_fb.c +++ b/drivers/gpu/drm/omapdrm/omap_fb.c @@ -218,6 +218,20 @@ void omap_framebuffer_update_scanout(struct drm_framebuffer *fb, info->rotation_type = OMAP_DSS_ROT_TILER; info->screen_width = omap_gem_tiled_stride(plane->bo, orient); } else { + switch (win->rotation & 0xf) { + case 0: + case BIT(DRM_ROTATE_0): + /* OK */ + break; + + default: + dev_warn(fb->dev->dev, + "rotation '%d' ignored for non-tiled fb\n", + win->rotation); + win->rotation = 0; + break; + } + info->paddr = get_linear_addr(plane, format, 0, x, y); info->rotation_type = OMAP_DSS_ROT_DMA; info->screen_width = plane->pitch; -- cgit v1.2.3-70-g09d2 From 772cdc9777403f10c4229c49645024a502dfd783 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Wed, 9 Apr 2014 14:51:01 +0300 Subject: drm/omap: remove extra plane->destroy from crtc destroy All the planes, including primary planes, are now destroyed by the drm framework. Thus we no longer need the explicit call to plane->destroy from the crtc's destroy function. This patch removes the call, thus fixing the crash caused by double freeing the plane. remove omap_crtc->plane->funcs->destroy(omap_crtc->plane) Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/omap_crtc.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c index f59ef9359e6..b3a7529845b 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.c +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c @@ -197,7 +197,6 @@ static void omap_crtc_destroy(struct drm_crtc *crtc) WARN_ON(omap_crtc->apply_irq.registered); omap_irq_unregister(crtc->dev, &omap_crtc->error_irq); - omap_crtc->plane->funcs->destroy(omap_crtc->plane); drm_crtc_cleanup(crtc); kfree(omap_crtc); -- cgit v1.2.3-70-g09d2 From b841aedfcfd543d836c856bfde5a17c51cab6b26 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 10 Apr 2014 08:57:55 +0300 Subject: drm/omap: remove warn from debugfs Patch dfe96ddcfa22b44100814b9435770f6ff1309d37 (omapdrm: simplify locking in the fb debugfs file) removed taking locks when using omapdrm's debugfs to dump fb objects. However, in omap_gem_describe we give a WARN is the lock has not been taken, so that WARN is now seen every time omapdrm debugfs is used. So, presuming the removal of locks is ok, we can also remove the WARN. Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/omap_gem.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/omap_gem.c b/drivers/gpu/drm/omapdrm/omap_gem.c index c8d97276388..70798b9fe63 100644 --- a/drivers/gpu/drm/omapdrm/omap_gem.c +++ b/drivers/gpu/drm/omapdrm/omap_gem.c @@ -980,12 +980,9 @@ int omap_gem_resume(struct device *dev) #ifdef CONFIG_DEBUG_FS void omap_gem_describe(struct drm_gem_object *obj, struct seq_file *m) { - struct drm_device *dev = obj->dev; struct omap_gem_object *omap_obj = to_omap_bo(obj); uint64_t off; - WARN_ON(!mutex_is_locked(&dev->struct_mutex)); - off = drm_vma_node_start(&obj->vma_node); seq_printf(m, "%08x: %2d (%2d) %08llx %08Zx (%2d) %p %4d", -- cgit v1.2.3-70-g09d2 From 15ec2ca964d7a52e7e0a452fe0f9c409d2f3eec6 Mon Sep 17 00:00:00 2001 From: Subhajit Paul Date: Fri, 11 Apr 2014 12:53:30 +0530 Subject: drm/omap: Fix memory leak in omap_gem_op_async In omap_gem_op_async(), if a waiter is not added to the wait list, it needs to be free'd in the function itself. Make sure we free the waiter for this case. Signed-off-by: Subhajit Paul Signed-off-by: Archit Taneja Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/omap_gem.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/omap_gem.c b/drivers/gpu/drm/omapdrm/omap_gem.c index 70798b9fe63..9a68e9a2843 100644 --- a/drivers/gpu/drm/omapdrm/omap_gem.c +++ b/drivers/gpu/drm/omapdrm/omap_gem.c @@ -1226,6 +1226,8 @@ int omap_gem_op_async(struct drm_gem_object *obj, enum omap_gem_op op, } spin_unlock(&sync_lock); + + kfree(waiter); } /* no waiting.. */ -- cgit v1.2.3-70-g09d2 From f2cff0f34ff2c51f703880a2b883ea0c9de4a5ac Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Fri, 11 Apr 2014 12:53:31 +0530 Subject: drm/omap: gem sync: wait on correct events A waiter of the type OMAP_GEM_READ should wait for a buffer to be completely written, and only then proceed with reading it. A similar logic applies for waiters with OMAP_GEM_WRITE flag. Currently the function is_waiting() waits on the read_complete/read_target counts in the sync object. This should be the other way round, as a reader should wait for users who are 'writing' to this buffer, and vice versa. Make readers of the buffer(OMAP_GEM_READ) wait on the write counters, and writers to the buffer(OMAP_GEM_WRITE) wait on the read counters in is_waiting() Signed-off-by: Archit Taneja Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/omap_gem.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/omap_gem.c b/drivers/gpu/drm/omapdrm/omap_gem.c index 9a68e9a2843..95dbce286a4 100644 --- a/drivers/gpu/drm/omapdrm/omap_gem.c +++ b/drivers/gpu/drm/omapdrm/omap_gem.c @@ -1047,10 +1047,10 @@ static inline bool is_waiting(struct omap_gem_sync_waiter *waiter) { struct omap_gem_object *omap_obj = waiter->omap_obj; if ((waiter->op & OMAP_GEM_READ) && - (omap_obj->sync->read_complete < waiter->read_target)) + (omap_obj->sync->write_complete < waiter->write_target)) return true; if ((waiter->op & OMAP_GEM_WRITE) && - (omap_obj->sync->write_complete < waiter->write_target)) + (omap_obj->sync->read_complete < waiter->read_target)) return true; return false; } -- cgit v1.2.3-70-g09d2 From 71b6667765c7019f3fd5ea5e0c02f65f7331f3e1 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Fri, 11 Apr 2014 12:53:32 +0530 Subject: drm/omap: Fix crash when using LCD3 overlay manager The channel_names list didn't have a string populated for LCD3 manager, this results in a crash when the display's output is connected to LCD3. Add an entry for LCD3. Reported-by: Somnath Mukherjee Signed-off-by: Archit Taneja Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/omap_crtc.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c index b3a7529845b..46f8e1e40e8 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.c +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c @@ -654,6 +654,7 @@ static const char *channel_names[] = { [OMAP_DSS_CHANNEL_LCD] = "lcd", [OMAP_DSS_CHANNEL_DIGIT] = "tv", [OMAP_DSS_CHANNEL_LCD2] = "lcd2", + [OMAP_DSS_CHANNEL_LCD3] = "lcd3", }; void omap_crtc_pre_init(void) -- cgit v1.2.3-70-g09d2 From bc905aced30e48a39af7c452bf46228d7c6188b9 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Fri, 11 Apr 2014 12:53:34 +0530 Subject: drm/omap: Use old_fb to synchronize between successive page flips omap_crtc->old_fb is used to check whether the previous page flip has completed or not. However, it's never initialized to anything, so it's always NULL. This results in the check to always succeed, and the page_flip to proceed. Initialize old_fb to the fb that we intend to flip to through page_flip, and therefore prevent a future page flip to proceed if the last one didn't complete. Signed-off-by: Archit Taneja Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/omap_crtc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c index 46f8e1e40e8..00798247190 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.c +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c @@ -360,7 +360,7 @@ static int omap_crtc_page_flip_locked(struct drm_crtc *crtc, } omap_crtc->event = event; - primary->fb = fb; + omap_crtc->old_fb = primary->fb = fb; /* * Hold a reference temporarily until the crtc is updated -- cgit v1.2.3-70-g09d2 From 38e5597a03d2d1499a785230031c4f48e1d9c6b7 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Fri, 11 Apr 2014 12:53:35 +0530 Subject: drm/omap: protect omap_crtc's event with event_lock spinlock The vblank_cb callback and the page_flip ioctl can occur together in different CPU contexts. vblank_cb uses takes tje drm device's event_lock spinlock when sending the vblank event and updating omap_crtc->event and omap_crtc->od_fb. Use the same spinlock in page_flip, to make sure the above omap_crtc parameters are configured sequentially. Signed-off-by: Archit Taneja Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/omap_crtc.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c index 00798247190..e3c47a8005f 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.c +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c @@ -350,11 +350,15 @@ static int omap_crtc_page_flip_locked(struct drm_crtc *crtc, struct omap_crtc *omap_crtc = to_omap_crtc(crtc); struct drm_plane *primary = crtc->primary; struct drm_gem_object *bo; + unsigned long flags; DBG("%d -> %d (event=%p)", primary->fb ? primary->fb->base.id : -1, fb->base.id, event); + spin_lock_irqsave(&dev->event_lock, flags); + if (omap_crtc->old_fb) { + spin_unlock_irqrestore(&dev->event_lock, flags); dev_err(dev->dev, "already a pending flip\n"); return -EINVAL; } @@ -362,6 +366,8 @@ static int omap_crtc_page_flip_locked(struct drm_crtc *crtc, omap_crtc->event = event; omap_crtc->old_fb = primary->fb = fb; + spin_unlock_irqrestore(&dev->event_lock, flags); + /* * Hold a reference temporarily until the crtc is updated * and takes the reference to the bo. This avoids it -- cgit v1.2.3-70-g09d2 From 16c50dcfc4c186ed09a4d80fbd511492d024a1c5 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 28 Feb 2014 15:37:10 +0000 Subject: iommu/arm-smmu: Return 0 on unmap failure The IOMMU core expects the unmap operation to return the number of bytes that have been unmapped or 0 on failure, a negative return value being treated like a number of bytes. Signed-off-by: Laurent Pinchart Signed-off-by: Will Deacon --- drivers/iommu/arm-smmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 8b89e33a89f..69d001a71b2 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -1499,7 +1499,7 @@ static size_t arm_smmu_unmap(struct iommu_domain *domain, unsigned long iova, ret = arm_smmu_handle_mapping(smmu_domain, iova, 0, size, 0); arm_smmu_tlb_inv_context(&smmu_domain->root_cfg); - return ret ? ret : size; + return ret ? 0 : size; } static phys_addr_t arm_smmu_iova_to_phys(struct iommu_domain *domain, -- cgit v1.2.3-70-g09d2 From aca1bc4595c5757f01167ab5bfef2a4f8edfcf4f Mon Sep 17 00:00:00 2001 From: Bin Wang Date: Fri, 21 Mar 2014 10:06:07 +0000 Subject: iommu/arm-smmu: fix panic in arm_smmu_alloc_init_pte MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit kernel panic happened when iommu_unmap a buffer larger than 2MB, more than expected pmd entries got “invalidated”, due to a wrong range passed to arm_smmu_alloc_init_pte. it was likely a typo, now we fix it, passing the correct "end" address to arm_smmu_alloc_init_pte. Signed-off-by: Bin Wang Signed-off-by: Will Deacon --- drivers/iommu/arm-smmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 69d001a71b2..647c3c7fd74 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -1381,7 +1381,7 @@ static int arm_smmu_alloc_init_pmd(struct arm_smmu_device *smmu, pud_t *pud, do { next = pmd_addr_end(addr, end); - ret = arm_smmu_alloc_init_pte(smmu, pmd, addr, end, pfn, + ret = arm_smmu_alloc_init_pte(smmu, pmd, addr, next, pfn, prot, stage); phys += next - addr; } while (pmd++, addr = next, addr < end); -- cgit v1.2.3-70-g09d2 From 3608aeff47034faee7518ddec52d77fb811e952c Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Mon, 31 Mar 2014 19:52:44 +0200 Subject: pata_samsung_cf: fix ata_host_activate() failure handling Add missing clk_disable() call to ata_host_activate() failure path. Cc: Ben Dooks Cc: Kukjin Kim Signed-off-by: Bartlomiej Zolnierkiewicz Reviewed-by: Jingoo Han Signed-off-by: Tejun Heo --- drivers/ata/pata_samsung_cf.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/pata_samsung_cf.c b/drivers/ata/pata_samsung_cf.c index a79566d0566..0610e78c8a2 100644 --- a/drivers/ata/pata_samsung_cf.c +++ b/drivers/ata/pata_samsung_cf.c @@ -594,9 +594,13 @@ static int __init pata_s3c_probe(struct platform_device *pdev) platform_set_drvdata(pdev, host); - return ata_host_activate(host, info->irq, - info->irq ? pata_s3c_irq : NULL, - 0, &pata_s3c_sht); + ret = ata_host_activate(host, info->irq, + info->irq ? pata_s3c_irq : NULL, + 0, &pata_s3c_sht); + if (ret) + goto stop_clk; + + return 0; stop_clk: clk_disable(info->clk); -- cgit v1.2.3-70-g09d2 From f2d022aa421ca903a30f63b04528064b7eceaf5e Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Tue, 15 Apr 2014 16:26:01 +0300 Subject: drm/omap: fix the handling of fb ref counts With the recent primary-plane changes for drm, the primary plane's framebuffer needs to be ref counted the same way as for non-primary-planes. This was not done by the omapdrm driver, which caused the ref count to drop to 0 too early, causing problems. This patch moves the fb unref and ref from omap_plane_update to omap_plane_mode_set. This way the fb refs are updated for both primary and non-primary cases, as omap_plane_update calls omap_plane_mode_set. Signed-off-by: Tomi Valkeinen --- drivers/gpu/drm/omapdrm/omap_plane.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/omapdrm/omap_plane.c b/drivers/gpu/drm/omapdrm/omap_plane.c index df1725247cc..3cf31ee59aa 100644 --- a/drivers/gpu/drm/omapdrm/omap_plane.c +++ b/drivers/gpu/drm/omapdrm/omap_plane.c @@ -225,6 +225,11 @@ int omap_plane_mode_set(struct drm_plane *plane, omap_plane->apply_done_cb.arg = arg; } + if (plane->fb) + drm_framebuffer_unreference(plane->fb); + + drm_framebuffer_reference(fb); + plane->fb = fb; plane->crtc = crtc; @@ -241,11 +246,6 @@ static int omap_plane_update(struct drm_plane *plane, struct omap_plane *omap_plane = to_omap_plane(plane); omap_plane->enabled = true; - if (plane->fb) - drm_framebuffer_unreference(plane->fb); - - drm_framebuffer_reference(fb); - /* omap_plane_mode_set() takes adjusted src */ switch (omap_plane->win.rotation & 0xf) { case BIT(DRM_ROTATE_90): -- cgit v1.2.3-70-g09d2 From 3a7745215e7f73a5c7d9bcdc50661a55b39052a3 Mon Sep 17 00:00:00 2001 From: Milan Broz Date: Mon, 14 Apr 2014 22:02:30 +0200 Subject: dm verity: fix biovecs hash calculation regression Commit 003b5c5719f159f4f4bf97511c4702a0638313dd ("block: Convert drivers to immutable biovecs") incorrectly converted biovec iteration in dm-verity to always calculate the hash from a full biovec, but the function only needs to calculate the hash from part of the biovec (up to the calculated "todo" value). Fix this issue by limiting hash input to only the requested data size. This problem was identified using the cryptsetup regression test for veritysetup (verity-compat-test). Signed-off-by: Milan Broz Acked-by: Mikulas Patocka Signed-off-by: Mike Snitzer Cc: stable@vger.kernel.org # 3.14+ --- drivers/md/dm-verity.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/md/dm-verity.c b/drivers/md/dm-verity.c index 796007a5e0e..7a7bab8947a 100644 --- a/drivers/md/dm-verity.c +++ b/drivers/md/dm-verity.c @@ -330,15 +330,17 @@ test_block_hash: return r; } } - todo = 1 << v->data_dev_block_bits; - while (io->iter.bi_size) { + do { u8 *page; + unsigned len; struct bio_vec bv = bio_iter_iovec(bio, io->iter); page = kmap_atomic(bv.bv_page); - r = crypto_shash_update(desc, page + bv.bv_offset, - bv.bv_len); + len = bv.bv_len; + if (likely(len >= todo)) + len = todo; + r = crypto_shash_update(desc, page + bv.bv_offset, len); kunmap_atomic(page); if (r < 0) { @@ -346,8 +348,9 @@ test_block_hash: return r; } - bio_advance_iter(bio, &io->iter, bv.bv_len); - } + bio_advance_iter(bio, &io->iter, len); + todo -= len; + } while (todo); if (!v->version) { r = crypto_shash_update(desc, v->salt, v->salt_size); -- cgit v1.2.3-70-g09d2 From f6da9fe45c3074b909084ae9da5f55034ebffeb4 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 15 Apr 2014 10:28:04 +0200 Subject: irqchip: vic: Properly chain the cascaded IRQs We are flagging the parent IRQ as chained, then we must also make sure to call the chained_irq_[enter|exit] functions for things to work smoothly. Signed-off-by: Linus Walleij Link: http://lkml.kernel.org/r/1397550484-7119-1-git-send-email-linus.walleij@linaro.org Signed-off-by: Thomas Gleixner --- drivers/irqchip/irq-vic.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/irqchip/irq-vic.c b/drivers/irqchip/irq-vic.c index 37dab0b472c..7d35287f9e9 100644 --- a/drivers/irqchip/irq-vic.c +++ b/drivers/irqchip/irq-vic.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -228,12 +229,17 @@ static int handle_one_vic(struct vic_device *vic, struct pt_regs *regs) static void vic_handle_irq_cascaded(unsigned int irq, struct irq_desc *desc) { u32 stat, hwirq; + struct irq_chip *host_chip = irq_desc_get_chip(desc); struct vic_device *vic = irq_desc_get_handler_data(desc); + chained_irq_enter(host_chip, desc); + while ((stat = readl_relaxed(vic->base + VIC_IRQ_STATUS))) { hwirq = ffs(stat) - 1; generic_handle_irq(irq_find_mapping(vic->domain, hwirq)); } + + chained_irq_exit(host_chip, desc); } /* -- cgit v1.2.3-70-g09d2 From cea37f87519ca3172a4e8ddd3ffcd2b4232b341f Mon Sep 17 00:00:00 2001 From: Daeseok Youn Date: Tue, 1 Apr 2014 19:15:59 +0900 Subject: xen: fix memory leak in __xen_pcibk_add_pci_dev() It need to free dev_entry when it failed to assign to a new slot on the virtual PCI bus. smatch says: drivers/xen/xen-pciback/vpci.c:142 __xen_pcibk_add_pci_dev() warn: possible memory leak of 'dev_entry' Signed-off-by: Daeseok Youn Signed-off-by: David Vrabel --- drivers/xen/xen-pciback/vpci.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/xen/xen-pciback/vpci.c b/drivers/xen/xen-pciback/vpci.c index 3165ce361b0..51afff96c51 100644 --- a/drivers/xen/xen-pciback/vpci.c +++ b/drivers/xen/xen-pciback/vpci.c @@ -137,6 +137,8 @@ unlock: /* Publish this device. */ if (!err) err = publish_cb(pdev, 0, 0, PCI_DEVFN(slot, func), devid); + else + kfree(dev_entry); out: return err; -- cgit v1.2.3-70-g09d2 From c0914e61660fa7d501ef9394b26f4847ef3dc98e Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 28 Mar 2014 11:24:59 +0300 Subject: xen-pciback: silence an unwanted debug printk There is a missing curly brace here so we might print some extra debug information. Signed-off-by: Dan Carpenter Signed-off-by: David Vrabel --- drivers/xen/xen-pciback/pciback_ops.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/xen/xen-pciback/pciback_ops.c b/drivers/xen/xen-pciback/pciback_ops.c index 929dd46bb40..607e41460c0 100644 --- a/drivers/xen/xen-pciback/pciback_ops.c +++ b/drivers/xen/xen-pciback/pciback_ops.c @@ -217,7 +217,7 @@ int xen_pcibk_enable_msix(struct xen_pcibk_device *pdev, if (result == 0) { for (i = 0; i < op->value; i++) { op->msix_entries[i].entry = entries[i].entry; - if (entries[i].vector) + if (entries[i].vector) { op->msix_entries[i].vector = xen_pirq_from_irq(entries[i].vector); if (unlikely(verbose_request)) @@ -225,6 +225,7 @@ int xen_pcibk_enable_msix(struct xen_pcibk_device *pdev, "MSI-X[%d]: %d\n", pci_name(dev), i, op->msix_entries[i].vector); + } } } else pr_warn_ratelimited("%s: error enabling MSI-X for guest %u: err %d!\n", -- cgit v1.2.3-70-g09d2 From 027bd7e89906a076225b23d1ca4b6702c84e72dc Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Fri, 4 Apr 2014 14:53:40 -0400 Subject: xen/xenbus: Avoid synchronous wait on XenBus stalling shutdown/restart. The 'read_reply' works with 'process_msg' to read of a reply in XenBus. 'process_msg' is running from within the 'xenbus' thread. Whenever a message shows up in XenBus it is put on a xs_state.reply_list list and 'read_reply' picks it up. The problem is if the backend domain or the xenstored process is killed. In which case 'xenbus' is still awaiting - and 'read_reply' if called - stuck forever waiting for the reply_list to have some contents. This is normally not a problem - as the backend domain can come back or the xenstored process can be restarted. However if the domain is in process of being powered off/restarted/halted - there is no point of waiting on it coming back - as we are effectively being terminated and should not impede the progress. This patch solves this problem by checking whether the guest is the right domain. If it is an initial domain and hurtling towards death - there is no point of continuing the wait. All other type of guests continue with their behavior (as Xenstore is expected to still be running in another domain). Fixes-Bug: http://bugs.xenproject.org/xen/bug/8 Signed-off-by: Konrad Rzeszutek Wilk Reviewed-by: Boris Ostrovsky Reviewed-by: David Vrabel Signed-off-by: David Vrabel --- drivers/xen/xenbus/xenbus_xs.c | 44 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/xen/xenbus/xenbus_xs.c b/drivers/xen/xenbus/xenbus_xs.c index b6d5fff43d1..ba804f3d827 100644 --- a/drivers/xen/xenbus/xenbus_xs.c +++ b/drivers/xen/xenbus/xenbus_xs.c @@ -50,6 +50,7 @@ #include #include #include "xenbus_comms.h" +#include "xenbus_probe.h" struct xs_stored_msg { struct list_head list; @@ -139,6 +140,29 @@ static int get_error(const char *errorstring) return xsd_errors[i].errnum; } +static bool xenbus_ok(void) +{ + switch (xen_store_domain_type) { + case XS_LOCAL: + switch (system_state) { + case SYSTEM_POWER_OFF: + case SYSTEM_RESTART: + case SYSTEM_HALT: + return false; + default: + break; + } + return true; + case XS_PV: + case XS_HVM: + /* FIXME: Could check that the remote domain is alive, + * but it is normally initial domain. */ + return true; + default: + break; + } + return false; +} static void *read_reply(enum xsd_sockmsg_type *type, unsigned int *len) { struct xs_stored_msg *msg; @@ -148,9 +172,20 @@ static void *read_reply(enum xsd_sockmsg_type *type, unsigned int *len) while (list_empty(&xs_state.reply_list)) { spin_unlock(&xs_state.reply_lock); - /* XXX FIXME: Avoid synchronous wait for response here. */ - wait_event(xs_state.reply_waitq, - !list_empty(&xs_state.reply_list)); + if (xenbus_ok()) + /* XXX FIXME: Avoid synchronous wait for response here. */ + wait_event_timeout(xs_state.reply_waitq, + !list_empty(&xs_state.reply_list), + msecs_to_jiffies(500)); + else { + /* + * If we are in the process of being shut-down there is + * no point of trying to contact XenBus - it is either + * killed (xenstored application) or the other domain + * has been killed or is unreachable. + */ + return ERR_PTR(-EIO); + } spin_lock(&xs_state.reply_lock); } @@ -215,6 +250,9 @@ void *xenbus_dev_request_and_reply(struct xsd_sockmsg *msg) mutex_unlock(&xs_state.request_mutex); + if (IS_ERR(ret)) + return ret; + if ((msg->type == XS_TRANSACTION_END) || ((req_msg.type == XS_TRANSACTION_START) && (msg->type == XS_ERROR))) -- cgit v1.2.3-70-g09d2 From eb47f71200b7d5b4c8c1f8c75675f592d855aafd Mon Sep 17 00:00:00 2001 From: Konrad Rzeszutek Wilk Date: Fri, 4 Apr 2014 14:53:41 -0400 Subject: xen/manage: Poweroff forcefully if user-space is not yet up. The user can launch the guest in this sequence: xl create -p /vm.cfg [launch, but pause it] xl shutdown latest [sets control/shutdown=poweroff] xl unpause latest xl console latest [and see that the guest has completely ignored the shutdown request] In reality the guest hasn't ignored it. It registers a watch and gets a notification that there is value. It then calls the shutdown_handler which ends up calling orderly_shutdown. Unfortunately that is so early in the bootup that there are no user-space. Which means that the orderly_shutdown fails. But since the force flag was set to false it continues on without reporting. What we really want to is to use the force when we are in the SYSTEM_BOOTING state and not use the 'force' when SYSTEM_RUNNING. However, if we are in the running state - and the shutdown command has been given before the user-space has been setup, there is nothing we can do. Worst yet, we stop ignoring the 'xl shutdown' requests! As such, the other part of this patch is to only stop ignoring the 'xl shutdown' when we are truly in the power off sequence. That means the user can do multiple 'xl shutdown' and we will try to act on them instead of ignoring them. Fixes-Bug: http://bugs.xenproject.org/xen/bug/6 Reported-by: Alex Bligh Signed-off-by: Konrad Rzeszutek Wilk Signed-off-by: David Vrabel --- drivers/xen/manage.c | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/xen/manage.c b/drivers/xen/manage.c index fc6c94c0b43..32f9236c959 100644 --- a/drivers/xen/manage.c +++ b/drivers/xen/manage.c @@ -198,10 +198,32 @@ struct shutdown_handler { void (*cb)(void); }; +static int poweroff_nb(struct notifier_block *cb, unsigned long code, void *unused) +{ + switch (code) { + case SYS_DOWN: + case SYS_HALT: + case SYS_POWER_OFF: + shutting_down = SHUTDOWN_POWEROFF; + default: + break; + } + return NOTIFY_DONE; +} static void do_poweroff(void) { - shutting_down = SHUTDOWN_POWEROFF; - orderly_poweroff(false); + switch (system_state) { + case SYSTEM_BOOTING: + orderly_poweroff(true); + break; + case SYSTEM_RUNNING: + orderly_poweroff(false); + break; + default: + /* Don't do it when we are halting/rebooting. */ + pr_info("Ignoring Xen toolstack shutdown.\n"); + break; + } } static void do_reboot(void) @@ -307,6 +329,10 @@ static struct xenbus_watch shutdown_watch = { .callback = shutdown_handler }; +static struct notifier_block xen_reboot_nb = { + .notifier_call = poweroff_nb, +}; + static int setup_shutdown_watcher(void) { int err; @@ -317,6 +343,7 @@ static int setup_shutdown_watcher(void) return err; } + #ifdef CONFIG_MAGIC_SYSRQ err = register_xenbus_watch(&sysrq_watch); if (err) { @@ -345,6 +372,7 @@ int xen_setup_shutdown_event(void) if (!xen_domain()) return -ENODEV; register_xenstore_notifier(&xenstore_notifier); + register_reboot_notifier(&xen_reboot_nb); return 0; } -- cgit v1.2.3-70-g09d2 From 3063a12be2b07c64e9802708a19489342e64c1a3 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Fri, 28 Mar 2014 14:31:47 -0500 Subject: usb: musb: fix PHY power on/off MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commi 30a70b0 (usb: musb: fix obex in g_nokia.ko causing kernel panic) removed phy_power_on() and phy_power_off() calls from runtime PM callbacks but it failed to note that the driver depended on pm_runtime_get_sync() calls to power up the PHY, thus leaving some platforms without any means to have a working PHY. Fix that by enabling the phy during omap2430_musb_init() and killing it in omap2430_musb_exit(). Fixes: 30a70b0 (usb: musb: fix obex in g_nokia.ko causing kernel panic) Cc: # v3.14 Cc: Pali Rohár Cc: Ivaylo Dimitrov Reported-by: Michael Scott Tested-by: Michael Scott Tested-by: Stefan Roese Reported-by: Rabin Vincent Signed-off-by: Felipe Balbi --- drivers/usb/musb/omap2430.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c index d341c149a2f..819a7cdcb86 100644 --- a/drivers/usb/musb/omap2430.c +++ b/drivers/usb/musb/omap2430.c @@ -416,6 +416,7 @@ static int omap2430_musb_init(struct musb *musb) omap_musb_set_mailbox(glue); phy_init(musb->phy); + phy_power_on(musb->phy); pm_runtime_put_noidle(musb->controller); return 0; @@ -478,6 +479,7 @@ static int omap2430_musb_exit(struct musb *musb) del_timer_sync(&musb_idle_timer); omap2430_low_level_exit(musb); + phy_power_off(musb->phy); phy_exit(musb->phy); return 0; -- cgit v1.2.3-70-g09d2 From 8b2bc2c9351b4c09bc3d9096e2a7af3988565dbf Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Mon, 7 Apr 2014 10:58:01 -0500 Subject: usb: musb: omap2430: make sure clocks are enabled when running mailbox on early initialization we could fall into a situation where the mailbox is called before MUSB's clocks are running, in order to avoid that, make sure mailbox is always wrapped with pm_runtime calls. Reported-by: Stefan Roese Signed-off-by: Felipe Balbi --- drivers/usb/musb/omap2430.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c index 819a7cdcb86..d369bf1f393 100644 --- a/drivers/usb/musb/omap2430.c +++ b/drivers/usb/musb/omap2430.c @@ -316,7 +316,13 @@ static void omap_musb_mailbox_work(struct work_struct *mailbox_work) { struct omap2430_glue *glue = container_of(mailbox_work, struct omap2430_glue, omap_musb_mailbox_work); + struct musb *musb = glue_to_musb(glue); + struct device *dev = musb->controller; + + pm_runtime_get_sync(dev); omap_musb_set_mailbox(glue); + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); } static irqreturn_t omap2430_musb_interrupt(int irq, void *__hci) -- cgit v1.2.3-70-g09d2 From 20474129d8bb0e6f113634f4f0f4f1584d0beed2 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Mon, 14 Apr 2014 15:31:05 -0700 Subject: mwifiex: process event before command response During extended scan, SCAN report event is always followed by command response. Sometimes It is observed that command response is processed before SCAN report which leads to a crash, because current command node is cleared while handling the response. This patch makes sure that driver's main thread gives priority to events over command responses. Signed-off-by: Amitkumar Karwar Signed-off-by: Maithili Hinge Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/main.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index 77db0886c6e..9c771b3e991 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -292,6 +292,12 @@ process_start: while ((skb = skb_dequeue(&adapter->usb_rx_data_q))) mwifiex_handle_rx_packet(adapter, skb); + /* Check for event */ + if (adapter->event_received) { + adapter->event_received = false; + mwifiex_process_event(adapter); + } + /* Check for Cmd Resp */ if (adapter->cmd_resp_received) { adapter->cmd_resp_received = false; @@ -304,12 +310,6 @@ process_start: } } - /* Check for event */ - if (adapter->event_received) { - adapter->event_received = false; - mwifiex_process_event(adapter); - } - /* Check if we need to confirm Sleep Request received previously */ if (adapter->ps_state == PS_STATE_PRE_SLEEP) { -- cgit v1.2.3-70-g09d2 From f8d2b9209ad648a8e9aa973d32fb64aa2ab01d00 Mon Sep 17 00:00:00 2001 From: Amitkumar Karwar Date: Mon, 14 Apr 2014 15:31:06 -0700 Subject: mwifiex: fix hung task on command timeout Sometimes when command timeout occurs due to a firmware or hardware bug, there may be some synchronous commands in command queue. These commands are never downloaded to firmware causing hung task warnings. This patch replaces wait_event_interruptible call with wait_event_interruptible_timeout to fix the issue. Signed-off-by: Amitkumar Karwar Signed-off-by: Avinash Patil Signed-off-by: Bing Zhao Signed-off-by: John W. Linville --- drivers/net/wireless/mwifiex/sta_ioctl.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index 894270611f2..536c14aa71f 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -60,9 +60,10 @@ int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter, int status; /* Wait for completion */ - status = wait_event_interruptible(adapter->cmd_wait_q.wait, - *(cmd_queued->condition)); - if (status) { + status = wait_event_interruptible_timeout(adapter->cmd_wait_q.wait, + *(cmd_queued->condition), + (12 * HZ)); + if (status <= 0) { dev_err(adapter->dev, "cmd_wait_q terminated: %d\n", status); mwifiex_cancel_all_pending_cmd(adapter); return status; -- cgit v1.2.3-70-g09d2 From aad88724c9d54acb1a9737cb6069d8470fa85f74 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 15 Apr 2014 13:47:15 -0400 Subject: ipv4: add a sock pointer to dst->output() path. In the dst->output() path for ipv4, the code assumes the skb it has to transmit is attached to an inet socket, specifically via ip_mc_output() : The sk_mc_loop() test triggers a WARN_ON() when the provider of the packet is an AF_PACKET socket. The dst->output() method gets an additional 'struct sock *sk' parameter. This needs a cascade of changes so that this parameter can be propagated from vxlan to final consumer. Fixes: 8f646c922d55 ("vxlan: keep original skb ownership") Reported-by: lucien xin Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 4 ++-- include/net/dst.h | 14 +++++++++++--- include/net/ip.h | 11 ++++++++--- include/net/ip_tunnels.h | 2 +- include/net/ipv6.h | 2 +- include/net/xfrm.h | 6 +++--- net/core/dst.c | 15 +++++++++------ net/decnet/dn_route.c | 16 ++++++++++++++-- net/ipv4/ip_output.c | 11 +++++------ net/ipv4/ip_tunnel.c | 2 +- net/ipv4/ip_tunnel_core.c | 4 ++-- net/ipv4/route.c | 4 ++-- net/ipv4/xfrm4_output.c | 2 +- net/ipv6/ip6_output.c | 2 +- net/ipv6/route.c | 14 +++++++------- net/ipv6/sit.c | 5 +++-- net/ipv6/xfrm6_output.c | 2 +- net/openvswitch/vport-gre.c | 2 +- net/xfrm/xfrm_policy.c | 2 +- 19 files changed, 74 insertions(+), 46 deletions(-) (limited to 'drivers') diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index c55e316373a..82355d5d155 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -1755,8 +1755,8 @@ int vxlan_xmit_skb(struct vxlan_sock *vs, if (err) return err; - return iptunnel_xmit(rt, skb, src, dst, IPPROTO_UDP, tos, ttl, df, - false); + return iptunnel_xmit(vs->sock->sk, rt, skb, src, dst, IPPROTO_UDP, + tos, ttl, df, false); } EXPORT_SYMBOL_GPL(vxlan_xmit_skb); diff --git a/include/net/dst.h b/include/net/dst.h index 46ed958e0c6..71c60f42be4 100644 --- a/include/net/dst.h +++ b/include/net/dst.h @@ -45,7 +45,7 @@ struct dst_entry { void *__pad1; #endif int (*input)(struct sk_buff *); - int (*output)(struct sk_buff *); + int (*output)(struct sock *sk, struct sk_buff *skb); unsigned short flags; #define DST_HOST 0x0001 @@ -367,7 +367,11 @@ static inline struct dst_entry *skb_dst_pop(struct sk_buff *skb) return child; } -int dst_discard(struct sk_buff *skb); +int dst_discard_sk(struct sock *sk, struct sk_buff *skb); +static inline int dst_discard(struct sk_buff *skb) +{ + return dst_discard_sk(skb->sk, skb); +} void *dst_alloc(struct dst_ops *ops, struct net_device *dev, int initial_ref, int initial_obsolete, unsigned short flags); void __dst_free(struct dst_entry *dst); @@ -449,9 +453,13 @@ static inline void dst_set_expires(struct dst_entry *dst, int timeout) } /* Output packet to network from transport. */ +static inline int dst_output_sk(struct sock *sk, struct sk_buff *skb) +{ + return skb_dst(skb)->output(sk, skb); +} static inline int dst_output(struct sk_buff *skb) { - return skb_dst(skb)->output(skb); + return dst_output_sk(skb->sk, skb); } /* Input packet from network to transport. */ diff --git a/include/net/ip.h b/include/net/ip.h index 77e73d293e0..3ec2b0fb9d8 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -104,13 +104,18 @@ int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev); int ip_local_deliver(struct sk_buff *skb); int ip_mr_input(struct sk_buff *skb); -int ip_output(struct sk_buff *skb); -int ip_mc_output(struct sk_buff *skb); +int ip_output(struct sock *sk, struct sk_buff *skb); +int ip_mc_output(struct sock *sk, struct sk_buff *skb); int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)); int ip_do_nat(struct sk_buff *skb); void ip_send_check(struct iphdr *ip); int __ip_local_out(struct sk_buff *skb); -int ip_local_out(struct sk_buff *skb); +int ip_local_out_sk(struct sock *sk, struct sk_buff *skb); +static inline int ip_local_out(struct sk_buff *skb) +{ + return ip_local_out_sk(skb->sk, skb); +} + int ip_queue_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl); void ip_init(void); int ip_append_data(struct sock *sk, struct flowi4 *fl4, diff --git a/include/net/ip_tunnels.h b/include/net/ip_tunnels.h index e77c10405d5..a4daf9eb856 100644 --- a/include/net/ip_tunnels.h +++ b/include/net/ip_tunnels.h @@ -153,7 +153,7 @@ static inline u8 ip_tunnel_ecn_encap(u8 tos, const struct iphdr *iph, } int iptunnel_pull_header(struct sk_buff *skb, int hdr_len, __be16 inner_proto); -int iptunnel_xmit(struct rtable *rt, struct sk_buff *skb, +int iptunnel_xmit(struct sock *sk, struct rtable *rt, struct sk_buff *skb, __be32 src, __be32 dst, __u8 proto, __u8 tos, __u8 ttl, __be16 df, bool xnet); diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 4f541f11ce6..d640925bc45 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -731,7 +731,7 @@ struct dst_entry *ip6_blackhole_route(struct net *net, * skb processing functions */ -int ip6_output(struct sk_buff *skb); +int ip6_output(struct sock *sk, struct sk_buff *skb); int ip6_forward(struct sk_buff *skb); int ip6_input(struct sk_buff *skb); int ip6_mc_input(struct sk_buff *skb); diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 32682ae47b3..116e9c7e19c 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -333,7 +333,7 @@ struct xfrm_state_afinfo { const xfrm_address_t *saddr); int (*tmpl_sort)(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n); int (*state_sort)(struct xfrm_state **dst, struct xfrm_state **src, int n); - int (*output)(struct sk_buff *skb); + int (*output)(struct sock *sk, struct sk_buff *skb); int (*output_finish)(struct sk_buff *skb); int (*extract_input)(struct xfrm_state *x, struct sk_buff *skb); @@ -1540,7 +1540,7 @@ static inline int xfrm4_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi) int xfrm4_extract_output(struct xfrm_state *x, struct sk_buff *skb); int xfrm4_prepare_output(struct xfrm_state *x, struct sk_buff *skb); -int xfrm4_output(struct sk_buff *skb); +int xfrm4_output(struct sock *sk, struct sk_buff *skb); int xfrm4_output_finish(struct sk_buff *skb); int xfrm4_rcv_cb(struct sk_buff *skb, u8 protocol, int err); int xfrm4_protocol_register(struct xfrm4_protocol *handler, unsigned char protocol); @@ -1565,7 +1565,7 @@ __be32 xfrm6_tunnel_alloc_spi(struct net *net, xfrm_address_t *saddr); __be32 xfrm6_tunnel_spi_lookup(struct net *net, const xfrm_address_t *saddr); int xfrm6_extract_output(struct xfrm_state *x, struct sk_buff *skb); int xfrm6_prepare_output(struct xfrm_state *x, struct sk_buff *skb); -int xfrm6_output(struct sk_buff *skb); +int xfrm6_output(struct sock *sk, struct sk_buff *skb); int xfrm6_output_finish(struct sk_buff *skb); int xfrm6_find_1stfragopt(struct xfrm_state *x, struct sk_buff *skb, u8 **prevhdr); diff --git a/net/core/dst.c b/net/core/dst.c index ca4231ec734..80d6286c8b6 100644 --- a/net/core/dst.c +++ b/net/core/dst.c @@ -142,12 +142,12 @@ loop: mutex_unlock(&dst_gc_mutex); } -int dst_discard(struct sk_buff *skb) +int dst_discard_sk(struct sock *sk, struct sk_buff *skb) { kfree_skb(skb); return 0; } -EXPORT_SYMBOL(dst_discard); +EXPORT_SYMBOL(dst_discard_sk); const u32 dst_default_metrics[RTAX_MAX + 1] = { /* This initializer is needed to force linker to place this variable @@ -184,7 +184,7 @@ void *dst_alloc(struct dst_ops *ops, struct net_device *dev, dst->xfrm = NULL; #endif dst->input = dst_discard; - dst->output = dst_discard; + dst->output = dst_discard_sk; dst->error = 0; dst->obsolete = initial_obsolete; dst->header_len = 0; @@ -209,8 +209,10 @@ static void ___dst_free(struct dst_entry *dst) /* The first case (dev==NULL) is required, when protocol module is unloaded. */ - if (dst->dev == NULL || !(dst->dev->flags&IFF_UP)) - dst->input = dst->output = dst_discard; + if (dst->dev == NULL || !(dst->dev->flags&IFF_UP)) { + dst->input = dst_discard; + dst->output = dst_discard_sk; + } dst->obsolete = DST_OBSOLETE_DEAD; } @@ -361,7 +363,8 @@ static void dst_ifdown(struct dst_entry *dst, struct net_device *dev, return; if (!unregister) { - dst->input = dst->output = dst_discard; + dst->input = dst_discard; + dst->output = dst_discard_sk; } else { dst->dev = dev_net(dst->dev)->loopback_dev; dev_hold(dst->dev); diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c index ce0cbbfe0f4..daccc4a36d8 100644 --- a/net/decnet/dn_route.c +++ b/net/decnet/dn_route.c @@ -752,7 +752,7 @@ static int dn_to_neigh_output(struct sk_buff *skb) return n->output(n, skb); } -static int dn_output(struct sk_buff *skb) +static int dn_output(struct sock *sk, struct sk_buff *skb) { struct dst_entry *dst = skb_dst(skb); struct dn_route *rt = (struct dn_route *)dst; @@ -838,6 +838,18 @@ drop: * Used to catch bugs. This should never normally get * called. */ +static int dn_rt_bug_sk(struct sock *sk, struct sk_buff *skb) +{ + struct dn_skb_cb *cb = DN_SKB_CB(skb); + + net_dbg_ratelimited("dn_rt_bug: skb from:%04x to:%04x\n", + le16_to_cpu(cb->src), le16_to_cpu(cb->dst)); + + kfree_skb(skb); + + return NET_RX_DROP; +} + static int dn_rt_bug(struct sk_buff *skb) { struct dn_skb_cb *cb = DN_SKB_CB(skb); @@ -1463,7 +1475,7 @@ make_route: rt->n = neigh; rt->dst.lastuse = jiffies; - rt->dst.output = dn_rt_bug; + rt->dst.output = dn_rt_bug_sk; switch (res.type) { case RTN_UNICAST: rt->dst.input = dn_forward; diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 7ad68b86093..1cbeba5edff 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -101,17 +101,17 @@ int __ip_local_out(struct sk_buff *skb) skb_dst(skb)->dev, dst_output); } -int ip_local_out(struct sk_buff *skb) +int ip_local_out_sk(struct sock *sk, struct sk_buff *skb) { int err; err = __ip_local_out(skb); if (likely(err == 1)) - err = dst_output(skb); + err = dst_output_sk(sk, skb); return err; } -EXPORT_SYMBOL_GPL(ip_local_out); +EXPORT_SYMBOL_GPL(ip_local_out_sk); static inline int ip_select_ttl(struct inet_sock *inet, struct dst_entry *dst) { @@ -226,9 +226,8 @@ static int ip_finish_output(struct sk_buff *skb) return ip_finish_output2(skb); } -int ip_mc_output(struct sk_buff *skb) +int ip_mc_output(struct sock *sk, struct sk_buff *skb) { - struct sock *sk = skb->sk; struct rtable *rt = skb_rtable(skb); struct net_device *dev = rt->dst.dev; @@ -287,7 +286,7 @@ int ip_mc_output(struct sk_buff *skb) !(IPCB(skb)->flags & IPSKB_REROUTED)); } -int ip_output(struct sk_buff *skb) +int ip_output(struct sock *sk, struct sk_buff *skb) { struct net_device *dev = skb_dst(skb)->dev; diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c index e77381d1df9..484d0ce27ef 100644 --- a/net/ipv4/ip_tunnel.c +++ b/net/ipv4/ip_tunnel.c @@ -670,7 +670,7 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev, return; } - err = iptunnel_xmit(rt, skb, fl4.saddr, fl4.daddr, protocol, + err = iptunnel_xmit(skb->sk, rt, skb, fl4.saddr, fl4.daddr, protocol, tos, ttl, df, !net_eq(tunnel->net, dev_net(dev))); iptunnel_xmit_stats(err, &dev->stats, dev->tstats); diff --git a/net/ipv4/ip_tunnel_core.c b/net/ipv4/ip_tunnel_core.c index e0c2b1d2ea4..bcf206c7900 100644 --- a/net/ipv4/ip_tunnel_core.c +++ b/net/ipv4/ip_tunnel_core.c @@ -46,7 +46,7 @@ #include #include -int iptunnel_xmit(struct rtable *rt, struct sk_buff *skb, +int iptunnel_xmit(struct sock *sk, struct rtable *rt, struct sk_buff *skb, __be32 src, __be32 dst, __u8 proto, __u8 tos, __u8 ttl, __be16 df, bool xnet) { @@ -76,7 +76,7 @@ int iptunnel_xmit(struct rtable *rt, struct sk_buff *skb, iph->ttl = ttl; __ip_select_ident(iph, &rt->dst, (skb_shinfo(skb)->gso_segs ?: 1) - 1); - err = ip_local_out(skb); + err = ip_local_out_sk(sk, skb); if (unlikely(net_xmit_eval(err))) pkt_len = 0; return pkt_len; diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 20a59c388e6..1485aafcad5 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1129,7 +1129,7 @@ static void ipv4_link_failure(struct sk_buff *skb) dst_set_expires(&rt->dst, 0); } -static int ip_rt_bug(struct sk_buff *skb) +static int ip_rt_bug(struct sock *sk, struct sk_buff *skb) { pr_debug("%s: %pI4 -> %pI4, %s\n", __func__, &ip_hdr(skb)->saddr, &ip_hdr(skb)->daddr, @@ -2218,7 +2218,7 @@ struct dst_entry *ipv4_blackhole_route(struct net *net, struct dst_entry *dst_or new->__use = 1; new->input = dst_discard; - new->output = dst_discard; + new->output = dst_discard_sk; new->dev = ort->dst.dev; if (new->dev) diff --git a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c index baa0f63731f..40e701f2e1e 100644 --- a/net/ipv4/xfrm4_output.c +++ b/net/ipv4/xfrm4_output.c @@ -86,7 +86,7 @@ int xfrm4_output_finish(struct sk_buff *skb) return xfrm_output(skb); } -int xfrm4_output(struct sk_buff *skb) +int xfrm4_output(struct sock *sk, struct sk_buff *skb) { struct dst_entry *dst = skb_dst(skb); struct xfrm_state *x = dst->xfrm; diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 3284d61577c..40e7581374f 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -132,7 +132,7 @@ static int ip6_finish_output(struct sk_buff *skb) return ip6_finish_output2(skb); } -int ip6_output(struct sk_buff *skb) +int ip6_output(struct sock *sk, struct sk_buff *skb) { struct net_device *dev = skb_dst(skb)->dev; struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb)); diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 5ea462eacd9..4011617cca6 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -84,9 +84,9 @@ static void ip6_dst_ifdown(struct dst_entry *, static int ip6_dst_gc(struct dst_ops *ops); static int ip6_pkt_discard(struct sk_buff *skb); -static int ip6_pkt_discard_out(struct sk_buff *skb); +static int ip6_pkt_discard_out(struct sock *sk, struct sk_buff *skb); static int ip6_pkt_prohibit(struct sk_buff *skb); -static int ip6_pkt_prohibit_out(struct sk_buff *skb); +static int ip6_pkt_prohibit_out(struct sock *sk, struct sk_buff *skb); static void ip6_link_failure(struct sk_buff *skb); static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk, struct sk_buff *skb, u32 mtu); @@ -290,7 +290,7 @@ static const struct rt6_info ip6_blk_hole_entry_template = { .obsolete = DST_OBSOLETE_FORCE_CHK, .error = -EINVAL, .input = dst_discard, - .output = dst_discard, + .output = dst_discard_sk, }, .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP), .rt6i_protocol = RTPROT_KERNEL, @@ -1058,7 +1058,7 @@ struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_ori new->__use = 1; new->input = dst_discard; - new->output = dst_discard; + new->output = dst_discard_sk; if (dst_metrics_read_only(&ort->dst)) new->_metrics = ort->dst._metrics; @@ -1577,7 +1577,7 @@ int ip6_route_add(struct fib6_config *cfg) switch (cfg->fc_type) { case RTN_BLACKHOLE: rt->dst.error = -EINVAL; - rt->dst.output = dst_discard; + rt->dst.output = dst_discard_sk; rt->dst.input = dst_discard; break; case RTN_PROHIBIT: @@ -2129,7 +2129,7 @@ static int ip6_pkt_discard(struct sk_buff *skb) return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_INNOROUTES); } -static int ip6_pkt_discard_out(struct sk_buff *skb) +static int ip6_pkt_discard_out(struct sock *sk, struct sk_buff *skb) { skb->dev = skb_dst(skb)->dev; return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_OUTNOROUTES); @@ -2140,7 +2140,7 @@ static int ip6_pkt_prohibit(struct sk_buff *skb) return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_INNOROUTES); } -static int ip6_pkt_prohibit_out(struct sk_buff *skb) +static int ip6_pkt_prohibit_out(struct sock *sk, struct sk_buff *skb) { skb->dev = skb_dst(skb)->dev; return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES); diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 1693c8d885f..8da8268d65f 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -974,8 +974,9 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, goto out; } - err = iptunnel_xmit(rt, skb, fl4.saddr, fl4.daddr, IPPROTO_IPV6, tos, - ttl, df, !net_eq(tunnel->net, dev_net(dev))); + err = iptunnel_xmit(skb->sk, rt, skb, fl4.saddr, fl4.daddr, + IPPROTO_IPV6, tos, ttl, df, + !net_eq(tunnel->net, dev_net(dev))); iptunnel_xmit_stats(err, &dev->stats, dev->tstats); return NETDEV_TX_OK; diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c index 6cd625e3770..19ef329bdbf 100644 --- a/net/ipv6/xfrm6_output.c +++ b/net/ipv6/xfrm6_output.c @@ -163,7 +163,7 @@ static int __xfrm6_output(struct sk_buff *skb) return x->outer_mode->afinfo->output_finish(skb); } -int xfrm6_output(struct sk_buff *skb) +int xfrm6_output(struct sock *sk, struct sk_buff *skb) { return NF_HOOK(NFPROTO_IPV6, NF_INET_POST_ROUTING, skb, NULL, skb_dst(skb)->dev, __xfrm6_output); diff --git a/net/openvswitch/vport-gre.c b/net/openvswitch/vport-gre.c index a3d6951602d..ebb6e244255 100644 --- a/net/openvswitch/vport-gre.c +++ b/net/openvswitch/vport-gre.c @@ -174,7 +174,7 @@ static int gre_tnl_send(struct vport *vport, struct sk_buff *skb) skb->local_df = 1; - return iptunnel_xmit(rt, skb, fl.saddr, + return iptunnel_xmit(skb->sk, rt, skb, fl.saddr, OVS_CB(skb)->tun_key->ipv4_dst, IPPROTO_GRE, OVS_CB(skb)->tun_key->ipv4_tos, OVS_CB(skb)->tun_key->ipv4_ttl, df, false); diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index f02f511b710..c08fbd11cef 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -1842,7 +1842,7 @@ purge_queue: xfrm_pol_put(pol); } -static int xdst_queue_output(struct sk_buff *skb) +static int xdst_queue_output(struct sock *sk, struct sk_buff *skb) { unsigned long sched_next; struct dst_entry *dst = skb_dst(skb); -- cgit v1.2.3-70-g09d2 From 29d1e7209e1866a1b6b686107cce9f5a9b886a53 Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Fri, 21 Mar 2014 00:42:54 +0100 Subject: staging/rtl8821ae: Fix OOM handling in _rtl_init_deferred_work() alloc_workqueue() can fail, handle this case. Signed-off-by: Richard Weinberger Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8821ae/base.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8821ae/base.c b/drivers/staging/rtl8821ae/base.c index e5073fe2477..a4c9cc437bc 100644 --- a/drivers/staging/rtl8821ae/base.c +++ b/drivers/staging/rtl8821ae/base.c @@ -388,7 +388,7 @@ static void _rtl_init_mac80211(struct ieee80211_hw *hw) } -static void _rtl_init_deferred_work(struct ieee80211_hw *hw) +static int _rtl_init_deferred_work(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -410,6 +410,9 @@ static void _rtl_init_deferred_work(struct ieee80211_hw *hw) rtlpriv->works.rtl_wq = create_workqueue(rtlpriv->cfg->name); #endif /**/ + if (!rtlpriv->works.rtl_wq) + return -ENOMEM; + INIT_DELAYED_WORK(&rtlpriv->works.watchdog_wq, (void *)rtl_watchdog_wq_callback); INIT_DELAYED_WORK(&rtlpriv->works.ips_nic_off_wq, @@ -421,6 +424,8 @@ static void _rtl_init_deferred_work(struct ieee80211_hw *hw) INIT_DELAYED_WORK(&rtlpriv->works.fwevt_wq, (void *)rtl_fwevt_wq_callback); + return 0; + } void rtl_deinit_deferred_work(struct ieee80211_hw *hw) @@ -519,7 +524,8 @@ int rtl_init_core(struct ieee80211_hw *hw) INIT_LIST_HEAD(&rtlpriv->entry_list); /* <6> init deferred work */ - _rtl_init_deferred_work(hw); + if (_rtl_init_deferred_work(hw)) + return 1; /* <7> */ #ifdef VIF_TODO -- cgit v1.2.3-70-g09d2 From 8564ae09e08340a26c5408637cc4b32dba9f1640 Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Tue, 15 Apr 2014 11:37:14 +0200 Subject: qlcnic: Fix MSI-X initialization code Function qlcnic_setup_tss_rss_intr() might enter endless loop in case pci_enable_msix() contiguously returns a positive number of MSI-Xs that could have been allocated. Besides, the function contains 'err = -EIO;' assignment that never could be reached. This update fixes the aforementioned issues. Cc: Shahed Shaikh Cc: Dept-HSGLinuxNICDev@qlogic.com Cc: netdev@vger.kernel.org Cc: linux-pci@vger.kernel.org Signed-off-by: Alexander Gordeev Acked-by: Shahed Shaikh Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c | 28 ++++++++++++++---------- 1 file changed, 16 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c index 84d011ed7ec..dbf75393f75 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c @@ -670,7 +670,7 @@ int qlcnic_setup_tss_rss_intr(struct qlcnic_adapter *adapter) else num_msix += adapter->drv_tx_rings; - if (adapter->drv_rss_rings > 0) + if (adapter->drv_rss_rings > 0) num_msix += adapter->drv_rss_rings; else num_msix += adapter->drv_sds_rings; @@ -686,19 +686,15 @@ int qlcnic_setup_tss_rss_intr(struct qlcnic_adapter *adapter) return -ENOMEM; } -restore: for (vector = 0; vector < num_msix; vector++) adapter->msix_entries[vector].entry = vector; +restore: err = pci_enable_msix(pdev, adapter->msix_entries, num_msix); - if (err == 0) { - adapter->ahw->num_msix = num_msix; - if (adapter->drv_tss_rings > 0) - adapter->drv_tx_rings = adapter->drv_tss_rings; + if (err > 0) { + if (!adapter->drv_tss_rings && !adapter->drv_rss_rings) + return -ENOSPC; - if (adapter->drv_rss_rings > 0) - adapter->drv_sds_rings = adapter->drv_rss_rings; - } else { netdev_info(adapter->netdev, "Unable to allocate %d MSI-X vectors, Available vectors %d\n", num_msix, err); @@ -716,12 +712,20 @@ restore: "Restoring %d Tx, %d SDS rings for total %d vectors.\n", adapter->drv_tx_rings, adapter->drv_sds_rings, num_msix); - goto restore; - err = -EIO; + goto restore; + } else if (err < 0) { + return err; } - return err; + adapter->ahw->num_msix = num_msix; + if (adapter->drv_tss_rings > 0) + adapter->drv_tx_rings = adapter->drv_tss_rings; + + if (adapter->drv_rss_rings > 0) + adapter->drv_sds_rings = adapter->drv_rss_rings; + + return 0; } int qlcnic_enable_msix(struct qlcnic_adapter *adapter, u32 num_msix) -- cgit v1.2.3-70-g09d2 From 6f1d7210376727d090e04b8635e6dda4d7eb7b0c Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Tue, 15 Apr 2014 14:22:34 -0500 Subject: cxgb4: use the correct max size for firmware flash The wrong max fw size was being used and causing false "too big" errors running ethtool -f. Signed-off-by: Steve Wise Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index fb2fe65903c..bba67681aea 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -682,7 +682,7 @@ enum { SF_RD_ID = 0x9f, /* read ID */ SF_ERASE_SECTOR = 0xd8, /* erase sector */ - FW_MAX_SIZE = 512 * 1024, + FW_MAX_SIZE = 16 * SF_SEC_SIZE, }; /** -- cgit v1.2.3-70-g09d2 From e7a62df8e8b4a5ecbbf4339b5b3671ae6582e50a Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 15 Apr 2014 08:38:17 -0700 Subject: of: Clean up of_update_property After searching for the old property, bail out with -ENODEV if it was not found. It is unnecessary to check if oldprop is NULL before removing its binary file; the check was already done before. Signed-off-by: Guenter Roeck Signed-off-by: Rob Herring --- drivers/of/base.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/of/base.c b/drivers/of/base.c index f72d19b7e5d..6d4ee22708c 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -1828,17 +1828,13 @@ int of_update_property(struct device_node *np, struct property *newprop) next = &(*next)->next; } raw_spin_unlock_irqrestore(&devtree_lock, flags); - if (rc) - return rc; + if (!found) + return -ENODEV; /* Update the sysfs attribute */ - if (oldprop) - sysfs_remove_bin_file(&np->kobj, &oldprop->attr); + sysfs_remove_bin_file(&np->kobj, &oldprop->attr); __of_add_property_sysfs(np, newprop); - if (!found) - return -ENODEV; - return 0; } -- cgit v1.2.3-70-g09d2 From ec03ab77cc2c39d115118fcd4fc11a5801cbb70e Mon Sep 17 00:00:00 2001 From: Wilfried Klaebe Date: Tue, 25 Mar 2014 17:59:39 +0000 Subject: staging: rtl8188eu: remove spaces, correct counts to unbreak P2P ioctls staging: rtl8188eu: remove spaces, correct counts to unbreak P2P ioctls It looks like someone did a search-and-replace on that driver, putting spaces before "=" characters, without checking this is OK everywhere. Also, in some places, there's memcpm()s/strncmp()s checking for some different length than the fixed string argument. These things result in code not working as intended. Fix that. Signed-off-by: Wilfried Klaebe Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8188eu/os_dep/ioctl_linux.c | 74 +++++++++++++------------- 1 file changed, 37 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c b/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c index 2636e7f3dbb..cf30a08912d 100644 --- a/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c +++ b/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c @@ -359,7 +359,7 @@ static char *translate_scan(struct adapter *padapter, if (wpa_len > 0) { p = buf; _rtw_memset(buf, 0, MAX_WPA_IE_LEN); - p += sprintf(p, "wpa_ie ="); + p += sprintf(p, "wpa_ie="); for (i = 0; i < wpa_len; i++) p += sprintf(p, "%02x", wpa_ie[i]); @@ -376,7 +376,7 @@ static char *translate_scan(struct adapter *padapter, if (rsn_len > 0) { p = buf; _rtw_memset(buf, 0, MAX_WPA_IE_LEN); - p += sprintf(p, "rsn_ie ="); + p += sprintf(p, "rsn_ie="); for (i = 0; i < rsn_len; i++) p += sprintf(p, "%02x", rsn_ie[i]); _rtw_memset(&iwe, 0, sizeof(iwe)); @@ -2899,7 +2899,7 @@ static int rtw_p2p_get_status(struct net_device *dev, /* Commented by Albert 2010/10/12 */ /* Because of the output size limitation, I had removed the "Role" information. */ /* About the "Role" information, we will use the new private IOCTL to get the "Role" information. */ - sprintf(extra, "\n\nStatus =%.2d\n", rtw_p2p_state(pwdinfo)); + sprintf(extra, "\n\nStatus=%.2d\n", rtw_p2p_state(pwdinfo)); wrqu->data.length = strlen(extra); return ret; @@ -2918,7 +2918,7 @@ static int rtw_p2p_get_req_cm(struct net_device *dev, struct adapter *padapter = (struct adapter *)rtw_netdev_priv(dev); struct wifidirect_info *pwdinfo = &(padapter->wdinfo); - sprintf(extra, "\n\nCM =%s\n", pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req); + sprintf(extra, "\n\nCM=%s\n", pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req); wrqu->data.length = strlen(extra); return ret; } @@ -2935,7 +2935,7 @@ static int rtw_p2p_get_role(struct net_device *dev, pwdinfo->p2p_peer_interface_addr[0], pwdinfo->p2p_peer_interface_addr[1], pwdinfo->p2p_peer_interface_addr[2], pwdinfo->p2p_peer_interface_addr[3], pwdinfo->p2p_peer_interface_addr[4], pwdinfo->p2p_peer_interface_addr[5]); - sprintf(extra, "\n\nRole =%.2d\n", rtw_p2p_role(pwdinfo)); + sprintf(extra, "\n\nRole=%.2d\n", rtw_p2p_role(pwdinfo)); wrqu->data.length = strlen(extra); return ret; } @@ -3022,7 +3022,7 @@ static int rtw_p2p_get_op_ch(struct net_device *dev, DBG_88E("[%s] Op_ch = %02x\n", __func__, pwdinfo->operating_channel); - sprintf(extra, "\n\nOp_ch =%.2d\n", pwdinfo->operating_channel); + sprintf(extra, "\n\nOp_ch=%.2d\n", pwdinfo->operating_channel); wrqu->data.length = strlen(extra); return ret; } @@ -3043,7 +3043,7 @@ static int rtw_p2p_get_wps_configmethod(struct net_device *dev, u8 blnMatch = 0; u16 attr_content = 0; uint attr_contentlen = 0; - /* 6 is the string "wpsCM =", 17 is the MAC addr, we have to clear it at wrqu->data.pointer */ + /* 6 is the string "wpsCM=", 17 is the MAC addr, we have to clear it at wrqu->data.pointer */ u8 attr_content_str[6 + 17] = {0x00}; /* Commented by Albert 20110727 */ @@ -3079,7 +3079,7 @@ static int rtw_p2p_get_wps_configmethod(struct net_device *dev, rtw_get_wps_attr_content(wpsie, wpsie_len, WPS_ATTR_CONF_METHOD, (u8 *) &be_tmp, &attr_contentlen); if (attr_contentlen) { attr_content = be16_to_cpu(be_tmp); - sprintf(attr_content_str, "\n\nM =%.4d", attr_content); + sprintf(attr_content_str, "\n\nM=%.4d", attr_content); blnMatch = 1; } } @@ -3091,7 +3091,7 @@ static int rtw_p2p_get_wps_configmethod(struct net_device *dev, spin_unlock_bh(&pmlmepriv->scanned_queue.lock); if (!blnMatch) - sprintf(attr_content_str, "\n\nM = 0000"); + sprintf(attr_content_str, "\n\nM=0000"); if (copy_to_user(wrqu->data.pointer, attr_content_str, 6 + 17)) return -EFAULT; @@ -3172,9 +3172,9 @@ static int rtw_p2p_get_go_device_address(struct net_device *dev, spin_unlock_bh(&pmlmepriv->scanned_queue.lock); if (!blnMatch) - snprintf(go_devadd_str, sizeof(go_devadd_str), "\n\ndev_add = NULL"); + snprintf(go_devadd_str, sizeof(go_devadd_str), "\n\ndev_add=NULL"); else - snprintf(go_devadd_str, sizeof(go_devadd_str), "\n\ndev_add =%.2X:%.2X:%.2X:%.2X:%.2X:%.2X", + snprintf(go_devadd_str, sizeof(go_devadd_str), "\n\ndev_add=%.2X:%.2X:%.2X:%.2X:%.2X:%.2X", attr_content[0], attr_content[1], attr_content[2], attr_content[3], attr_content[4], attr_content[5]); if (copy_to_user(wrqu->data.pointer, go_devadd_str, sizeof(go_devadd_str))) @@ -3198,7 +3198,7 @@ static int rtw_p2p_get_device_type(struct net_device *dev, u8 blnMatch = 0; u8 dev_type[8] = {0x00}; uint dev_type_len = 0; - u8 dev_type_str[17 + 9] = {0x00}; /* +9 is for the str "dev_type =", we have to clear it at wrqu->data.pointer */ + u8 dev_type_str[17 + 9] = {0x00}; /* +9 is for the str "dev_type=", we have to clear it at wrqu->data.pointer */ /* Commented by Albert 20121209 */ /* The input data is the MAC address which the application wants to know its device type. */ @@ -3239,7 +3239,7 @@ static int rtw_p2p_get_device_type(struct net_device *dev, memcpy(&be_tmp, dev_type, 2); type = be16_to_cpu(be_tmp); - sprintf(dev_type_str, "\n\nN =%.2d", type); + sprintf(dev_type_str, "\n\nN=%.2d", type); blnMatch = 1; } } @@ -3252,7 +3252,7 @@ static int rtw_p2p_get_device_type(struct net_device *dev, spin_unlock_bh(&pmlmepriv->scanned_queue.lock); if (!blnMatch) - sprintf(dev_type_str, "\n\nN = 00"); + sprintf(dev_type_str, "\n\nN=00"); if (copy_to_user(wrqu->data.pointer, dev_type_str, 9 + 17)) { return -EFAULT; @@ -3277,7 +3277,7 @@ static int rtw_p2p_get_device_name(struct net_device *dev, u8 blnMatch = 0; u8 dev_name[WPS_MAX_DEVICE_NAME_LEN] = {0x00}; uint dev_len = 0; - u8 dev_name_str[WPS_MAX_DEVICE_NAME_LEN + 5] = {0x00}; /* +5 is for the str "devN =", we have to clear it at wrqu->data.pointer */ + u8 dev_name_str[WPS_MAX_DEVICE_NAME_LEN + 5] = {0x00}; /* +5 is for the str "devN=", we have to clear it at wrqu->data.pointer */ /* Commented by Albert 20121225 */ /* The input data is the MAC address which the application wants to know its device name. */ @@ -3310,7 +3310,7 @@ static int rtw_p2p_get_device_name(struct net_device *dev, if (wpsie) { rtw_get_wps_attr_content(wpsie, wpsie_len, WPS_ATTR_DEVICE_NAME, dev_name, &dev_len); if (dev_len) { - sprintf(dev_name_str, "\n\nN =%s", dev_name); + sprintf(dev_name_str, "\n\nN=%s", dev_name); blnMatch = 1; } } @@ -3323,7 +3323,7 @@ static int rtw_p2p_get_device_name(struct net_device *dev, spin_unlock_bh(&pmlmepriv->scanned_queue.lock); if (!blnMatch) - sprintf(dev_name_str, "\n\nN = 0000"); + sprintf(dev_name_str, "\n\nN=0000"); if (copy_to_user(wrqu->data.pointer, dev_name_str, 5 + ((dev_len > 17) ? dev_len : 17))) return -EFAULT; @@ -3349,7 +3349,7 @@ static int rtw_p2p_get_invitation_procedure(struct net_device *dev, u8 attr_content[2] = {0x00}; u8 inv_proc_str[17 + 8] = {0x00}; - /* +8 is for the str "InvProc =", we have to clear it at wrqu->data.pointer */ + /* +8 is for the str "InvProc=", we have to clear it at wrqu->data.pointer */ /* Commented by Ouden 20121226 */ /* The application wants to know P2P initiation procedure is supported or not. */ @@ -3397,12 +3397,12 @@ static int rtw_p2p_get_invitation_procedure(struct net_device *dev, spin_unlock_bh(&pmlmepriv->scanned_queue.lock); if (!blnMatch) { - sprintf(inv_proc_str, "\nIP =-1"); + sprintf(inv_proc_str, "\nIP=-1"); } else { if (attr_content[0] & 0x20) - sprintf(inv_proc_str, "\nIP = 1"); + sprintf(inv_proc_str, "\nIP=1"); else - sprintf(inv_proc_str, "\nIP = 0"); + sprintf(inv_proc_str, "\nIP=0"); } if (copy_to_user(wrqu->data.pointer, inv_proc_str, 8 + 17)) return -EFAULT; @@ -3512,7 +3512,7 @@ static int rtw_p2p_invite_req(struct net_device *dev, /* The input data contains two informations. */ /* 1. First information is the P2P device address which you want to send to. */ /* 2. Second information is the group id which combines with GO's mac address, space and GO's ssid. */ - /* Command line sample: iwpriv wlan0 p2p_set invite ="00:11:22:33:44:55 00:E0:4C:00:00:05 DIRECT-xy" */ + /* Command line sample: iwpriv wlan0 p2p_set invite="00:11:22:33:44:55 00:E0:4C:00:00:05 DIRECT-xy" */ /* Format: 00:11:22:33:44:55 00:E0:4C:00:00:05 DIRECT-xy */ DBG_88E("[%s] data = %s\n", __func__, extra); @@ -3805,48 +3805,48 @@ static int rtw_p2p_set(struct net_device *dev, #ifdef CONFIG_88EU_P2P DBG_88E("[%s] extra = %s\n", __func__, extra); - if (!memcmp(extra, "enable =", 7)) { + if (!memcmp(extra, "enable=", 7)) { rtw_wext_p2p_enable(dev, info, wrqu, &extra[7]); - } else if (!memcmp(extra, "setDN =", 6)) { + } else if (!memcmp(extra, "setDN=", 6)) { wrqu->data.length -= 6; rtw_p2p_setDN(dev, info, wrqu, &extra[6]); - } else if (!memcmp(extra, "profilefound =", 13)) { + } else if (!memcmp(extra, "profilefound=", 13)) { wrqu->data.length -= 13; rtw_p2p_profilefound(dev, info, wrqu, &extra[13]); - } else if (!memcmp(extra, "prov_disc =", 10)) { + } else if (!memcmp(extra, "prov_disc=", 10)) { wrqu->data.length -= 10; rtw_p2p_prov_disc(dev, info, wrqu, &extra[10]); - } else if (!memcmp(extra, "nego =", 5)) { + } else if (!memcmp(extra, "nego=", 5)) { wrqu->data.length -= 5; rtw_p2p_connect(dev, info, wrqu, &extra[5]); - } else if (!memcmp(extra, "intent =", 7)) { + } else if (!memcmp(extra, "intent=", 7)) { /* Commented by Albert 2011/03/23 */ /* The wrqu->data.length will include the null character */ /* So, we will decrease 7 + 1 */ wrqu->data.length -= 8; rtw_p2p_set_intent(dev, info, wrqu, &extra[7]); - } else if (!memcmp(extra, "ssid =", 5)) { + } else if (!memcmp(extra, "ssid=", 5)) { wrqu->data.length -= 5; rtw_p2p_set_go_nego_ssid(dev, info, wrqu, &extra[5]); - } else if (!memcmp(extra, "got_wpsinfo =", 12)) { + } else if (!memcmp(extra, "got_wpsinfo=", 12)) { wrqu->data.length -= 12; rtw_p2p_got_wpsinfo(dev, info, wrqu, &extra[12]); - } else if (!memcmp(extra, "listen_ch =", 10)) { + } else if (!memcmp(extra, "listen_ch=", 10)) { /* Commented by Albert 2011/05/24 */ /* The wrqu->data.length will include the null character */ /* So, we will decrease (10 + 1) */ wrqu->data.length -= 11; rtw_p2p_set_listen_ch(dev, info, wrqu, &extra[10]); - } else if (!memcmp(extra, "op_ch =", 6)) { + } else if (!memcmp(extra, "op_ch=", 6)) { /* Commented by Albert 2011/05/24 */ /* The wrqu->data.length will include the null character */ /* So, we will decrease (6 + 1) */ wrqu->data.length -= 7; rtw_p2p_set_op_ch(dev, info, wrqu, &extra[6]); - } else if (!memcmp(extra, "invite =", 7)) { + } else if (!memcmp(extra, "invite=", 7)) { wrqu->data.length -= 8; rtw_p2p_invite_req(dev, info, wrqu, &extra[7]); - } else if (!memcmp(extra, "persistent =", 11)) { + } else if (!memcmp(extra, "persistent=", 11)) { wrqu->data.length -= 11; rtw_p2p_set_persistent(dev, info, wrqu, &extra[11]); } @@ -3887,7 +3887,7 @@ static int rtw_p2p_get(struct net_device *dev, "group_id", 8)) { rtw_p2p_get_groupid(dev, info, wrqu, extra); } else if (!memcmp((__force const char *)wrqu->data.pointer, - "peer_deva_inv", 9)) { + "peer_deva_inv", 13)) { /* Get the P2P device address when receiving the P2P Invitation request frame. */ rtw_p2p_get_peer_devaddr_by_invitation(dev, info, wrqu, extra); } else if (!memcmp((__force const char *)wrqu->data.pointer, @@ -6920,7 +6920,7 @@ static int rtw_mp_ctx(struct net_device *dev, DBG_88E("%s: in =%s\n", __func__, extra); - countPkTx = strncmp(extra, "count =", 5); /* strncmp true is 0 */ + countPkTx = strncmp(extra, "count=", 6); /* strncmp true is 0 */ cotuTx = strncmp(extra, "background", 20); CarrSprTx = strncmp(extra, "background, cs", 20); scTx = strncmp(extra, "background, sc", 20); @@ -7044,7 +7044,7 @@ static int rtw_mp_arx(struct net_device *dev, DBG_88E("%s: %s\n", __func__, input); bStartRx = (strncmp(input, "start", 5) == 0) ? 1 : 0; /* strncmp true is 0 */ - bStopRx = (strncmp(input, "stop", 5) == 0) ? 1 : 0; /* strncmp true is 0 */ + bStopRx = (strncmp(input, "stop", 4) == 0) ? 1 : 0; /* strncmp true is 0 */ bQueryPhy = (strncmp(input, "phy", 3) == 0) ? 1 : 0; /* strncmp true is 0 */ if (bStartRx) { -- cgit v1.2.3-70-g09d2 From 21c5e8408d105386c54603aed2cae9195143d87d Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Mon, 24 Mar 2014 13:45:13 -0600 Subject: staging/usbip: userspace - fix usbipd SIGSEGV from refresh_exported_devices() refresh_exported_devices() doesn't check udev_device_new_from_syspath() return value and passed in null dev to udev_device_get_driver() resulting in a segmentation fault. Change it to check for null return value from both udev_device_new_from_syspath() and udev_device_get_driver(). Signed-off-by: Shuah Khan Signed-off-by: Greg Kroah-Hartman --- drivers/staging/usbip/userspace/libsrc/usbip_host_driver.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/usbip/userspace/libsrc/usbip_host_driver.c b/drivers/staging/usbip/userspace/libsrc/usbip_host_driver.c index c5bf60b135b..92caef7474c 100644 --- a/drivers/staging/usbip/userspace/libsrc/usbip_host_driver.c +++ b/drivers/staging/usbip/userspace/libsrc/usbip_host_driver.c @@ -118,6 +118,7 @@ static int refresh_exported_devices(void) struct udev_list_entry *devices, *dev_list_entry; struct udev_device *dev; const char *path; + const char *driver; enumerate = udev_enumerate_new(udev_context); udev_enumerate_add_match_subsystem(enumerate, "usb"); @@ -128,10 +129,12 @@ static int refresh_exported_devices(void) udev_list_entry_foreach(dev_list_entry, devices) { path = udev_list_entry_get_name(dev_list_entry); dev = udev_device_new_from_syspath(udev_context, path); + if (dev == NULL) + continue; /* Check whether device uses usbip-host driver. */ - if (!strcmp(udev_device_get_driver(dev), - USBIP_HOST_DRV_NAME)) { + driver = udev_device_get_driver(dev); + if (driver != NULL && !strcmp(driver, USBIP_HOST_DRV_NAME)) { edev = usbip_exported_device_new(path); if (!edev) { dbg("usbip_exported_device_new failed"); -- cgit v1.2.3-70-g09d2 From de4734bc651d19ed71ad30222aac9b1416e1bd52 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Tue, 25 Mar 2014 06:47:13 -0600 Subject: staging/usbip: fix store_attach() sscanf return value check sscanf() parses the input buffer for four input items. However, the return value check is incorrect, as it checks for one input item instead of four which is what it is expecting in the input buffer. As a result, sscanf() will always fail even when the input buffer is correct. Signed-off-by: Shuah Khan Signed-off-by: Greg Kroah-Hartman --- drivers/staging/usbip/vhci_sysfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/usbip/vhci_sysfs.c b/drivers/staging/usbip/vhci_sysfs.c index 47bddcdde0a..211f43f67ea 100644 --- a/drivers/staging/usbip/vhci_sysfs.c +++ b/drivers/staging/usbip/vhci_sysfs.c @@ -184,7 +184,7 @@ static ssize_t store_attach(struct device *dev, struct device_attribute *attr, * @devid: unique device identifier in a remote host * @speed: usb device speed in a remote host */ - if (sscanf(buf, "%u %u %u %u", &rhport, &sockfd, &devid, &speed) != 1) + if (sscanf(buf, "%u %u %u %u", &rhport, &sockfd, &devid, &speed) != 4) return -EINVAL; usbip_dbg_vhci_sysfs("rhport(%u) sockfd(%u) devid(%u) speed(%u)\n", -- cgit v1.2.3-70-g09d2 From d06fb58cb63c66ddcc2ac94edf99f505f4919da0 Mon Sep 17 00:00:00 2001 From: Paul Bolle Date: Thu, 3 Apr 2014 10:32:17 +0200 Subject: staging: fpgaboot: clean up Makefile This Makefile tries to set the DEBUG macro but it uses an unknown Kconfig macro to do so. Since no code appears to even care about the DEBUG macro this line can safely be removed. Signed-off-by: Paul Bolle Reviewed-by: Insop Song Signed-off-by: Greg Kroah-Hartman --- drivers/staging/gs_fpgaboot/Makefile | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/gs_fpgaboot/Makefile b/drivers/staging/gs_fpgaboot/Makefile index 34cb606e0e3..d2f0211ba54 100644 --- a/drivers/staging/gs_fpgaboot/Makefile +++ b/drivers/staging/gs_fpgaboot/Makefile @@ -1,4 +1,2 @@ gs_fpga-y += gs_fpgaboot.o io.o obj-$(CONFIG_GS_FPGABOOT) += gs_fpga.o - -ccflags-$(CONFIG_GS_FPGA_DEBUG) := -DDEBUG -- cgit v1.2.3-70-g09d2 From 1a52489318c16aaff71059b3892a1a2f3bb8ecec Mon Sep 17 00:00:00 2001 From: Daeseok Youn Date: Wed, 26 Mar 2014 12:01:48 +0900 Subject: staging: vme: fix memory leak in vme_user_probe() If vme_master_request() returns NULL when it failed, it need to free buffers for master. And also removes unreachable code in vme_user_probe(). Signed-off-by: Daeseok Youn Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vme/devices/vme_user.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/vme/devices/vme_user.c b/drivers/staging/vme/devices/vme_user.c index 79279271567..ffb4eeefddd 100644 --- a/drivers/staging/vme/devices/vme_user.c +++ b/drivers/staging/vme/devices/vme_user.c @@ -776,7 +776,8 @@ static int vme_user_probe(struct vme_dev *vdev) image[i].kern_buf = kmalloc(image[i].size_buf, GFP_KERNEL); if (image[i].kern_buf == NULL) { err = -ENOMEM; - goto err_master_buf; + vme_master_free(image[i].resource); + goto err_master; } } @@ -819,8 +820,6 @@ static int vme_user_probe(struct vme_dev *vdev) return 0; - /* Ensure counter set correcty to destroy all sysfs devices */ - i = VME_DEVS; err_sysfs: while (i > 0) { i--; @@ -830,12 +829,10 @@ err_sysfs: /* Ensure counter set correcty to unalloc all master windows */ i = MASTER_MAX + 1; -err_master_buf: - for (i = MASTER_MINOR; i < (MASTER_MAX + 1); i++) - kfree(image[i].kern_buf); err_master: while (i > MASTER_MINOR) { i--; + kfree(image[i].kern_buf); vme_master_free(image[i].resource); } -- cgit v1.2.3-70-g09d2 From 14e6e35d04995c118f41582299f6861ab209bdb3 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 25 Mar 2014 16:48:35 +0100 Subject: staging: gs_fpgaboot: remove __TIMESTAMP__ macro We specifically build the kernel with -Werror=date-time to detect such macros, which gives us this error: gs_fpgaboot/gs_fpgaboot.c:376:44: error: macro "__TIMESTAMP__" might prevent reproducible builds [-Werror=date-time] pr_info("built at %s UTC\n", __TIMESTAMP__); The obvious fix is to remove the printk output line. Signed-off-by: Arnd Bergmann Signed-off-by: Insop Song Acked-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman --- drivers/staging/gs_fpgaboot/gs_fpgaboot.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/gs_fpgaboot/gs_fpgaboot.c b/drivers/staging/gs_fpgaboot/gs_fpgaboot.c index 89bc84d833e..7506900c9b8 100644 --- a/drivers/staging/gs_fpgaboot/gs_fpgaboot.c +++ b/drivers/staging/gs_fpgaboot/gs_fpgaboot.c @@ -373,7 +373,6 @@ static int __init gs_fpgaboot_init(void) r = -1; pr_info("FPGA DOWNLOAD --->\n"); - pr_info("built at %s UTC\n", __TIMESTAMP__); pr_info("FPGA image file name: %s\n", file); -- cgit v1.2.3-70-g09d2 From f5d197b614d8fbc5c25307e7eff1d663653966fa Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Tue, 15 Apr 2014 19:43:20 +0200 Subject: staging: rtl8723au: Fix buffer overflow in rtw_get_wfd_ie() Add bounds checking to not allow WFD Information Elements larger than 128, and make sure we use the correct buffer size MAX_WFD_IE_LEN instea of hardcoding the size. This also simplifies rtw_get_wfd_ie() by using the cfg80211 infrastructure. Reported-by: Dan Carpenter Signed-off-by: Jes Sorensen Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723au/core/rtw_ieee80211.c | 46 +++++++------------------- drivers/staging/rtl8723au/core/rtw_mlme_ext.c | 2 +- drivers/staging/rtl8723au/core/rtw_p2p.c | 4 +-- drivers/staging/rtl8723au/core/rtw_wlan_util.c | 2 +- 4 files changed, 16 insertions(+), 38 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8723au/core/rtw_ieee80211.c b/drivers/staging/rtl8723au/core/rtw_ieee80211.c index 780631fd3b6..a48ab25a7d8 100644 --- a/drivers/staging/rtl8723au/core/rtw_ieee80211.c +++ b/drivers/staging/rtl8723au/core/rtw_ieee80211.c @@ -1496,45 +1496,23 @@ void rtw_wlan_bssid_ex_remove_p2p_attr23a(struct wlan_bssid_ex *bss_ex, u8 attr_ int rtw_get_wfd_ie(u8 *in_ie, int in_len, u8 *wfd_ie, uint *wfd_ielen) { int match; - uint cnt = 0; - u8 eid, wfd_oui[4] = {0x50, 0x6F, 0x9A, 0x0A}; + const u8 *ie; - match = false; + match = 0; - if (in_len < 0) { + if (in_len < 0) return match; - } - - while (cnt < in_len) - { - eid = in_ie[cnt]; - if ((eid == _VENDOR_SPECIFIC_IE_) && - !memcmp(&in_ie[cnt+2], wfd_oui, 4)) { - if (wfd_ie != NULL) { - memcpy(wfd_ie, &in_ie[cnt], in_ie[cnt + 1] + 2); - - } else { - if (wfd_ielen != NULL) { - *wfd_ielen = 0; - } - } - - if (wfd_ielen != NULL) { - *wfd_ielen = in_ie[cnt + 1] + 2; - } - - cnt += in_ie[cnt + 1] + 2; - - match = true; - break; - } else { - cnt += in_ie[cnt + 1] +2; /* goto next */ - } - } + ie = cfg80211_find_vendor_ie(0x506F9A, 0x0A, in_ie, in_len); + if (ie && (ie[1] <= (MAX_WFD_IE_LEN - 2))) { + if (wfd_ie) { + *wfd_ielen = ie[1] + 2; + memcpy(wfd_ie, ie, ie[1] + 2); + } else + if (wfd_ielen) + *wfd_ielen = 0; - if (match == true) { - match = cnt; + match = 1; } return match; diff --git a/drivers/staging/rtl8723au/core/rtw_mlme_ext.c b/drivers/staging/rtl8723au/core/rtw_mlme_ext.c index 4c753639ea5..1f3e8a0aece 100644 --- a/drivers/staging/rtl8723au/core/rtw_mlme_ext.c +++ b/drivers/staging/rtl8723au/core/rtw_mlme_ext.c @@ -1281,7 +1281,7 @@ unsigned int OnAssocReq23a(struct rtw_adapter *padapter, struct recv_frame *prec u8 p2p_status_code = P2P_STATUS_SUCCESS; u8 *p2pie; u32 p2pielen = 0; - u8 wfd_ie[ 128 ] = { 0x00 }; + u8 wfd_ie[MAX_WFD_IE_LEN] = { 0x00 }; u32 wfd_ielen = 0; #endif /* CONFIG_8723AU_P2P */ diff --git a/drivers/staging/rtl8723au/core/rtw_p2p.c b/drivers/staging/rtl8723au/core/rtw_p2p.c index 27a6cc76973..1a961e3f3a5 100644 --- a/drivers/staging/rtl8723au/core/rtw_p2p.c +++ b/drivers/staging/rtl8723au/core/rtw_p2p.c @@ -2535,7 +2535,7 @@ u8 process_p2p_group_negotation_req23a(struct wifidirect_info *pwdinfo, u8 *pfra u16 wps_devicepassword_id = 0x0000; uint wps_devicepassword_id_len = 0; #ifdef CONFIG_8723AU_P2P - u8 wfd_ie[ 128 ] = { 0x00 }; + u8 wfd_ie[MAX_WFD_IE_LEN] = { 0x00 }; u32 wfd_ielen = 0; #endif /* CONFIG_8723AU_P2P */ @@ -2741,7 +2741,7 @@ u8 process_p2p_group_negotation_resp23a(struct wifidirect_info *pwdinfo, u8 *pfr u32 ies_len; u8 * p2p_ie; #ifdef CONFIG_8723AU_P2P - u8 wfd_ie[ 128 ] = { 0x00 }; + u8 wfd_ie[MAX_WFD_IE_LEN] = { 0x00 }; u32 wfd_ielen = 0; #endif /* CONFIG_8723AU_P2P */ diff --git a/drivers/staging/rtl8723au/core/rtw_wlan_util.c b/drivers/staging/rtl8723au/core/rtw_wlan_util.c index 0dfcfbce3b5..e743b053b8a 100644 --- a/drivers/staging/rtl8723au/core/rtw_wlan_util.c +++ b/drivers/staging/rtl8723au/core/rtw_wlan_util.c @@ -570,7 +570,7 @@ void flush_all_cam_entry23a(struct rtw_adapter *padapter) int WFD_info_handler(struct rtw_adapter *padapter, struct ndis_802_11_var_ies * pIE) { struct wifidirect_info *pwdinfo; - u8 wfd_ie[128] = {0x00}; + u8 wfd_ie[MAX_WFD_IE_LEN] = {0x00}; u32 wfd_ielen = 0; pwdinfo = &padapter->wdinfo; -- cgit v1.2.3-70-g09d2 From 2dda47d1a416750bf69eb11dd9b6607d18287b0c Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 3 Apr 2014 11:32:06 +0200 Subject: platform: Fix timberdale dependencies VIDEO_TIMBERDALE selects TIMB_DMA which itself depends on MFD_TIMBERDALE, so VIDEO_TIMBERDALE should either select or depend on MFD_TIMBERDALE as well. I chose to make it depend on it because I think it makes more sense and it is consistent with what other options are doing. Adding a "|| HAS_IOMEM" to the TIMB_DMA dependencies silenced the kconfig warning about unmet direct dependencies but it was wrong: without MFD_TIMBERDALE, TIMB_DMA is useless as the driver has no device to bind to. Signed-off-by: Jean Delvare Cc: Vinod Koul Cc: Dan Williams Cc: Mauro Carvalho Chehab Signed-off-by: Vinod Koul --- drivers/dma/Kconfig | 2 +- drivers/media/platform/Kconfig | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index ba06d1d2f99..5c5863842de 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -197,7 +197,7 @@ config AMCC_PPC440SPE_ADMA config TIMB_DMA tristate "Timberdale FPGA DMA support" - depends on MFD_TIMBERDALE || HAS_IOMEM + depends on MFD_TIMBERDALE select DMA_ENGINE help Enable support for the Timberdale FPGA DMA engine. diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index c137abfa0c5..20f1655e6d7 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -56,7 +56,7 @@ config VIDEO_VIU config VIDEO_TIMBERDALE tristate "Support for timberdale Video In/LogiWIN" - depends on VIDEO_V4L2 && I2C && DMADEVICES + depends on MFD_TIMBERDALE && VIDEO_V4L2 && I2C && DMADEVICES select DMA_ENGINE select TIMB_DMA select VIDEO_ADV7180 -- cgit v1.2.3-70-g09d2 From f3817e777ca3a089381a5b2370fbb869c3bcce6f Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 3 Apr 2014 10:29:33 +0300 Subject: dmaengine: sirf: off by one in of_dma_sirfsoc_xlate() The ">" here should be ">=" or we are one step beyond the end of the sdma->channels[] array. Fixes: 2e041c94628c ('dmaengine: sirf: enable generic dt binding for dma channels') Signed-off-by: Dan Carpenter Acked-by: Barry Song Signed-off-by: Vinod Koul --- drivers/dma/sirf-dma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/dma/sirf-dma.c b/drivers/dma/sirf-dma.c index a1bd8298d55..03f7820fa33 100644 --- a/drivers/dma/sirf-dma.c +++ b/drivers/dma/sirf-dma.c @@ -666,7 +666,7 @@ static struct dma_chan *of_dma_sirfsoc_xlate(struct of_phandle_args *dma_spec, struct sirfsoc_dma *sdma = ofdma->of_dma_data; unsigned int request = dma_spec->args[0]; - if (request > SIRFSOC_DMA_CHANNELS) + if (request >= SIRFSOC_DMA_CHANNELS) return NULL; return dma_get_slave_channel(&sdma->channels[request].chan); -- cgit v1.2.3-70-g09d2 From 8edc51c197b8f409bef7b21755254e6f3ce7ed23 Mon Sep 17 00:00:00 2001 From: Yuan Yao Date: Fri, 4 Apr 2014 12:27:55 +0800 Subject: dma: fix eDMA driver as a subsys_initcall Because of some driver base on DMA, changed the initcall order as subsys_initcall. Signed-off-by: Yuan Yao Signed-off-by: Vinod Koul --- drivers/dma/fsl-edma.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/dma/fsl-edma.c b/drivers/dma/fsl-edma.c index 381e793184b..b396a7fb53a 100644 --- a/drivers/dma/fsl-edma.c +++ b/drivers/dma/fsl-edma.c @@ -968,7 +968,17 @@ static struct platform_driver fsl_edma_driver = { .remove = fsl_edma_remove, }; -module_platform_driver(fsl_edma_driver); +static int __init fsl_edma_init(void) +{ + return platform_driver_register(&fsl_edma_driver); +} +subsys_initcall(fsl_edma_init); + +static void __exit fsl_edma_exit(void) +{ + platform_driver_unregister(&fsl_edma_driver); +} +module_exit(fsl_edma_exit); MODULE_ALIAS("platform:fsl-edma"); MODULE_DESCRIPTION("Freescale eDMA engine driver"); -- cgit v1.2.3-70-g09d2 From 22bbd5d949dc7fdd72a4e78e767fa09d8e54b446 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Fri, 4 Apr 2014 16:31:05 -0600 Subject: gpu: host1x: handle the correct # of syncpt regs BIT_WORD() truncates rather than rounds, so the loops in syncpt_thresh_isr() and _host1x_intr_disable_all_syncpt_intrs() use <= rather than < in an attempt to process the correct number of registers when rounding of the conversion of count of bits to count of words is necessary. However, when rounding isn't necessary because the value is already a multiple of the divisor (as is the case for all values of nb_pts the code actually sees), this causes one too many registers to be processed. Solve this by using and explicit DIV_ROUND_UP() call, rather than BIT_WORD(), and comparing with < rather than <=. Fixes: 7ede0b0bf3e2 ("gpu: host1x: Add syncpoint wait and interrupts") Cc: # 3.10 Signed-off-by: Stephen Warren Acked-By: Terje Bergstrom Signed-off-by: Thierry Reding --- drivers/gpu/host1x/hw/intr_hw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/host1x/hw/intr_hw.c b/drivers/gpu/host1x/hw/intr_hw.c index db9017adfe2..498b37e3905 100644 --- a/drivers/gpu/host1x/hw/intr_hw.c +++ b/drivers/gpu/host1x/hw/intr_hw.c @@ -47,7 +47,7 @@ static irqreturn_t syncpt_thresh_isr(int irq, void *dev_id) unsigned long reg; int i, id; - for (i = 0; i <= BIT_WORD(host->info->nb_pts); i++) { + for (i = 0; i < DIV_ROUND_UP(host->info->nb_pts, 32); i++) { reg = host1x_sync_readl(host, HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(i)); for_each_set_bit(id, ®, BITS_PER_LONG) { @@ -64,7 +64,7 @@ static void _host1x_intr_disable_all_syncpt_intrs(struct host1x *host) { u32 i; - for (i = 0; i <= BIT_WORD(host->info->nb_pts); ++i) { + for (i = 0; i < DIV_ROUND_UP(host->info->nb_pts, 32); ++i) { host1x_sync_writel(host, 0xffffffffu, HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE(i)); host1x_sync_writel(host, 0xffffffffu, -- cgit v1.2.3-70-g09d2 From 32702e96a9f76ea0e0a1d218310d2ac1adbd2907 Mon Sep 17 00:00:00 2001 From: Jack Pham Date: Wed, 26 Mar 2014 10:31:44 -0700 Subject: usb: dwc3: gadget: Iterate only over valid endpoints Make dwc3_gadget_resize_tx_fifos() iterate only over IN endpoints that are actually present, based on the num_in_eps parameter. This terminates the loop so as to prevent dereferencing a potential NULL dwc->eps[i] where i >= (num_in_eps + num_out_eps). Signed-off-by: Jack Pham Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/gadget.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index a740eac74d5..70715eeeded 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -187,15 +187,12 @@ int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc) * improve this algorithm so that we better use the internal * FIFO space */ - for (num = 0; num < DWC3_ENDPOINTS_NUM; num++) { - struct dwc3_ep *dep = dwc->eps[num]; - int fifo_number = dep->number >> 1; + for (num = 0; num < dwc->num_in_eps; num++) { + /* bit0 indicates direction; 1 means IN ep */ + struct dwc3_ep *dep = dwc->eps[(num << 1) | 1]; int mult = 1; int tmp; - if (!(dep->number & 1)) - continue; - if (!(dep->flags & DWC3_EP_ENABLED)) continue; @@ -224,8 +221,7 @@ int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc) dev_vdbg(dwc->dev, "%s: Fifo Addr %04x Size %d\n", dep->name, last_fifo_depth, fifo_size & 0xffff); - dwc3_writel(dwc->regs, DWC3_GTXFIFOSIZ(fifo_number), - fifo_size); + dwc3_writel(dwc->regs, DWC3_GTXFIFOSIZ(num), fifo_size); last_fifo_depth += (fifo_size & 0xffff); } -- cgit v1.2.3-70-g09d2 From 9c1b70361e0b38e4acb8e62b54da66538cb77ff2 Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Wed, 26 Mar 2014 18:46:38 +0200 Subject: usb: gadget: zero: Fix SuperSpeed enumeration for alternate setting 1 It was impossible to enumerate on a SuperSpeed (XHCI) host with alternate setting = 1 due to the wrongly set 'bMaxBurst' field in the SuperSpeed Endpoint Companion descriptor. Testcase: modprobe -r usbtest; modprobe usbtest alt=1 modprobe g_zero plug device to SuperSpeed port on the host. Without this patch the host always complains like so "usb 12-2: Not enough bandwidth for new device state. usb 12-2: Not enough bandwidth for altsetting 1" Bug was introduced by commit cf9a08ae in v3.9 Fixes: cf9a08ae5aec (usb: gadget: convert source sink and loopback to new function interface) Cc: 3.9+ # 3.9+ Reviewed-by: Felipe Balbi Acked-by: Sebastian Andrzej Siewior Signed-off-by: Roger Quadros Signed-off-by: Felipe Balbi --- drivers/usb/gadget/zero.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index 9f170c53e3d..134f354ede6 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c @@ -300,7 +300,7 @@ static int __init zero_bind(struct usb_composite_dev *cdev) ss_opts->isoc_interval = gzero_options.isoc_interval; ss_opts->isoc_maxpacket = gzero_options.isoc_maxpacket; ss_opts->isoc_mult = gzero_options.isoc_mult; - ss_opts->isoc_maxburst = gzero_options.isoc_maxpacket; + ss_opts->isoc_maxburst = gzero_options.isoc_maxburst; ss_opts->bulk_buflen = gzero_options.bulk_buflen; func_ss = usb_get_function(func_inst_ss); -- cgit v1.2.3-70-g09d2 From f45e5f00dacf09362a16339d372fcc96705e40c7 Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Wed, 26 Mar 2014 11:43:09 +0200 Subject: usb: dwc3: core: Fix gadget for system suspend/resume During system resume, if the event buffers are not setup before the gadget controller starts then we start with invalid context and this can lead to bus access errors. This is especially true for platforms that loose the controller context during system suspend. e.g. AM437x. The following backtrace was found when the system is suspended and resumed with g_zero loaded on AM437x-evm (USB cable connected to host all the while). [ 120.981506] WARNING: CPU: 0 PID: 1656 at drivers/bus/omap_l3_noc.c:137 l3_interrupt_handler+0x198/0x28c() [ 120.981514] L3 custom error: MASTER:USB0 WR TARGET:GPMC [ 120.981638] Modules linked in: g_mass_storage usb_f_mass_storage libcomposite configfs bufferclass_ti(O) omaplfb(O) cryptodev(O) dwc3 snd_soc_evm snd_soc_omap snd_pe [ 120.981659] CPU: 0 PID: 1656 Comm: sh Tainted: G O 3.12.10-gc559824 #1 [ 120.981669] Backtrace: [ 120.981705] [] (dump_backtrace+0x0/0x10c) from [] (show_stack+0x18/0x1c) [ 120.981730] r6:c02819ac r5:00000009 r4:ec137cb8 r3:00000000 [ 120.981767] [] (show_stack+0x0/0x1c) from [] (dump_stack+0x20/0x28) [ 120.981802] [] (dump_stack+0x0/0x28) from [] (warn_slowpath_common+0x70/0x90) [ 120.981830] [] (warn_slowpath_common+0x0/0x90) from [] (warn_slowpath_fmt+0x38/0x40) [ 120.981856] r8:c0855eb0 r7:00000002 r6:f1000700 r5:00000007 r4:80080003 [ 120.981886] [] (warn_slowpath_fmt+0x0/0x40) from [] (l3_interrupt_handler+0x198/0x28c) [ 120.981900] r3:c0801ab8 r2:c06cb354 [ 120.981936] [] (l3_interrupt_handler+0x0/0x28c) from [] (handle_irq_event_percpu+0x54/0x1b8) [ 120.981962] [] (handle_irq_event_percpu+0x0/0x1b8) from [] (handle_irq_event+0x30/0x40) [ 120.981993] [] (handle_irq_event+0x0/0x40) from [] (handle_fasteoi_irq+0x74/0x128) [ 120.982006] r4:ed0056c0 r3:00000000 [ 120.982033] [] (handle_fasteoi_irq+0x0/0x128) from [] (generic_handle_irq+0x28/0x38) [ 120.982046] r4:0000002a r3:c0073fe4 [ 120.982085] [] (generic_handle_irq+0x0/0x38) from [] (handle_IRQ+0x38/0x8c) [ 120.982098] r4:c080137c r3:00000182 [ 120.982124] [] (handle_IRQ+0x0/0x8c) from [] (gic_handle_irq+0x30/0x5c) [ 120.982145] r6:ec137dd0 r5:c07ac480 r4:fa24010c r3:00000100 [ 120.982169] [] (gic_handle_irq+0x0/0x5c) from [] (__irq_svc+0x40/0x54) [ 120.982179] Exception stack(0xec137dd0 to 0xec137e18) [ 120.982195] 7dc0: 00000000 a00001d3 00000000 00000004 [ 120.982216] 7de0: a0000153 ec1d9010 c080de90 ec137e30 c080debc 00000000 ed756e44 ec137e2c [ 120.982232] 7e00: ec137de0 ec137e18 bf1150e4 bf115474 60000153 ffffffff [ 120.982253] r7:ec137e04 r6:ffffffff r5:60000153 r4:bf115474 [ 120.982327] [] (dwc3_complete+0x0/0x40 [dwc3]) from [] (dpm_complete+0xd4/0x19c) [ 120.982341] r5:ed756e10 r4:ed756e64 [ 120.982370] [] (dpm_complete+0x0/0x19c) from [] (dpm_resume_end+0x1c/0x20) [ 120.982400] [] (dpm_resume_end+0x0/0x20) from [] (suspend_devices_and_enter+0x118/0x33c) [ 120.982412] r4:c0833da4 r3:00000000 [ 120.982436] [] (suspend_devices_and_enter+0x0/0x33c) from [] (pm_suspend+0x218/0x254) [ 120.982458] [] (pm_suspend+0x0/0x254) from [] (state_store+0x70/0xc0) [ 120.982478] r6:c057a6cc r5:c06a8320 r4:00000003 r3:0000006d [ 120.982515] [] (state_store+0x0/0xc0) from [] (kobj_attr_store+0x1c/0x28) [ 120.982546] [] (kobj_attr_store+0x0/0x28) from [] (sysfs_write_file+0x170/0x1a4) [ 120.982583] [] (sysfs_write_file+0x0/0x1a4) from [] (vfs_write+0xb8/0x190) [ 120.982611] [] (vfs_write+0x0/0x190) from [] (SyS_write+0x44/0x78) [ 120.982641] [] (SyS_write+0x0/0x78) from [] (ret_fast_syscall+0x0/0x30) Signed-off-by: Roger Quadros Acked-by: Felipe Balbi Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index d001417e8e3..10aaaae9af2 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -821,6 +821,7 @@ static void dwc3_complete(struct device *dev) spin_lock_irqsave(&dwc->lock, flags); + dwc3_event_buffers_setup(dwc); switch (dwc->dr_mode) { case USB_DR_MODE_PERIPHERAL: case USB_DR_MODE_OTG: @@ -828,7 +829,6 @@ static void dwc3_complete(struct device *dev) /* FALLTHROUGH */ case USB_DR_MODE_HOST: default: - dwc3_event_buffers_setup(dwc); break; } -- cgit v1.2.3-70-g09d2 From 5cdf7d5be8443ba0e14a5cfe551c59f931983647 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Thu, 27 Mar 2014 08:09:21 +0100 Subject: usb: gadget: gadgetfs: Initialize CHIP to NULL before UDC probe Otherwise the value from the last probe would be retained that possibly is freed since (the UDC is removed) and therefore no longer relevant. Reproducible with the dummy UDC: modprobe dummy_hcd mount -t gadgetfs gadgetfs /dev/gadget umount /dev/gadget rmmod dummy_hcd mount -t gadgetfs gadgetfs /dev/gadget BUG: unable to handle kernel paging request at ffffffffa066fd9d Call Trace: [] ? d_alloc_name+0x22/0x50 [] ? selinux_d_instantiate+0x1c/0x20 [] gadgetfs_create_file+0x27/0xa0 [gadgetfs] [] ? setup_req.isra.4+0x80/0x80 [gadgetfs] [] gadgetfs_fill_super+0x13c/0x180 [gadgetfs] [] mount_single+0x92/0xc0 [] gadgetfs_mount+0x18/0x20 [gadgetfs] [] mount_fs+0x39/0x1b0 [] ? __alloc_percpu+0x10/0x20 [] vfs_kern_mount+0x63/0xf0 [] do_mount+0x23e/0xac0 [] ? strndup_user+0x4b/0xf0 [] SyS_mount+0x83/0xc0 [] system_call_fastpath+0x16/0x1b Signed-off-by: Lubomir Rintel Signed-off-by: Felipe Balbi --- drivers/usb/gadget/inode.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index b5be6f0308c..a925d0cbcd4 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -2043,6 +2043,7 @@ gadgetfs_fill_super (struct super_block *sb, void *opts, int silent) return -ESRCH; /* fake probe to determine $CHIP */ + CHIP = NULL; usb_gadget_probe_driver(&probe_driver); if (!CHIP) return -ENODEV; -- cgit v1.2.3-70-g09d2 From 0fca91b8a446d4a38b8f3d4772c4a8665ebcd7b2 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Wed, 2 Apr 2014 11:46:51 +0200 Subject: usb: musb: dsps: move debugfs_remove_recursive() When the platform initialization fails due to missing resources, it will return -EPROBE_DEFER after dsps_musb_init() has been called. dsps_musb_init() calls dsps_musb_dbg_init() to allocate the debugfs nodes. At a later point in time, the probe will be retried, and dsps_musb_dbg_init() will be called again. debugfs_create_dir() will fail this time, as the node already exists, and so the entire device probe will fail with -ENOMEM. Fix this by moving debugfs_remove_recursive() from dsps_remove() to the plaform's exit function, so it will be cleanly torn down when the probe fails. It also feels more natural this way, as .exit is the counterpart to .init. Signed-off-by: Daniel Mack Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_dsps.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index 3372ded5def..e2fd263585d 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -470,8 +470,9 @@ static int dsps_musb_exit(struct musb *musb) struct dsps_glue *glue = dev_get_drvdata(dev->parent); del_timer_sync(&glue->timer); - usb_phy_shutdown(musb->xceiv); + debugfs_remove_recursive(glue->dbgfs_root); + return 0; } @@ -708,8 +709,6 @@ static int dsps_remove(struct platform_device *pdev) pm_runtime_put(&pdev->dev); pm_runtime_disable(&pdev->dev); - debugfs_remove_recursive(glue->dbgfs_root); - return 0; } -- cgit v1.2.3-70-g09d2 From fc696881c6ec991f39a2f93d41f9ae841c6ace38 Mon Sep 17 00:00:00 2001 From: Suresh Gupta Date: Wed, 2 Apr 2014 22:26:46 +0530 Subject: usb : gadget : fsl: fix the fault issue on rmmod completion in udc_controller->done should be assign with proper value before complete called. The complete called in fsl_udc_release which intern called from usb_del_gadget_udc, so moving assignment before calling usb_del_gadget_udc Signed-off-by: Suresh Gupta Signed-off-by: Felipe Balbi --- drivers/usb/gadget/fsl_udc_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c index 15960af0f67..dcd0b07ae3a 100644 --- a/drivers/usb/gadget/fsl_udc_core.c +++ b/drivers/usb/gadget/fsl_udc_core.c @@ -2532,8 +2532,8 @@ static int __exit fsl_udc_remove(struct platform_device *pdev) if (!udc_controller) return -ENODEV; - usb_del_gadget_udc(&udc_controller->gadget); udc_controller->done = &done; + usb_del_gadget_udc(&udc_controller->gadget); fsl_udc_clk_release(); -- cgit v1.2.3-70-g09d2 From ae8dd0cc4146740e24ffb2092530c47e838001c5 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Fri, 4 Apr 2014 22:27:59 -0300 Subject: usb: gadget: rndis: Include "u_rndis.h" Include "u_rndis.h" in order to fix the following sparse warning: drivers/usb/gadget/rndis.c:1144:5: warning: symbol 'rndis_init' was not declared. Should it be static? drivers/usb/gadget/rndis.c:1177:6: warning: symbol 'rndis_exit' was not declared. Should it be static? Signed-off-by: Fabio Estevam Signed-off-by: Felipe Balbi --- drivers/usb/gadget/rndis.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c index d822d822efb..7ed452d90f4 100644 --- a/drivers/usb/gadget/rndis.c +++ b/drivers/usb/gadget/rndis.c @@ -35,6 +35,7 @@ #include #include +#include "u_rndis.h" #undef VERBOSE_DEBUG -- cgit v1.2.3-70-g09d2 From 9dc9cb0c9ad0f999e29ce4c4f307cd2abbe752d3 Mon Sep 17 00:00:00 2001 From: Mathias Krause Date: Tue, 15 Apr 2014 07:58:15 +0200 Subject: usb: phy: return an error in usb_get_phy() if try_module_get() fails In case we found a matching USB PHY in usb_get_phy() but the call to try_module_get() fails, we shouldn't return a (probably soon dangling) pointer but an ERR_PTR instead. Signed-off-by: Mathias Krause Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/phy/phy.c b/drivers/usb/phy/phy.c index 8afa813d690..36b6bce33b2 100644 --- a/drivers/usb/phy/phy.c +++ b/drivers/usb/phy/phy.c @@ -132,6 +132,9 @@ struct usb_phy *usb_get_phy(enum usb_phy_type type) if (IS_ERR(phy) || !try_module_get(phy->dev->driver->owner)) { pr_debug("PHY: unable to find transceiver of type %s\n", usb_phy_type_string(type)); + if (!IS_ERR(phy)) + phy = ERR_PTR(-ENODEV); + goto err0; } -- cgit v1.2.3-70-g09d2 From 97839ca4b06ab27790700ad7da6be9a75fc0cc1d Mon Sep 17 00:00:00 2001 From: Chao Bi Date: Mon, 14 Apr 2014 11:19:53 +0800 Subject: usb: gadget: ffs: race between ffs_epfile_io() and ffs_func_eps_disable() ffs_epfile_io() is called from userspace, while ffs_func_eps_disable() might be called from USB disconnect interrupt, the two functions would run in parallel but they are not well protected, that epfile->ep would be removed by ffs_func_eps_disable() during ffs_epfile_io() is referring this pointer, then it leads to kernel PANIC. The scenario is as below: Thread 1 Thread 2 | | SyS_read dwc3_gadget_disconnect_interrupt | | ffs_epfile_read reset_config | | ffs_epfile_io ffs_func_eps_disable | | ----- usb_ep_disable(): epfile->ep->ep->desc = NULL | | usb_ep_align_maybe(): ----- it refers ep->desc->wMaxPacketSize ----- Signed-off-by: Chao Bi Signed-off-by: Felipe Balbi --- drivers/usb/gadget/f_fs.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c index 2e164dca08e..1e12b3ee56f 100644 --- a/drivers/usb/gadget/f_fs.c +++ b/drivers/usb/gadget/f_fs.c @@ -745,6 +745,12 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) */ struct usb_gadget *gadget = epfile->ffs->gadget; + spin_lock_irq(&epfile->ffs->eps_lock); + /* In the meantime, endpoint got disabled or changed. */ + if (epfile->ep != ep) { + spin_unlock_irq(&epfile->ffs->eps_lock); + return -ESHUTDOWN; + } /* * Controller may require buffer size to be aligned to * maxpacketsize of an out endpoint. @@ -752,6 +758,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) data_len = io_data->read ? usb_ep_align_maybe(gadget, ep->ep, io_data->len) : io_data->len; + spin_unlock_irq(&epfile->ffs->eps_lock); data = kmalloc(data_len, GFP_KERNEL); if (unlikely(!data)) -- cgit v1.2.3-70-g09d2 From c23fdc7da4853c25509255419bf88ed94cd42a5b Mon Sep 17 00:00:00 2001 From: Mohit Kumar Date: Wed, 16 Apr 2014 10:23:28 -0600 Subject: PCI: designware: Fix comment for setting number of lanes Corrects comment for setting number of lanes. Signed-off-by: Mohit Kumar Signed-off-by: Bjorn Helgaas Acked-by: Jingoo Han --- drivers/pci/host/pcie-designware.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c index 509a29d8450..8909e7748e6 100644 --- a/drivers/pci/host/pcie-designware.c +++ b/drivers/pci/host/pcie-designware.c @@ -764,7 +764,7 @@ void dw_pcie_setup_rc(struct pcie_port *pp) u32 membase; u32 memlimit; - /* set the number of lines as 4 */ + /* set the number of lanes */ dw_pcie_readl_rc(pp, PCIE_PORT_LINK_CONTROL, &val); val &= ~PORT_LINK_MODE_MASK; switch (pp->lanes) { -- cgit v1.2.3-70-g09d2 From 017fcdc30cdae18c0946eef1ece1f14b4c7897ba Mon Sep 17 00:00:00 2001 From: Mohit Kumar Date: Wed, 16 Apr 2014 10:23:34 -0600 Subject: PCI: designware: Fix iATU programming for cfg1, io and mem viewport This patch corrects iATU programming for cfg1, io and mem viewport. Enable ATU only after configuring it. Signed-off-by: Mohit Kumar Signed-off-by: Ajay Khandelwal Signed-off-by: Bjorn Helgaas Acked-by: Jingoo Han Cc: stable@vger.kernel.org --- drivers/pci/host/pcie-designware.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c index 8909e7748e6..a9a62ce4bf0 100644 --- a/drivers/pci/host/pcie-designware.c +++ b/drivers/pci/host/pcie-designware.c @@ -520,13 +520,13 @@ static void dw_pcie_prog_viewport_cfg1(struct pcie_port *pp, u32 busdev) dw_pcie_writel_rc(pp, PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX1, PCIE_ATU_VIEWPORT); dw_pcie_writel_rc(pp, PCIE_ATU_TYPE_CFG1, PCIE_ATU_CR1); - dw_pcie_writel_rc(pp, PCIE_ATU_ENABLE, PCIE_ATU_CR2); dw_pcie_writel_rc(pp, pp->cfg1_base, PCIE_ATU_LOWER_BASE); dw_pcie_writel_rc(pp, (pp->cfg1_base >> 32), PCIE_ATU_UPPER_BASE); dw_pcie_writel_rc(pp, pp->cfg1_base + pp->config.cfg1_size - 1, PCIE_ATU_LIMIT); dw_pcie_writel_rc(pp, busdev, PCIE_ATU_LOWER_TARGET); dw_pcie_writel_rc(pp, 0, PCIE_ATU_UPPER_TARGET); + dw_pcie_writel_rc(pp, PCIE_ATU_ENABLE, PCIE_ATU_CR2); } static void dw_pcie_prog_viewport_mem_outbound(struct pcie_port *pp) @@ -535,7 +535,6 @@ static void dw_pcie_prog_viewport_mem_outbound(struct pcie_port *pp) dw_pcie_writel_rc(pp, PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX0, PCIE_ATU_VIEWPORT); dw_pcie_writel_rc(pp, PCIE_ATU_TYPE_MEM, PCIE_ATU_CR1); - dw_pcie_writel_rc(pp, PCIE_ATU_ENABLE, PCIE_ATU_CR2); dw_pcie_writel_rc(pp, pp->mem_base, PCIE_ATU_LOWER_BASE); dw_pcie_writel_rc(pp, (pp->mem_base >> 32), PCIE_ATU_UPPER_BASE); dw_pcie_writel_rc(pp, pp->mem_base + pp->config.mem_size - 1, @@ -543,6 +542,7 @@ static void dw_pcie_prog_viewport_mem_outbound(struct pcie_port *pp) dw_pcie_writel_rc(pp, pp->config.mem_bus_addr, PCIE_ATU_LOWER_TARGET); dw_pcie_writel_rc(pp, upper_32_bits(pp->config.mem_bus_addr), PCIE_ATU_UPPER_TARGET); + dw_pcie_writel_rc(pp, PCIE_ATU_ENABLE, PCIE_ATU_CR2); } static void dw_pcie_prog_viewport_io_outbound(struct pcie_port *pp) @@ -551,7 +551,6 @@ static void dw_pcie_prog_viewport_io_outbound(struct pcie_port *pp) dw_pcie_writel_rc(pp, PCIE_ATU_REGION_OUTBOUND | PCIE_ATU_REGION_INDEX1, PCIE_ATU_VIEWPORT); dw_pcie_writel_rc(pp, PCIE_ATU_TYPE_IO, PCIE_ATU_CR1); - dw_pcie_writel_rc(pp, PCIE_ATU_ENABLE, PCIE_ATU_CR2); dw_pcie_writel_rc(pp, pp->io_base, PCIE_ATU_LOWER_BASE); dw_pcie_writel_rc(pp, (pp->io_base >> 32), PCIE_ATU_UPPER_BASE); dw_pcie_writel_rc(pp, pp->io_base + pp->config.io_size - 1, @@ -559,6 +558,7 @@ static void dw_pcie_prog_viewport_io_outbound(struct pcie_port *pp) dw_pcie_writel_rc(pp, pp->config.io_bus_addr, PCIE_ATU_LOWER_TARGET); dw_pcie_writel_rc(pp, upper_32_bits(pp->config.io_bus_addr), PCIE_ATU_UPPER_TARGET); + dw_pcie_writel_rc(pp, PCIE_ATU_ENABLE, PCIE_ATU_CR2); } static int dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus, -- cgit v1.2.3-70-g09d2 From f86b3e392780050e5907f1c0f3cb6c4cc05fd6bb Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Wed, 16 Apr 2014 10:23:46 -0600 Subject: PCI: designware: Use new OF interrupt mapping when possible Use new OF interrupt mapping (of_irq_parse_and_map_pci()) when possible. This is the recommended method of doing the IRQ mapping. For old devicetrees we fall back to the previous practice. This makes INTB, INTC, and INTD work on i.MX. Tested-by: Tim Harvey Signed-off-by: Lucas Stach Signed-off-by: Bjorn Helgaas Reviewed-by: Marek Vasut Acked-by: Arnd Bergmann Acked-by: Jingoo Han --- drivers/pci/host/pcie-designware.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c index a9a62ce4bf0..c4e37329447 100644 --- a/drivers/pci/host/pcie-designware.c +++ b/drivers/pci/host/pcie-designware.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -490,7 +491,7 @@ int __init dw_pcie_host_init(struct pcie_port *pp) dw_pci.nr_controllers = 1; dw_pci.private_data = (void **)&pp; - pci_common_init(&dw_pci); + pci_common_init_dev(pp->dev, &dw_pci); pci_assign_unassigned_resources(); #ifdef CONFIG_PCI_DOMAINS dw_pci.domain++; @@ -723,7 +724,7 @@ static struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys) if (pp) { pp->root_bus_nr = sys->busnr; - bus = pci_scan_root_bus(NULL, sys->busnr, &dw_pcie_ops, + bus = pci_scan_root_bus(pp->dev, sys->busnr, &dw_pcie_ops, sys, &sys->resources); } else { bus = NULL; @@ -736,8 +737,13 @@ static struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys) static int dw_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) { struct pcie_port *pp = sys_to_pcie(dev->bus->sysdata); + int irq; - return pp->irq; + irq = of_irq_parse_and_map_pci(dev, slot, pin); + if (!irq) + irq = pp->irq; + + return irq; } static void dw_pcie_add_bus(struct pci_bus *bus) -- cgit v1.2.3-70-g09d2 From f8f2fe7355fb04dd129d49ac0ad440beb44f0f79 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Wed, 16 Apr 2014 10:24:09 -0600 Subject: PCI: rcar: Use new OF interrupt mapping when possible Use new OF interrupt mapping (of_irq_parse_and_map_pci()) when possible. This is the recommended method of doing the IRQ mapping. For old devicetrees we fall back to the previous practice. This allows interrupts to be remapped across bridges. Signed-off-by: Lucas Stach Signed-off-by: Bjorn Helgaas Acked-by: Simon Horman --- drivers/pci/host/pci-rcar-gen2.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/host/pci-rcar-gen2.c b/drivers/pci/host/pci-rcar-gen2.c index fd3e3ab5650..4fe349dcaf5 100644 --- a/drivers/pci/host/pci-rcar-gen2.c +++ b/drivers/pci/host/pci-rcar-gen2.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -180,8 +181,13 @@ static int rcar_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) { struct pci_sys_data *sys = dev->bus->sysdata; struct rcar_pci_priv *priv = sys->private_data; + int irq; + + irq = of_irq_parse_and_map_pci(dev, slot, pin); + if (!irq) + irq = priv->irq; - return priv->irq; + return irq; } #ifdef CONFIG_PCI_DEBUG -- cgit v1.2.3-70-g09d2 From f5d3352b2751f8de7e06e23a04ac0b4c474075e9 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Wed, 16 Apr 2014 10:24:32 -0600 Subject: PCI: tegra: Use new OF interrupt mapping when possible Use new OF interrupt mapping (of_irq_parse_and_map_pci()) when possible. This is the recommended method of doing the IRQ mapping. For old devicetrees we fall back to the previous practice. This allows interrupts to be remapped across bridges. Tested-by: Stephen Warren Signed-off-by: Lucas Stach Signed-off-by: Bjorn Helgaas Acked-by: Arnd Bergmann --- drivers/pci/host/pci-tegra.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c index 330f7e3a32d..083cf37ca04 100644 --- a/drivers/pci/host/pci-tegra.c +++ b/drivers/pci/host/pci-tegra.c @@ -639,10 +639,15 @@ static int tegra_pcie_setup(int nr, struct pci_sys_data *sys) static int tegra_pcie_map_irq(const struct pci_dev *pdev, u8 slot, u8 pin) { struct tegra_pcie *pcie = sys_to_pcie(pdev->bus->sysdata); + int irq; tegra_cpuidle_pcie_irqs_in_use(); - return pcie->irq; + irq = of_irq_parse_and_map_pci(pdev, slot, pin); + if (!irq) + irq = pcie->irq; + + return irq; } static void tegra_pcie_add_bus(struct pci_bus *bus) -- cgit v1.2.3-70-g09d2 From 9ae794ac5e407d3bc3fec785db481d5a2c0fa275 Mon Sep 17 00:00:00 2001 From: David Milburn Date: Wed, 16 Apr 2014 11:43:46 -0500 Subject: ahci: do not request irq for dummy port System may crash in ahci_hw_interrupt() or ahci_thread_fn() when accessing the interrupt status in a port's private_data if the port is actually a DUMMY port. 00:1f.2 SATA controller: Intel Corporation 82801JI (ICH10 Family) SATA AHCI Controller [ 9.352080] ahci 0000:00:1f.2: AHCI 0001.0200 32 slots 6 ports 3 Gbps 0x1 impl SATA mode [ 9.352084] ahci 0000:00:1f.2: flags: 64bit ncq sntf pm led clo pio slum part ccc [ 9.368155] Console: switching to colour frame buffer device 128x48 [ 9.439759] mgag200 0000:11:00.0: fb0: mgadrmfb frame buffer device [ 9.446765] mgag200 0000:11:00.0: registered panic notifier [ 9.470166] scsi1 : ahci [ 9.479166] scsi2 : ahci [ 9.488172] scsi3 : ahci [ 9.497174] scsi4 : ahci [ 9.506175] scsi5 : ahci [ 9.515174] scsi6 : ahci [ 9.518181] ata1: SATA max UDMA/133 abar m2048@0x95c00000 port 0x95c00100 irq 91 [ 9.526448] ata2: DUMMY [ 9.529182] ata3: DUMMY [ 9.531916] ata4: DUMMY [ 9.534650] ata5: DUMMY [ 9.537382] ata6: DUMMY [ 9.576196] [drm] Initialized mgag200 1.0.0 20110418 for 0000:11:00.0 on minor 0 [ 9.845257] ata1: SATA link up 1.5 Gbps (SStatus 113 SControl 300) [ 9.865161] ata1.00: ATAPI: Optiarc DVD RW AD-7580S, FX04, max UDMA/100 [ 9.891407] ata1.00: configured for UDMA/100 [ 9.900525] scsi 1:0:0:0: CD-ROM Optiarc DVD RW AD-7580S FX04 PQ: 0 ANSI: 5 [ 10.247399] iTCO_vendor_support: vendor-support=0 [ 10.261572] iTCO_wdt: Intel TCO WatchDog Timer Driver v1.11 [ 10.269764] iTCO_wdt: unable to reset NO_REBOOT flag, device disabled by hardware/BIOS [ 10.301932] sd 0:2:0:0: [sda] 570310656 512-byte logical blocks: (291 GB/271 GiB) [ 10.317085] sd 0:2:0:0: [sda] Write Protect is off [ 10.328326] sd 0:2:0:0: [sda] Write cache: disabled, read cache: disabled, supports DPO and FUA [ 10.375452] BUG: unable to handle kernel NULL pointer dereference at 000000000000003c [ 10.384217] IP: [] ahci_hw_interrupt+0x100/0x130 [libahci] [ 10.392101] PGD 0 [ 10.394353] Oops: 0000 [#1] SMP [ 10.397978] Modules linked in: sr_mod(+) cdrom sd_mod iTCO_wdt crc_t10dif iTCO_vendor_support crct10dif_common ahci libahci libata lpc_ich mfd_core mgag200 syscopyarea sysfillrect sysimgblt i2c_algo_bit drm_kms_helper ttm drm i2c_core megaraid_sas dm_mirror dm_region_hash dm_log dm_mod [ 10.426499] CPU: 0 PID: 0 Comm: swapper/0 Not tainted 3.15.0-rc1 #1 [ 10.433495] Hardware name: QCI QSSC-S4R/QSSC-S4R, BIOS QSSC-S4R.QCI.01.00.S013.032920111005 03/29/2011 [ 10.443886] task: ffffffff81906460 ti: ffffffff818f0000 task.ti: ffffffff818f0000 [ 10.452239] RIP: 0010:[] [] ahci_hw_interrupt+0x100/0x130 [libahci] [ 10.462838] RSP: 0018:ffff880033c03d98 EFLAGS: 00010046 [ 10.468767] RAX: 0000000000a400a4 RBX: ffff880029a6bc18 RCX: 00000000fffffffa [ 10.476731] RDX: 00000000000000a4 RSI: ffff880029bb0000 RDI: ffff880029a6bc18 [ 10.484696] RBP: ffff880033c03dc8 R08: 0000000000000000 R09: ffff88002f800490 [ 10.492661] R10: 0000000000000000 R11: 0000000000000005 R12: 0000000000000000 [ 10.500625] R13: ffff880029a6bd98 R14: 0000000000000000 R15: ffffc90000194000 [ 10.508590] FS: 0000000000000000(0000) GS:ffff880033c00000(0000) knlGS:0000000000000000 [ 10.517623] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b [ 10.524035] CR2: 000000000000003c CR3: 00000000328ff000 CR4: 00000000000007b0 [ 10.531999] Stack: [ 10.534241] 0000000000000017 ffff880031ba7d00 000000000000005c ffff880031ba7d00 [ 10.542535] 0000000000000000 000000000000005c ffff880033c03e10 ffffffff810c2a1e [ 10.550827] ffff880031ae2900 000000008108fb4f ffff880031ae2900 ffff880031ae2984 [ 10.559121] Call Trace: [ 10.561849] [ 10.563994] [] handle_irq_event_percpu+0x3e/0x1a0 [ 10.571309] [] handle_irq_event+0x3d/0x60 [ 10.577631] [] try_one_irq.isra.6+0x8d/0xf0 [ 10.584142] [] note_interrupt+0x173/0x1f0 [ 10.590460] [] handle_irq_event_percpu+0xae/0x1a0 [ 10.597554] [] handle_irq_event+0x3d/0x60 [ 10.603872] [] handle_edge_irq+0x77/0x130 [ 10.610199] [] handle_irq+0xbf/0x150 [ 10.616040] [] ? vtime_account_idle+0xe/0x50 [ 10.622654] [] ? atomic_notifier_call_chain+0x1a/0x20 [ 10.630140] [] do_IRQ+0x4f/0xf0 [ 10.635490] [] common_interrupt+0x6d/0x6d [ 10.641805] [ 10.643950] [] ? cpuidle_enter_state+0x4f/0xc0 [ 10.650972] [] ? cpuidle_enter_state+0x48/0xc0 [ 10.657775] [] cpuidle_enter+0x17/0x20 [ 10.663807] [] cpu_startup_entry+0x2c0/0x3d0 [ 10.670423] [] rest_init+0x77/0x80 [ 10.676065] [] start_kernel+0x40f/0x41a [ 10.682190] [] ? repair_env_string+0x5c/0x5c [ 10.688799] [] ? early_idt_handlers+0x120/0x120 [ 10.695699] [] x86_64_start_reservations+0x2a/0x2c [ 10.702889] [] x86_64_start_kernel+0x143/0x152 [ 10.709689] Code: a0 fc ff 85 c0 8b 4d d4 74 c3 48 8b 7b 08 89 ca 48 c7 c6 60 66 13 a0 31 c0 e8 9d 70 28 e1 8b 4d d4 eb aa 0f 1f 84 00 00 00 00 00 <45> 8b 64 24 3c 48 89 df e8 23 47 4c e1 41 83 fc 01 19 c0 48 83 [ 10.731470] RIP [] ahci_hw_interrupt+0x100/0x130 [libahci] [ 10.739441] RSP [ 10.743333] CR2: 000000000000003c [ 10.747032] ---[ end trace b6e82636970e2690 ]--- [ 10.760190] Kernel panic - not syncing: Fatal exception in interrupt [ 10.767291] Kernel Offset: 0x0 from 0xffffffff81000000 (relocation range: 0xffffffff80000000-0xffffffff9fffffff) Cc: Alexander Gordeev Cc: Tejun Heo Cc: Signed-of-by: David Milburn Fixes: 5ca72c4f7c41 ("AHCI: Support multiple MSIs") --- drivers/ata/ahci.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 5a0bf8ed649..e45b18ee04c 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1232,18 +1232,14 @@ int ahci_host_activate(struct ata_host *host, int irq, unsigned int n_msis) return rc; for (i = 0; i < host->n_ports; i++) { - const char* desc; struct ahci_port_priv *pp = host->ports[i]->private_data; /* pp is NULL for dummy ports */ if (pp) - desc = pp->irq_desc; - else - desc = dev_driver_string(host->dev); - - rc = devm_request_threaded_irq(host->dev, - irq + i, ahci_hw_interrupt, ahci_thread_fn, IRQF_SHARED, - desc, host->ports[i]); + rc = devm_request_threaded_irq(host->dev, + irq + i, ahci_hw_interrupt, + ahci_thread_fn, IRQF_SHARED, + pp->irq_desc, host->ports[i]); if (rc) goto out_free_irqs; } -- cgit v1.2.3-70-g09d2 From e283546c0465dd3026bc94f7b1a9de7f6b8969ec Mon Sep 17 00:00:00 2001 From: Edward Cree Date: Wed, 16 Apr 2014 19:27:48 +0100 Subject: sfc:On MCDI timeout, issue an FLR (and mark MCDI to fail-fast) When an MCDI command times out (whether or not we find it completed when we poll), call efx_mcdi_abandon(), which tells all subsequent MCDI calls to fail-fast, and queues up an FLR. Because an FLR doesn't lead to receiving any reboot even from the MC (unlike most other types of reset), we have to call efx_ef10_reset_mc_allocations. In efx_start_all(), if a reset (of any kind) is pending, we bail out. Without this, attempts to reconfigure (e.g. change mtu) can cause driver/mc state inconsistency if the first MCDI call triggers an FLR. For similar reasons, on EF10, in efx_reset_down(method=RESET_TYPE_MCDI_TIMEOUT), set the number of active queues to zero before calling efx_stop_all(). And, on farch, in efx_reset_up(method=RESET_TYPE_MCDI_TIMEOUT), set active_queues and flushes pending & outstanding to zero. efx_mcdi_mode_{poll,event}() should not take us out of fail-fast mode. Instead, this is done by efx_mcdi_reset() after the FLR completes. The new FLR reset_type RESET_TYPE_MCDI_TIMEOUT doesn't really fit into the hierarchy of reset 'scopes' whereby efx_reset() decides some resets subsume others. Thus, it uses separate logic. Also, fixed up some inconsistency around RESET_TYPE_MC_BIST, which was in the wrong place in that hierarchy. Signed-off-by: Shradha Shah Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/ef10.c | 12 +++++++- drivers/net/ethernet/sfc/efx.c | 19 ++++++++++-- drivers/net/ethernet/sfc/enum.h | 23 ++++++++++----- drivers/net/ethernet/sfc/falcon.c | 4 +++ drivers/net/ethernet/sfc/farch.c | 22 ++++++++++++++ drivers/net/ethernet/sfc/mcdi.c | 55 ++++++++++++++++++++++++++++------- drivers/net/ethernet/sfc/mcdi.h | 13 +++++++++ drivers/net/ethernet/sfc/net_driver.h | 4 +++ drivers/net/ethernet/sfc/nic.h | 1 + drivers/net/ethernet/sfc/siena.c | 2 ++ 10 files changed, 133 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index 21c20ea0dad..b5ed30a3914 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -738,8 +738,11 @@ static int efx_ef10_reset(struct efx_nic *efx, enum reset_type reset_type) /* If it was a port reset, trigger reallocation of MC resources. * Note that on an MC reset nothing needs to be done now because we'll * detect the MC reset later and handle it then. + * For an FLR, we never get an MC reset event, but the MC has reset all + * resources assigned to us, so we have to trigger reallocation now. */ - if (reset_type == RESET_TYPE_ALL && !rc) + if ((reset_type == RESET_TYPE_ALL || + reset_type == RESET_TYPE_MCDI_TIMEOUT) && !rc) efx_ef10_reset_mc_allocations(efx); return rc; } @@ -2141,6 +2144,11 @@ static int efx_ef10_fini_dmaq(struct efx_nic *efx) return 0; } +static void efx_ef10_prepare_flr(struct efx_nic *efx) +{ + atomic_set(&efx->active_queues, 0); +} + static bool efx_ef10_filter_equal(const struct efx_filter_spec *left, const struct efx_filter_spec *right) { @@ -3603,6 +3611,8 @@ const struct efx_nic_type efx_hunt_a0_nic_type = { .probe_port = efx_mcdi_port_probe, .remove_port = efx_mcdi_port_remove, .fini_dmaq = efx_ef10_fini_dmaq, + .prepare_flr = efx_ef10_prepare_flr, + .finish_flr = efx_port_dummy_op_void, .describe_stats = efx_ef10_describe_stats, .update_stats = efx_ef10_update_stats, .start_stats = efx_mcdi_mac_start_stats, diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index 57b971e5e6b..63d595fd3cc 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c @@ -76,6 +76,7 @@ const char *const efx_reset_type_names[] = { [RESET_TYPE_RECOVER_OR_ALL] = "RECOVER_OR_ALL", [RESET_TYPE_WORLD] = "WORLD", [RESET_TYPE_RECOVER_OR_DISABLE] = "RECOVER_OR_DISABLE", + [RESET_TYPE_MC_BIST] = "MC_BIST", [RESET_TYPE_DISABLE] = "DISABLE", [RESET_TYPE_TX_WATCHDOG] = "TX_WATCHDOG", [RESET_TYPE_INT_ERROR] = "INT_ERROR", @@ -83,7 +84,7 @@ const char *const efx_reset_type_names[] = { [RESET_TYPE_DMA_ERROR] = "DMA_ERROR", [RESET_TYPE_TX_SKIP] = "TX_SKIP", [RESET_TYPE_MC_FAILURE] = "MC_FAILURE", - [RESET_TYPE_MC_BIST] = "MC_BIST", + [RESET_TYPE_MCDI_TIMEOUT] = "MCDI_TIMEOUT (FLR)", }; /* Reset workqueue. If any NIC has a hardware failure then a reset will be @@ -1739,7 +1740,8 @@ static void efx_start_all(struct efx_nic *efx) /* Check that it is appropriate to restart the interface. All * of these flags are safe to read under just the rtnl lock */ - if (efx->port_enabled || !netif_running(efx->net_dev)) + if (efx->port_enabled || !netif_running(efx->net_dev) || + efx->reset_pending) return; efx_start_port(efx); @@ -2334,6 +2336,9 @@ void efx_reset_down(struct efx_nic *efx, enum reset_type method) { EFX_ASSERT_RESET_SERIALISED(efx); + if (method == RESET_TYPE_MCDI_TIMEOUT) + efx->type->prepare_flr(efx); + efx_stop_all(efx); efx_disable_interrupts(efx); @@ -2354,6 +2359,10 @@ int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok) EFX_ASSERT_RESET_SERIALISED(efx); + if (method == RESET_TYPE_MCDI_TIMEOUT) + efx->type->finish_flr(efx); + + /* Ensure that SRAM is initialised even if we're disabling the device */ rc = efx->type->init(efx); if (rc) { netif_err(efx, drv, efx->net_dev, "failed to initialise NIC\n"); @@ -2417,7 +2426,10 @@ int efx_reset(struct efx_nic *efx, enum reset_type method) /* Clear flags for the scopes we covered. We assume the NIC and * driver are now quiescent so that there is no race here. */ - efx->reset_pending &= -(1 << (method + 1)); + if (method < RESET_TYPE_MAX_METHOD) + efx->reset_pending &= -(1 << (method + 1)); + else /* it doesn't fit into the well-ordered scope hierarchy */ + __clear_bit(method, &efx->reset_pending); /* Reinitialise bus-mastering, which may have been turned off before * the reset was scheduled. This is still appropriate, even in the @@ -2546,6 +2558,7 @@ void efx_schedule_reset(struct efx_nic *efx, enum reset_type type) case RESET_TYPE_DISABLE: case RESET_TYPE_RECOVER_OR_DISABLE: case RESET_TYPE_MC_BIST: + case RESET_TYPE_MCDI_TIMEOUT: method = type; netif_dbg(efx, drv, efx->net_dev, "scheduling %s reset\n", RESET_TYPE(method)); diff --git a/drivers/net/ethernet/sfc/enum.h b/drivers/net/ethernet/sfc/enum.h index 75ef7ef6450..d1dbb5fb31b 100644 --- a/drivers/net/ethernet/sfc/enum.h +++ b/drivers/net/ethernet/sfc/enum.h @@ -143,6 +143,7 @@ enum efx_loopback_mode { * @RESET_TYPE_WORLD: Reset as much as possible * @RESET_TYPE_RECOVER_OR_DISABLE: Try to recover. Apply RESET_TYPE_DISABLE if * unsuccessful. + * @RESET_TYPE_MC_BIST: MC entering BIST mode. * @RESET_TYPE_DISABLE: Reset datapath, MAC and PHY; leave NIC disabled * @RESET_TYPE_TX_WATCHDOG: reset due to TX watchdog * @RESET_TYPE_INT_ERROR: reset due to internal error @@ -150,14 +151,16 @@ enum efx_loopback_mode { * @RESET_TYPE_DMA_ERROR: DMA error * @RESET_TYPE_TX_SKIP: hardware completed empty tx descriptors * @RESET_TYPE_MC_FAILURE: MC reboot/assertion + * @RESET_TYPE_MCDI_TIMEOUT: MCDI timeout. */ enum reset_type { - RESET_TYPE_INVISIBLE = 0, - RESET_TYPE_RECOVER_OR_ALL = 1, - RESET_TYPE_ALL = 2, - RESET_TYPE_WORLD = 3, - RESET_TYPE_RECOVER_OR_DISABLE = 4, - RESET_TYPE_DISABLE = 5, + RESET_TYPE_INVISIBLE, + RESET_TYPE_RECOVER_OR_ALL, + RESET_TYPE_ALL, + RESET_TYPE_WORLD, + RESET_TYPE_RECOVER_OR_DISABLE, + RESET_TYPE_MC_BIST, + RESET_TYPE_DISABLE, RESET_TYPE_MAX_METHOD, RESET_TYPE_TX_WATCHDOG, RESET_TYPE_INT_ERROR, @@ -165,7 +168,13 @@ enum reset_type { RESET_TYPE_DMA_ERROR, RESET_TYPE_TX_SKIP, RESET_TYPE_MC_FAILURE, - RESET_TYPE_MC_BIST, + /* RESET_TYPE_MCDI_TIMEOUT is actually a method, not just a reason, but + * it doesn't fit the scope hierarchy (not well-ordered by inclusion). + * We encode this by having its enum value be greater than + * RESET_TYPE_MAX_METHOD. This also prevents issuing it with + * efx_ioctl_reset. + */ + RESET_TYPE_MCDI_TIMEOUT, RESET_TYPE_MAX, }; diff --git a/drivers/net/ethernet/sfc/falcon.c b/drivers/net/ethernet/sfc/falcon.c index 8ec20b713cc..fae25a41864 100644 --- a/drivers/net/ethernet/sfc/falcon.c +++ b/drivers/net/ethernet/sfc/falcon.c @@ -2696,6 +2696,8 @@ const struct efx_nic_type falcon_a1_nic_type = { .fini_dmaq = efx_farch_fini_dmaq, .prepare_flush = falcon_prepare_flush, .finish_flush = efx_port_dummy_op_void, + .prepare_flr = efx_port_dummy_op_void, + .finish_flr = efx_farch_finish_flr, .describe_stats = falcon_describe_nic_stats, .update_stats = falcon_update_nic_stats, .start_stats = falcon_start_nic_stats, @@ -2790,6 +2792,8 @@ const struct efx_nic_type falcon_b0_nic_type = { .fini_dmaq = efx_farch_fini_dmaq, .prepare_flush = falcon_prepare_flush, .finish_flush = efx_port_dummy_op_void, + .prepare_flr = efx_port_dummy_op_void, + .finish_flr = efx_farch_finish_flr, .describe_stats = falcon_describe_nic_stats, .update_stats = falcon_update_nic_stats, .start_stats = falcon_start_nic_stats, diff --git a/drivers/net/ethernet/sfc/farch.c b/drivers/net/ethernet/sfc/farch.c index a08761360cd..0537381cd2f 100644 --- a/drivers/net/ethernet/sfc/farch.c +++ b/drivers/net/ethernet/sfc/farch.c @@ -741,6 +741,28 @@ int efx_farch_fini_dmaq(struct efx_nic *efx) return rc; } +/* Reset queue and flush accounting after FLR + * + * One possible cause of FLR recovery is that DMA may be failing (eg. if bus + * mastering was disabled), in which case we don't receive (RXQ) flush + * completion events. This means that efx->rxq_flush_outstanding remained at 4 + * after the FLR; also, efx->active_queues was non-zero (as no flush completion + * events were received, and we didn't go through efx_check_tx_flush_complete()) + * If we don't fix this up, on the next call to efx_realloc_channels() we won't + * flush any RX queues because efx->rxq_flush_outstanding is at the limit of 4 + * for batched flush requests; and the efx->active_queues gets messed up because + * we keep incrementing for the newly initialised queues, but it never went to + * zero previously. Then we get a timeout every time we try to restart the + * queues, as it doesn't go back to zero when we should be flushing the queues. + */ +void efx_farch_finish_flr(struct efx_nic *efx) +{ + atomic_set(&efx->rxq_flush_pending, 0); + atomic_set(&efx->rxq_flush_outstanding, 0); + atomic_set(&efx->active_queues, 0); +} + + /************************************************************************** * * Event queue processing diff --git a/drivers/net/ethernet/sfc/mcdi.c b/drivers/net/ethernet/sfc/mcdi.c index 7bd4b14bf3b..5239cf9bdc5 100644 --- a/drivers/net/ethernet/sfc/mcdi.c +++ b/drivers/net/ethernet/sfc/mcdi.c @@ -52,12 +52,7 @@ static void efx_mcdi_timeout_async(unsigned long context); static int efx_mcdi_drv_attach(struct efx_nic *efx, bool driver_operating, bool *was_attached_out); static bool efx_mcdi_poll_once(struct efx_nic *efx); - -static inline struct efx_mcdi_iface *efx_mcdi(struct efx_nic *efx) -{ - EFX_BUG_ON_PARANOID(!efx->mcdi); - return &efx->mcdi->iface; -} +static void efx_mcdi_abandon(struct efx_nic *efx); int efx_mcdi_init(struct efx_nic *efx) { @@ -558,6 +553,8 @@ static int _efx_mcdi_rpc_finish(struct efx_nic *efx, unsigned cmd, size_t inlen, rc = 0; } + efx_mcdi_abandon(efx); + /* Close the race with efx_mcdi_ev_cpl() executing just too late * and completing a request we've just cancelled, by ensuring * that the seqno check therein fails. @@ -672,6 +669,9 @@ int efx_mcdi_rpc_start(struct efx_nic *efx, unsigned cmd, if (efx->mc_bist_for_other_fn) return -ENETDOWN; + if (mcdi->mode == MCDI_MODE_FAIL) + return -ENETDOWN; + efx_mcdi_acquire_sync(mcdi); efx_mcdi_send_request(efx, cmd, inbuf, inlen); return 0; @@ -812,7 +812,11 @@ void efx_mcdi_mode_poll(struct efx_nic *efx) return; mcdi = efx_mcdi(efx); - if (mcdi->mode == MCDI_MODE_POLL) + /* If already in polling mode, nothing to do. + * If in fail-fast state, don't switch to polled completion. + * FLR recovery will do that later. + */ + if (mcdi->mode == MCDI_MODE_POLL || mcdi->mode == MCDI_MODE_FAIL) return; /* We can switch from event completion to polled completion, because @@ -841,8 +845,8 @@ void efx_mcdi_flush_async(struct efx_nic *efx) mcdi = efx_mcdi(efx); - /* We must be in polling mode so no more requests can be queued */ - BUG_ON(mcdi->mode != MCDI_MODE_POLL); + /* We must be in poll or fail mode so no more requests can be queued */ + BUG_ON(mcdi->mode == MCDI_MODE_EVENTS); del_timer_sync(&mcdi->async_timer); @@ -875,8 +879,11 @@ void efx_mcdi_mode_event(struct efx_nic *efx) return; mcdi = efx_mcdi(efx); - - if (mcdi->mode == MCDI_MODE_EVENTS) + /* If already in event completion mode, nothing to do. + * If in fail-fast state, don't switch to event completion. FLR + * recovery will do that later. + */ + if (mcdi->mode == MCDI_MODE_EVENTS || mcdi->mode == MCDI_MODE_FAIL) return; /* We can't switch from polled to event completion in the middle of a @@ -966,6 +973,19 @@ static void efx_mcdi_ev_bist(struct efx_nic *efx) spin_unlock(&mcdi->iface_lock); } +/* MCDI timeouts seen, so make all MCDI calls fail-fast and issue an FLR to try + * to recover. + */ +static void efx_mcdi_abandon(struct efx_nic *efx) +{ + struct efx_mcdi_iface *mcdi = efx_mcdi(efx); + + if (xchg(&mcdi->mode, MCDI_MODE_FAIL) == MCDI_MODE_FAIL) + return; /* it had already been done */ + netif_dbg(efx, hw, efx->net_dev, "MCDI is timing out; trying to recover\n"); + efx_schedule_reset(efx, RESET_TYPE_MCDI_TIMEOUT); +} + /* Called from falcon_process_eventq for MCDI events */ void efx_mcdi_process_event(struct efx_channel *channel, efx_qword_t *event) @@ -1512,6 +1532,19 @@ int efx_mcdi_reset(struct efx_nic *efx, enum reset_type method) { int rc; + /* If MCDI is down, we can't handle_assertion */ + if (method == RESET_TYPE_MCDI_TIMEOUT) { + rc = pci_reset_function(efx->pci_dev); + if (rc) + return rc; + /* Re-enable polled MCDI completion */ + if (efx->mcdi) { + struct efx_mcdi_iface *mcdi = efx_mcdi(efx); + mcdi->mode = MCDI_MODE_POLL; + } + return 0; + } + /* Recover from a failed assertion pre-reset */ rc = efx_mcdi_handle_assertion(efx); if (rc) diff --git a/drivers/net/ethernet/sfc/mcdi.h b/drivers/net/ethernet/sfc/mcdi.h index 52931aebf3c..56465f7465a 100644 --- a/drivers/net/ethernet/sfc/mcdi.h +++ b/drivers/net/ethernet/sfc/mcdi.h @@ -28,9 +28,16 @@ enum efx_mcdi_state { MCDI_STATE_COMPLETED, }; +/** + * enum efx_mcdi_mode - MCDI transaction mode + * @MCDI_MODE_POLL: poll for MCDI completion, until timeout + * @MCDI_MODE_EVENTS: wait for an mcdi_event. On timeout, poll once + * @MCDI_MODE_FAIL: we think MCDI is dead, so fail-fast all calls + */ enum efx_mcdi_mode { MCDI_MODE_POLL, MCDI_MODE_EVENTS, + MCDI_MODE_FAIL, }; /** @@ -104,6 +111,12 @@ struct efx_mcdi_data { u32 fn_flags; }; +static inline struct efx_mcdi_iface *efx_mcdi(struct efx_nic *efx) +{ + EFX_BUG_ON_PARANOID(!efx->mcdi); + return &efx->mcdi->iface; +} + #ifdef CONFIG_SFC_MCDI_MON static inline struct efx_mcdi_mon *efx_mcdi_mon(struct efx_nic *efx) { diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h index 8a400a0595e..5bdae8ed7c5 100644 --- a/drivers/net/ethernet/sfc/net_driver.h +++ b/drivers/net/ethernet/sfc/net_driver.h @@ -972,6 +972,8 @@ struct efx_mtd_partition { * (for Falcon architecture) * @finish_flush: Clean up after flushing the DMA queues (for Falcon * architecture) + * @prepare_flr: Prepare for an FLR + * @finish_flr: Clean up after an FLR * @describe_stats: Describe statistics for ethtool * @update_stats: Update statistics not provided by event handling. * Either argument may be %NULL. @@ -1100,6 +1102,8 @@ struct efx_nic_type { int (*fini_dmaq)(struct efx_nic *efx); void (*prepare_flush)(struct efx_nic *efx); void (*finish_flush)(struct efx_nic *efx); + void (*prepare_flr)(struct efx_nic *efx); + void (*finish_flr)(struct efx_nic *efx); size_t (*describe_stats)(struct efx_nic *efx, u8 *names); size_t (*update_stats)(struct efx_nic *efx, u64 *full_stats, struct rtnl_link_stats64 *core_stats); diff --git a/drivers/net/ethernet/sfc/nic.h b/drivers/net/ethernet/sfc/nic.h index a001fae1a8d..d3ad8ed8d90 100644 --- a/drivers/net/ethernet/sfc/nic.h +++ b/drivers/net/ethernet/sfc/nic.h @@ -757,6 +757,7 @@ static inline int efx_nic_irq_test_irq_cpu(struct efx_nic *efx) int efx_nic_flush_queues(struct efx_nic *efx); void siena_prepare_flush(struct efx_nic *efx); int efx_farch_fini_dmaq(struct efx_nic *efx); +void efx_farch_finish_flr(struct efx_nic *efx); void siena_finish_flush(struct efx_nic *efx); void falcon_start_nic_stats(struct efx_nic *efx); void falcon_stop_nic_stats(struct efx_nic *efx); diff --git a/drivers/net/ethernet/sfc/siena.c b/drivers/net/ethernet/sfc/siena.c index 23f3a6f7737..50ffefed492 100644 --- a/drivers/net/ethernet/sfc/siena.c +++ b/drivers/net/ethernet/sfc/siena.c @@ -921,6 +921,8 @@ const struct efx_nic_type siena_a0_nic_type = { .fini_dmaq = efx_farch_fini_dmaq, .prepare_flush = siena_prepare_flush, .finish_flush = siena_finish_flush, + .prepare_flr = efx_port_dummy_op_void, + .finish_flr = efx_farch_finish_flr, .describe_stats = siena_describe_nic_stats, .update_stats = siena_update_nic_stats, .start_stats = efx_mcdi_mac_start_stats, -- cgit v1.2.3-70-g09d2 From 5ed0a8e667090003fdf7b750296fcfb248349502 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 16 Apr 2014 11:35:54 -0700 Subject: staging: delete rtl8187se wireless driver There is a "real" driver for this hardware now in drivers/net/ so remove the staging version as it's not needed anymore. Reported-by: Xose Vazquez Perez Cc: Larry Finger Cc: John W. Linville" Signed-off-by: Greg Kroah-Hartman --- drivers/staging/Kconfig | 2 - drivers/staging/Makefile | 1 - drivers/staging/rtl8187se/Kconfig | 10 - drivers/staging/rtl8187se/Makefile | 38 - drivers/staging/rtl8187se/Module.symvers | 0 drivers/staging/rtl8187se/TODO | 13 - drivers/staging/rtl8187se/ieee80211/dot11d.c | 189 - drivers/staging/rtl8187se/ieee80211/dot11d.h | 71 - drivers/staging/rtl8187se/ieee80211/ieee80211.h | 1496 -------- .../staging/rtl8187se/ieee80211/ieee80211_crypt.c | 240 -- .../staging/rtl8187se/ieee80211/ieee80211_crypt.h | 86 - .../rtl8187se/ieee80211/ieee80211_crypt_ccmp.c | 455 --- .../rtl8187se/ieee80211/ieee80211_crypt_tkip.c | 740 ---- .../rtl8187se/ieee80211/ieee80211_crypt_wep.c | 277 -- .../staging/rtl8187se/ieee80211/ieee80211_module.c | 203 -- drivers/staging/rtl8187se/ieee80211/ieee80211_rx.c | 1486 -------- .../rtl8187se/ieee80211/ieee80211_softmac.c | 2711 -------------- .../rtl8187se/ieee80211/ieee80211_softmac_wx.c | 567 --- drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c | 591 --- drivers/staging/rtl8187se/ieee80211/ieee80211_wx.c | 713 ---- drivers/staging/rtl8187se/r8180.h | 640 ---- drivers/staging/rtl8187se/r8180_93cx6.h | 54 - drivers/staging/rtl8187se/r8180_core.c | 3775 -------------------- drivers/staging/rtl8187se/r8180_dm.c | 1139 ------ drivers/staging/rtl8187se/r8180_dm.h | 23 - drivers/staging/rtl8187se/r8180_hw.h | 588 --- drivers/staging/rtl8187se/r8180_rtl8225.h | 34 - drivers/staging/rtl8187se/r8180_rtl8225z2.c | 811 ----- drivers/staging/rtl8187se/r8180_wx.c | 1409 -------- drivers/staging/rtl8187se/r8180_wx.h | 21 - drivers/staging/rtl8187se/r8185b_init.c | 1464 -------- 31 files changed, 19847 deletions(-) delete mode 100644 drivers/staging/rtl8187se/Kconfig delete mode 100644 drivers/staging/rtl8187se/Makefile delete mode 100644 drivers/staging/rtl8187se/Module.symvers delete mode 100644 drivers/staging/rtl8187se/TODO delete mode 100644 drivers/staging/rtl8187se/ieee80211/dot11d.c delete mode 100644 drivers/staging/rtl8187se/ieee80211/dot11d.h delete mode 100644 drivers/staging/rtl8187se/ieee80211/ieee80211.h delete mode 100644 drivers/staging/rtl8187se/ieee80211/ieee80211_crypt.c delete mode 100644 drivers/staging/rtl8187se/ieee80211/ieee80211_crypt.h delete mode 100644 drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_ccmp.c delete mode 100644 drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_tkip.c delete mode 100644 drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_wep.c delete mode 100644 drivers/staging/rtl8187se/ieee80211/ieee80211_module.c delete mode 100644 drivers/staging/rtl8187se/ieee80211/ieee80211_rx.c delete mode 100644 drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c delete mode 100644 drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c delete mode 100644 drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c delete mode 100644 drivers/staging/rtl8187se/ieee80211/ieee80211_wx.c delete mode 100644 drivers/staging/rtl8187se/r8180.h delete mode 100644 drivers/staging/rtl8187se/r8180_93cx6.h delete mode 100644 drivers/staging/rtl8187se/r8180_core.c delete mode 100644 drivers/staging/rtl8187se/r8180_dm.c delete mode 100644 drivers/staging/rtl8187se/r8180_dm.h delete mode 100644 drivers/staging/rtl8187se/r8180_hw.h delete mode 100644 drivers/staging/rtl8187se/r8180_rtl8225.h delete mode 100644 drivers/staging/rtl8187se/r8180_rtl8225z2.c delete mode 100644 drivers/staging/rtl8187se/r8180_wx.c delete mode 100644 drivers/staging/rtl8187se/r8180_wx.h delete mode 100644 drivers/staging/rtl8187se/r8185b_init.c (limited to 'drivers') diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index ea5efb426f7..22365f140be 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -40,8 +40,6 @@ source "drivers/staging/olpc_dcon/Kconfig" source "drivers/staging/panel/Kconfig" -source "drivers/staging/rtl8187se/Kconfig" - source "drivers/staging/rtl8192u/Kconfig" source "drivers/staging/rtl8192e/Kconfig" diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index 86e020c2ad0..fbe84ed2d04 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -12,7 +12,6 @@ obj-$(CONFIG_PRISM2_USB) += wlan-ng/ obj-$(CONFIG_COMEDI) += comedi/ obj-$(CONFIG_FB_OLPC_DCON) += olpc_dcon/ obj-$(CONFIG_PANEL) += panel/ -obj-$(CONFIG_R8187SE) += rtl8187se/ obj-$(CONFIG_RTL8192U) += rtl8192u/ obj-$(CONFIG_RTL8192E) += rtl8192e/ obj-$(CONFIG_R8712U) += rtl8712/ diff --git a/drivers/staging/rtl8187se/Kconfig b/drivers/staging/rtl8187se/Kconfig deleted file mode 100644 index ff8d41ebca3..00000000000 --- a/drivers/staging/rtl8187se/Kconfig +++ /dev/null @@ -1,10 +0,0 @@ -config R8187SE - tristate "RealTek RTL8187SE Wireless LAN NIC driver" - depends on PCI && WLAN - depends on m - select WIRELESS_EXT - select WEXT_PRIV - select EEPROM_93CX6 - select CRYPTO - ---help--- - If built as a module, it will be called r8187se.ko. diff --git a/drivers/staging/rtl8187se/Makefile b/drivers/staging/rtl8187se/Makefile deleted file mode 100644 index 91d1aa2830c..00000000000 --- a/drivers/staging/rtl8187se/Makefile +++ /dev/null @@ -1,38 +0,0 @@ - -#ccflags-y += -DCONFIG_IEEE80211_NOWEP=y -#ccflags-y += -std=gnu89 -#ccflags-y += -O2 -#CC = gcc - -ccflags-y := -DSW_ANTE -ccflags-y += -DTX_TRACK -ccflags-y += -DHIGH_POWER -ccflags-y += -DSW_DIG -ccflags-y += -DRATE_ADAPT - -#enable it for legacy power save, disable it for leisure power save -ccflags-y += -DENABLE_LPS - - -#ccflags-y := -mhard-float -DCONFIG_FORCE_HARD_FLOAT=y - -r8187se-y := \ - r8180_core.o \ - r8180_wx.o \ - r8180_rtl8225z2.o \ - r8185b_init.o \ - r8180_dm.o \ - ieee80211/dot11d.o \ - ieee80211/ieee80211_softmac.o \ - ieee80211/ieee80211_rx.o \ - ieee80211/ieee80211_tx.o \ - ieee80211/ieee80211_wx.o \ - ieee80211/ieee80211_module.o \ - ieee80211/ieee80211_softmac_wx.o \ - ieee80211/ieee80211_crypt.o \ - ieee80211/ieee80211_crypt_tkip.o \ - ieee80211/ieee80211_crypt_ccmp.o \ - ieee80211/ieee80211_crypt_wep.o - -obj-$(CONFIG_R8187SE) += r8187se.o - diff --git a/drivers/staging/rtl8187se/Module.symvers b/drivers/staging/rtl8187se/Module.symvers deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/drivers/staging/rtl8187se/TODO b/drivers/staging/rtl8187se/TODO deleted file mode 100644 index 704949a9da0..00000000000 --- a/drivers/staging/rtl8187se/TODO +++ /dev/null @@ -1,13 +0,0 @@ -TODO: -- prepare private ieee80211 stack for merge with rtl8192su's version: - - add hwsec_active flag to struct ieee80211_device - - add bHwSec flag to cb_desc structure -- switch to use shared "librtl" instead of private ieee80211 stack -- switch to use LIB80211 -- switch to use MAC80211 -- use kernel coding style -- checkpatch.pl fixes -- sparse fixes -- integrate with drivers/net/wireless/rtl818x - -Please send any patches to Greg Kroah-Hartman . diff --git a/drivers/staging/rtl8187se/ieee80211/dot11d.c b/drivers/staging/rtl8187se/ieee80211/dot11d.c deleted file mode 100644 index 4483c2c0307..00000000000 --- a/drivers/staging/rtl8187se/ieee80211/dot11d.c +++ /dev/null @@ -1,189 +0,0 @@ -#include "dot11d.h" - -void Dot11d_Init(struct ieee80211_device *ieee) -{ - PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(ieee); - - pDot11dInfo->bEnabled = 0; - - pDot11dInfo->State = DOT11D_STATE_NONE; - pDot11dInfo->CountryIeLen = 0; - memset(pDot11dInfo->channel_map, 0, MAX_CHANNEL_NUMBER+1); - memset(pDot11dInfo->MaxTxPwrDbmList, 0xFF, MAX_CHANNEL_NUMBER+1); - RESET_CIE_WATCHDOG(ieee); - - netdev_info(ieee->dev, "Dot11d_Init()\n"); -} - -/* Reset to the state as we are just entering a regulatory domain. */ -void Dot11d_Reset(struct ieee80211_device *ieee) -{ - u32 i; - PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(ieee); - - /* Clear old channel map */ - memset(pDot11dInfo->channel_map, 0, MAX_CHANNEL_NUMBER+1); - memset(pDot11dInfo->MaxTxPwrDbmList, 0xFF, MAX_CHANNEL_NUMBER+1); - /* Set new channel map */ - for (i = 1; i <= 11; i++) - (pDot11dInfo->channel_map)[i] = 1; - - for (i = 12; i <= 14; i++) - (pDot11dInfo->channel_map)[i] = 2; - - pDot11dInfo->State = DOT11D_STATE_NONE; - pDot11dInfo->CountryIeLen = 0; - RESET_CIE_WATCHDOG(ieee); -} - -/* - * Description: - * Update country IE from Beacon or Probe Response and configure PHY for - * operation in the regulatory domain. - * - * TODO: - * Configure Tx power. - * - * Assumption: - * 1. IS_DOT11D_ENABLE() is TRUE. - * 2. Input IE is an valid one. - */ -void Dot11d_UpdateCountryIe(struct ieee80211_device *dev, u8 *pTaddr, - u16 CoutryIeLen, u8 *pCoutryIe) -{ - PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(dev); - u8 i, j, NumTriples, MaxChnlNum; - u8 index, MaxTxPowerInDbm; - PCHNL_TXPOWER_TRIPLE pTriple; - - if ((CoutryIeLen - 3)%3 != 0) { - netdev_info(dev->dev, "Dot11d_UpdateCountryIe(): Invalid country IE, skip it........1\n"); - Dot11d_Reset(dev); - return; - } - - memset(pDot11dInfo->channel_map, 0, MAX_CHANNEL_NUMBER+1); - memset(pDot11dInfo->MaxTxPwrDbmList, 0xFF, MAX_CHANNEL_NUMBER+1); - MaxChnlNum = 0; - NumTriples = (CoutryIeLen - 3) / 3; /* skip 3-byte country string. */ - pTriple = (PCHNL_TXPOWER_TRIPLE)(pCoutryIe + 3); - for (i = 0; i < NumTriples; i++) { - if (MaxChnlNum >= pTriple->FirstChnl) { - /* - * It is not in a monotonically increasing order, - * so stop processing. - */ - netdev_info(dev->dev, - "Dot11d_UpdateCountryIe(): Invalid country IE, skip it........1\n"); - Dot11d_Reset(dev); - return; - } - if (MAX_CHANNEL_NUMBER < - (pTriple->FirstChnl + pTriple->NumChnls)) { - /* - * It is not a valid set of channel id, - * so stop processing - */ - netdev_info(dev->dev, - "Dot11d_UpdateCountryIe(): Invalid country IE, skip it........2\n"); - Dot11d_Reset(dev); - return; - } - - for (j = 0; j < pTriple->NumChnls; j++) { - index = pTriple->FirstChnl + j; - pDot11dInfo->channel_map[index] = 1; - MaxTxPowerInDbm = pTriple->MaxTxPowerInDbm; - pDot11dInfo->MaxTxPwrDbmList[index] = MaxTxPowerInDbm; - MaxChnlNum = pTriple->FirstChnl + j; - } - - pTriple = (PCHNL_TXPOWER_TRIPLE)((u8 *)pTriple + 3); - } -#if 1 - netdev_info(dev->dev, "Channel List:"); - for (i = 1; i <= MAX_CHANNEL_NUMBER; i++) - if (pDot11dInfo->channel_map[i] > 0) - netdev_info(dev->dev, " %d", i); - netdev_info(dev->dev, "\n"); -#endif - - UPDATE_CIE_SRC(dev, pTaddr); - - pDot11dInfo->CountryIeLen = CoutryIeLen; - memcpy(pDot11dInfo->CountryIeBuf, pCoutryIe, CoutryIeLen); - pDot11dInfo->State = DOT11D_STATE_LEARNED; -} - -u8 DOT11D_GetMaxTxPwrInDbm(struct ieee80211_device *dev, u8 Channel) -{ - PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(dev); - u8 MaxTxPwrInDbm = 255; - - if (MAX_CHANNEL_NUMBER < Channel) { - netdev_info(dev->dev, "DOT11D_GetMaxTxPwrInDbm(): Invalid Channel\n"); - return MaxTxPwrInDbm; - } - if (pDot11dInfo->channel_map[Channel]) - MaxTxPwrInDbm = pDot11dInfo->MaxTxPwrDbmList[Channel]; - - return MaxTxPwrInDbm; -} - - -void DOT11D_ScanComplete(struct ieee80211_device *dev) -{ - PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(dev); - - switch (pDot11dInfo->State) { - case DOT11D_STATE_LEARNED: - pDot11dInfo->State = DOT11D_STATE_DONE; - break; - - case DOT11D_STATE_DONE: - if (GET_CIE_WATCHDOG(dev) == 0) { - /* Reset country IE if previous one is gone. */ - Dot11d_Reset(dev); - } - break; - case DOT11D_STATE_NONE: - break; - } -} - -int IsLegalChannel(struct ieee80211_device *dev, u8 channel) -{ - PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(dev); - - if (MAX_CHANNEL_NUMBER < channel) { - netdev_info(dev->dev, "IsLegalChannel(): Invalid Channel\n"); - return 0; - } - if (pDot11dInfo->channel_map[channel] > 0) - return 1; - return 0; -} - -int ToLegalChannel(struct ieee80211_device *dev, u8 channel) -{ - PRT_DOT11D_INFO pDot11dInfo = GET_DOT11D_INFO(dev); - u8 default_chn = 0; - u32 i = 0; - - for (i = 1; i <= MAX_CHANNEL_NUMBER; i++) { - if (pDot11dInfo->channel_map[i] > 0) { - default_chn = i; - break; - } - } - - if (MAX_CHANNEL_NUMBER < channel) { - netdev_info(dev->dev, "IsLegalChannel(): Invalid Channel\n"); - return default_chn; - } - - if (pDot11dInfo->channel_map[channel] > 0) - return channel; - - return default_chn; -} diff --git a/drivers/staging/rtl8187se/ieee80211/dot11d.h b/drivers/staging/rtl8187se/ieee80211/dot11d.h deleted file mode 100644 index f996691307b..00000000000 --- a/drivers/staging/rtl8187se/ieee80211/dot11d.h +++ /dev/null @@ -1,71 +0,0 @@ -#ifndef __INC_DOT11D_H -#define __INC_DOT11D_H - -#include "ieee80211.h" - -/* #define ENABLE_DOT11D */ - -/* #define DOT11D_MAX_CHNL_NUM 83 */ - -typedef struct _CHNL_TXPOWER_TRIPLE { - u8 FirstChnl; - u8 NumChnls; - u8 MaxTxPowerInDbm; -} CHNL_TXPOWER_TRIPLE, *PCHNL_TXPOWER_TRIPLE; - -typedef enum _DOT11D_STATE { - DOT11D_STATE_NONE = 0, - DOT11D_STATE_LEARNED, - DOT11D_STATE_DONE, -} DOT11D_STATE; - -typedef struct _RT_DOT11D_INFO { - /* DECLARE_RT_OBJECT(RT_DOT12D_INFO); */ - - bool bEnabled; /* dot11MultiDomainCapabilityEnabled */ - - u16 CountryIeLen; /* > 0 if CountryIeBuf[] contains valid country information element. */ - u8 CountryIeBuf[MAX_IE_LEN]; - u8 CountryIeSrcAddr[6]; /* Source AP of the country IE. */ - u8 CountryIeWatchdog; - - u8 channel_map[MAX_CHANNEL_NUMBER+1]; /* !!!Value 0: Invalid, 1: Valid (active scan), 2: Valid (passive scan) */ - /* u8 ChnlListLen; // #Bytes valid in ChnlList[]. */ - /* u8 ChnlList[DOT11D_MAX_CHNL_NUM]; */ - u8 MaxTxPwrDbmList[MAX_CHANNEL_NUMBER+1]; - - DOT11D_STATE State; -} RT_DOT11D_INFO, *PRT_DOT11D_INFO; - -#define eqMacAddr(a, b) (((a)[0] == (b)[0] && (a)[1] == (b)[1] && (a)[2] == (b)[2] && (a)[3] == (b)[3] && (a)[4] == (b)[4] && (a)[5] == (b)[5]) ? 1:0) -#define cpMacAddr(des, src) ((des)[0] = (src)[0], (des)[1] = (src)[1], (des)[2] = (src)[2], (des)[3] = (src)[3], (des)[4] = (src)[4], (des)[5] = (src)[5]) -#define GET_DOT11D_INFO(__pIeeeDev) ((PRT_DOT11D_INFO)((__pIeeeDev)->pDot11dInfo)) - -#define IS_DOT11D_ENABLE(__pIeeeDev) GET_DOT11D_INFO(__pIeeeDev)->bEnabled -#define IS_COUNTRY_IE_VALID(__pIeeeDev) (GET_DOT11D_INFO(__pIeeeDev)->CountryIeLen > 0) - -#define IS_EQUAL_CIE_SRC(__pIeeeDev, __pTa) eqMacAddr(GET_DOT11D_INFO(__pIeeeDev)->CountryIeSrcAddr, __pTa) -#define UPDATE_CIE_SRC(__pIeeeDev, __pTa) cpMacAddr(GET_DOT11D_INFO(__pIeeeDev)->CountryIeSrcAddr, __pTa) - -#define IS_COUNTRY_IE_CHANGED(__pIeeeDev, __Ie) \ - (((__Ie).Length == 0 || (__Ie).Length != GET_DOT11D_INFO(__pIeeeDev)->CountryIeLen) ? \ - FALSE : \ - (!memcmp(GET_DOT11D_INFO(__pIeeeDev)->CountryIeBuf, (__Ie).Octet, (__Ie).Length))) - -#define CIE_WATCHDOG_TH 1 -#define GET_CIE_WATCHDOG(__pIeeeDev) GET_DOT11D_INFO(__pIeeeDev)->CountryIeWatchdog -#define RESET_CIE_WATCHDOG(__pIeeeDev) GET_CIE_WATCHDOG(__pIeeeDev) = 0 -#define UPDATE_CIE_WATCHDOG(__pIeeeDev) ++GET_CIE_WATCHDOG(__pIeeeDev) - -#define IS_DOT11D_STATE_DONE(__pIeeeDev) (GET_DOT11D_INFO(__pIeeeDev)->State == DOT11D_STATE_DONE) - -void Dot11d_Init(struct ieee80211_device *dev); -void Dot11d_Reset(struct ieee80211_device *dev); -void Dot11d_UpdateCountryIe(struct ieee80211_device *dev, u8 *pTaddr, - u16 CoutryIeLen, u8 *pCoutryIe); -u8 DOT11D_GetMaxTxPwrInDbm(struct ieee80211_device *dev, u8 Channel); -void DOT11D_ScanComplete(struct ieee80211_device *dev); -int IsLegalChannel(struct ieee80211_device *dev, u8 channel); -int ToLegalChannel(struct ieee80211_device *dev, u8 channel); - -#endif /* #ifndef __INC_DOT11D_H */ diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211.h b/drivers/staging/rtl8187se/ieee80211/ieee80211.h deleted file mode 100644 index d1763b7b8f2..00000000000 --- a/drivers/staging/rtl8187se/ieee80211/ieee80211.h +++ /dev/null @@ -1,1496 +0,0 @@ -/* - * Merged with mainline ieee80211.h in Aug 2004. Original ieee802_11 - * remains copyright by the original authors - * - * Portions of the merged code are based on Host AP (software wireless - * LAN access point) driver for Intersil Prism2/2.5/3. - * - * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen - * - * Copyright (c) 2002-2003, Jouni Malinen - * - * Adaption to a generic IEEE 802.11 stack by James Ketrenos - * - * Copyright (c) 2004, Intel Corporation - * - * Modified for Realtek's wi-fi cards by Andrea Merello - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. See README and COPYING for - * more details. - */ -#ifndef IEEE80211_H -#define IEEE80211_H -#include /* ETH_ALEN */ -#include /* ARRAY_SIZE */ -#include -#include -#include -#include -#include -#include -#include - -#define KEY_TYPE_NA 0x0 -#define KEY_TYPE_WEP40 0x1 -#define KEY_TYPE_TKIP 0x2 -#define KEY_TYPE_CCMP 0x4 -#define KEY_TYPE_WEP104 0x5 - -#define aSifsTime 10 - -#define MGMT_QUEUE_NUM 5 - - -#define IEEE_CMD_SET_WPA_PARAM 1 -#define IEEE_CMD_SET_WPA_IE 2 -#define IEEE_CMD_SET_ENCRYPTION 3 -#define IEEE_CMD_MLME 4 - -#define IEEE_PARAM_WPA_ENABLED 1 -#define IEEE_PARAM_TKIP_COUNTERMEASURES 2 -#define IEEE_PARAM_DROP_UNENCRYPTED 3 -#define IEEE_PARAM_PRIVACY_INVOKED 4 -#define IEEE_PARAM_AUTH_ALGS 5 -#define IEEE_PARAM_IEEE_802_1X 6 -//It should consistent with the driver_XXX.c -// David, 2006.9.26 -#define IEEE_PARAM_WPAX_SELECT 7 -//Added for notify the encryption type selection -// David, 2006.9.26 -#define IEEE_PROTO_WPA 1 -#define IEEE_PROTO_RSN 2 -//Added for notify the encryption type selection -// David, 2006.9.26 -#define IEEE_WPAX_USEGROUP 0 -#define IEEE_WPAX_WEP40 1 -#define IEEE_WPAX_TKIP 2 -#define IEEE_WPAX_WRAP 3 -#define IEEE_WPAX_CCMP 4 -#define IEEE_WPAX_WEP104 5 - -#define IEEE_KEY_MGMT_IEEE8021X 1 -#define IEEE_KEY_MGMT_PSK 2 - - - -#define IEEE_MLME_STA_DEAUTH 1 -#define IEEE_MLME_STA_DISASSOC 2 - - -#define IEEE_CRYPT_ERR_UNKNOWN_ALG 2 -#define IEEE_CRYPT_ERR_UNKNOWN_ADDR 3 -#define IEEE_CRYPT_ERR_CRYPT_INIT_FAILED 4 -#define IEEE_CRYPT_ERR_KEY_SET_FAILED 5 -#define IEEE_CRYPT_ERR_TX_KEY_SET_FAILED 6 -#define IEEE_CRYPT_ERR_CARD_CONF_FAILED 7 - - -#define IEEE_CRYPT_ALG_NAME_LEN 16 - -extern int ieee80211_crypto_tkip_init(void); -extern void ieee80211_crypto_tkip_exit(void); - -//by amy for ps -typedef struct ieee_param { - u32 cmd; - u8 sta_addr[ETH_ALEN]; - union { - struct { - u8 name; - u32 value; - } wpa_param; - struct { - u32 len; - u8 reserved[32]; - u8 data[0]; - } wpa_ie; - struct{ - int command; - int reason_code; - } mlme; - struct { - u8 alg[IEEE_CRYPT_ALG_NAME_LEN]; - u8 set_tx; - u32 err; - u8 idx; - u8 seq[8]; /* sequence counter (set: RX, get: TX) */ - u16 key_len; - u8 key[0]; - } crypt; - - } u; -}ieee_param; - - -#define MSECS(t) msecs_to_jiffies(t) -#define msleep_interruptible_rtl msleep_interruptible - -#define IEEE80211_DATA_LEN 2304 -/* Maximum size for the MA-UNITDATA primitive, 802.11 standard section - 6.2.1.1.2. - - The figure in section 7.1.2 suggests a body size of up to 2312 - bytes is allowed, which is a bit confusing, I suspect this - represents the 2304 bytes of real data, plus a possible 8 bytes of - WEP IV and ICV. (this interpretation suggested by Ramiro Barreiro) */ - -#define IEEE80211_3ADDR_LEN 24 -#define IEEE80211_4ADDR_LEN 30 -#define IEEE80211_FCS_LEN 4 -#define IEEE80211_HLEN IEEE80211_4ADDR_LEN -#define IEEE80211_FRAME_LEN (IEEE80211_DATA_LEN + IEEE80211_HLEN) -#define IEEE80211_MGMT_HDR_LEN 24 -#define IEEE80211_DATA_HDR3_LEN 24 -#define IEEE80211_DATA_HDR4_LEN 30 - -#define MIN_FRAG_THRESHOLD 256U -#define MAX_FRAG_THRESHOLD 2346U - -/* Frame control field constants */ -#define IEEE80211_FCTL_DSTODS 0x0300 //added by david -#define IEEE80211_FCTL_WEP 0x4000 - -/* debug macros */ - -#ifdef CONFIG_IEEE80211_DEBUG -extern u32 ieee80211_debug_level; -#define IEEE80211_DEBUG(level, fmt, args...) \ -do { if (ieee80211_debug_level & (level)) \ - printk(KERN_DEBUG "ieee80211: %c %s " fmt, \ - in_interrupt() ? 'I' : 'U', __func__ , ## args); } while (0) -#else -#define IEEE80211_DEBUG(level, fmt, args...) do {} while (0) -#endif /* CONFIG_IEEE80211_DEBUG */ - -/* - * To use the debug system; - * - * If you are defining a new debug classification, simply add it to the #define - * list here in the form of: - * - * #define IEEE80211_DL_xxxx VALUE - * - * shifting value to the left one bit from the previous entry. xxxx should be - * the name of the classification (for example, WEP) - * - * You then need to either add a IEEE80211_xxxx_DEBUG() macro definition for your - * classification, or use IEEE80211_DEBUG(IEEE80211_DL_xxxx, ...) whenever you want - * to send output to that classification. - * - * To add your debug level to the list of levels seen when you perform - * - * % cat /proc/net/ipw/debug_level - * - * you simply need to add your entry to the ipw_debug_levels array. - * - * If you do not see debug_level in /proc/net/ipw then you do not have - * CONFIG_IEEE80211_DEBUG defined in your kernel configuration - * - */ - -#define IEEE80211_DL_INFO (1<<0) -#define IEEE80211_DL_WX (1<<1) -#define IEEE80211_DL_SCAN (1<<2) -#define IEEE80211_DL_STATE (1<<3) -#define IEEE80211_DL_MGMT (1<<4) -#define IEEE80211_DL_FRAG (1<<5) -#define IEEE80211_DL_EAP (1<<6) -#define IEEE80211_DL_DROP (1<<7) - -#define IEEE80211_DL_TX (1<<8) -#define IEEE80211_DL_RX (1<<9) - -#define IEEE80211_ERROR(f, a...) printk(KERN_ERR "ieee80211: " f, ## a) -#define IEEE80211_WARNING(f, a...) printk(KERN_WARNING "ieee80211: " f, ## a) -#define IEEE80211_DEBUG_INFO(f, a...) IEEE80211_DEBUG(IEEE80211_DL_INFO, f, ## a) - -#define IEEE80211_DEBUG_WX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_WX, f, ## a) -#define IEEE80211_DEBUG_SCAN(f, a...) IEEE80211_DEBUG(IEEE80211_DL_SCAN, f, ## a) -//#define IEEE_DEBUG_SCAN IEEE80211_WARNING -#define IEEE80211_DEBUG_STATE(f, a...) IEEE80211_DEBUG(IEEE80211_DL_STATE, f, ## a) -#define IEEE80211_DEBUG_MGMT(f, a...) IEEE80211_DEBUG(IEEE80211_DL_MGMT, f, ## a) -#define IEEE80211_DEBUG_FRAG(f, a...) IEEE80211_DEBUG(IEEE80211_DL_FRAG, f, ## a) -#define IEEE80211_DEBUG_EAP(f, a...) IEEE80211_DEBUG(IEEE80211_DL_EAP, f, ## a) -#define IEEE80211_DEBUG_DROP(f, a...) IEEE80211_DEBUG(IEEE80211_DL_DROP, f, ## a) -#define IEEE80211_DEBUG_TX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_TX, f, ## a) -#define IEEE80211_DEBUG_RX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_RX, f, ## a) -#include -#include /* ARPHRD_ETHER */ - -#ifndef WIRELESS_SPY -#define WIRELESS_SPY // enable iwspy support -#endif -#include // new driver API - -#ifndef ETH_P_PAE -#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */ -#endif /* ETH_P_PAE */ - -#define ETH_P_PREAUTH 0x88C7 /* IEEE 802.11i pre-authentication */ - -#ifndef ETH_P_80211_RAW -#define ETH_P_80211_RAW (ETH_P_ECONET + 1) -#endif - -/* IEEE 802.11 defines */ - -#define P80211_OUI_LEN 3 - -struct ieee80211_snap_hdr { - - u8 dsap; /* always 0xAA */ - u8 ssap; /* always 0xAA */ - u8 ctrl; /* always 0x03 */ - u8 oui[P80211_OUI_LEN]; /* organizational universal id */ - -} __attribute__ ((packed)); - -#define SNAP_SIZE sizeof(struct ieee80211_snap_hdr) - -#define WLAN_FC_GET_TYPE(fc) ((fc) & IEEE80211_FCTL_FTYPE) -#define WLAN_FC_GET_STYPE(fc) ((fc) & IEEE80211_FCTL_STYPE) - -#define WLAN_GET_SEQ_FRAG(seq) ((seq) & IEEE80211_SCTL_FRAG) -#define WLAN_GET_SEQ_SEQ(seq) ((seq) & IEEE80211_SCTL_SEQ) - -#define WLAN_CAPABILITY_BSS (1<<0) -#define WLAN_CAPABILITY_SHORT_SLOT (1<<10) - -#define IEEE80211_STATMASK_SIGNAL (1<<0) -#define IEEE80211_STATMASK_RSSI (1<<1) -#define IEEE80211_STATMASK_NOISE (1<<2) -#define IEEE80211_STATMASK_RATE (1<<3) -#define IEEE80211_STATMASK_WEMASK 0x7 - - -#define IEEE80211_CCK_MODULATION (1<<0) -#define IEEE80211_OFDM_MODULATION (1<<1) - -#define IEEE80211_24GHZ_BAND (1<<0) -#define IEEE80211_52GHZ_BAND (1<<1) - -#define IEEE80211_CCK_RATE_LEN 4 -#define IEEE80211_CCK_RATE_1MB 0x02 -#define IEEE80211_CCK_RATE_2MB 0x04 -#define IEEE80211_CCK_RATE_5MB 0x0B -#define IEEE80211_CCK_RATE_11MB 0x16 -#define IEEE80211_OFDM_RATE_LEN 8 -#define IEEE80211_OFDM_RATE_6MB 0x0C -#define IEEE80211_OFDM_RATE_9MB 0x12 -#define IEEE80211_OFDM_RATE_12MB 0x18 -#define IEEE80211_OFDM_RATE_18MB 0x24 -#define IEEE80211_OFDM_RATE_24MB 0x30 -#define IEEE80211_OFDM_RATE_36MB 0x48 -#define IEEE80211_OFDM_RATE_48MB 0x60 -#define IEEE80211_OFDM_RATE_54MB 0x6C -#define IEEE80211_BASIC_RATE_MASK 0x80 - -#define IEEE80211_CCK_RATE_1MB_MASK (1<<0) -#define IEEE80211_CCK_RATE_2MB_MASK (1<<1) -#define IEEE80211_CCK_RATE_5MB_MASK (1<<2) -#define IEEE80211_CCK_RATE_11MB_MASK (1<<3) -#define IEEE80211_OFDM_RATE_6MB_MASK (1<<4) -#define IEEE80211_OFDM_RATE_9MB_MASK (1<<5) -#define IEEE80211_OFDM_RATE_12MB_MASK (1<<6) -#define IEEE80211_OFDM_RATE_18MB_MASK (1<<7) -#define IEEE80211_OFDM_RATE_24MB_MASK (1<<8) -#define IEEE80211_OFDM_RATE_36MB_MASK (1<<9) -#define IEEE80211_OFDM_RATE_48MB_MASK (1<<10) -#define IEEE80211_OFDM_RATE_54MB_MASK (1<<11) - -#define IEEE80211_CCK_RATES_MASK 0x0000000F -#define IEEE80211_CCK_BASIC_RATES_MASK (IEEE80211_CCK_RATE_1MB_MASK | \ - IEEE80211_CCK_RATE_2MB_MASK) -#define IEEE80211_CCK_DEFAULT_RATES_MASK (IEEE80211_CCK_BASIC_RATES_MASK | \ - IEEE80211_CCK_RATE_5MB_MASK | \ - IEEE80211_CCK_RATE_11MB_MASK) - -#define IEEE80211_OFDM_RATES_MASK 0x00000FF0 -#define IEEE80211_OFDM_BASIC_RATES_MASK (IEEE80211_OFDM_RATE_6MB_MASK | \ - IEEE80211_OFDM_RATE_12MB_MASK | \ - IEEE80211_OFDM_RATE_24MB_MASK) -#define IEEE80211_OFDM_DEFAULT_RATES_MASK (IEEE80211_OFDM_BASIC_RATES_MASK | \ - IEEE80211_OFDM_RATE_9MB_MASK | \ - IEEE80211_OFDM_RATE_18MB_MASK | \ - IEEE80211_OFDM_RATE_36MB_MASK | \ - IEEE80211_OFDM_RATE_48MB_MASK | \ - IEEE80211_OFDM_RATE_54MB_MASK) -#define IEEE80211_DEFAULT_RATES_MASK (IEEE80211_OFDM_DEFAULT_RATES_MASK | \ - IEEE80211_CCK_DEFAULT_RATES_MASK) - -#define IEEE80211_NUM_OFDM_RATES 8 -#define IEEE80211_NUM_CCK_RATES 4 -#define IEEE80211_OFDM_SHIFT_MASK_A 4 - -/* this is stolen and modified from the madwifi driver*/ -#define IEEE80211_FC0_TYPE_MASK 0x0c -#define IEEE80211_FC0_TYPE_DATA 0x08 -#define IEEE80211_FC0_SUBTYPE_MASK 0xB0 -#define IEEE80211_FC0_SUBTYPE_QOS 0x80 - -#define IEEE80211_QOS_HAS_SEQ(fc) \ - (((fc) & (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_MASK)) == \ - (IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_QOS)) - -/* this is stolen from ipw2200 driver */ -#define IEEE_IBSS_MAC_HASH_SIZE 31 -struct ieee_ibss_seq { - u8 mac[ETH_ALEN]; - u16 seq_num[17]; - u16 frag_num[17]; - unsigned long packet_time[17]; - struct list_head list; -}; - -/* NOTE: This data is for statistical purposes; not all hardware provides this - * information for frames received. Not setting these will not cause - * any adverse affects. */ -struct ieee80211_rx_stats { - u32 mac_time[2]; - u8 signalstrength; - s8 rssi; - u8 signal; - u8 noise; - u16 rate; /* in 100 kbps */ - u8 received_channel; - u8 control; - u8 mask; - u8 freq; - u16 len; - u8 nic_type; -}; - -/* IEEE 802.11 requires that STA supports concurrent reception of at least - * three fragmented frames. This define can be increased to support more - * concurrent frames, but it should be noted that each entry can consume about - * 2 kB of RAM and increasing cache size will slow down frame reassembly. */ -#define IEEE80211_FRAG_CACHE_LEN 4 - -struct ieee80211_frag_entry { - unsigned long first_frag_time; - unsigned int seq; - unsigned int last_frag; - struct sk_buff *skb; - u8 src_addr[ETH_ALEN]; - u8 dst_addr[ETH_ALEN]; -}; - -struct ieee80211_stats { - unsigned int tx_unicast_frames; - unsigned int tx_multicast_frames; - unsigned int tx_fragments; - unsigned int tx_unicast_octets; - unsigned int tx_multicast_octets; - unsigned int tx_deferred_transmissions; - unsigned int tx_single_retry_frames; - unsigned int tx_multiple_retry_frames; - unsigned int tx_retry_limit_exceeded; - unsigned int tx_discards; - unsigned int rx_unicast_frames; - unsigned int rx_multicast_frames; - unsigned int rx_fragments; - unsigned int rx_unicast_octets; - unsigned int rx_multicast_octets; - unsigned int rx_fcs_errors; - unsigned int rx_discards_no_buffer; - unsigned int tx_discards_wrong_sa; - unsigned int rx_discards_undecryptable; - unsigned int rx_message_in_msg_fragments; - unsigned int rx_message_in_bad_msg_fragments; -}; - -struct ieee80211_device; - -#include "ieee80211_crypt.h" - -#define SEC_KEY_1 (1<<0) -#define SEC_KEY_2 (1<<1) -#define SEC_KEY_3 (1<<2) -#define SEC_KEY_4 (1<<3) -#define SEC_ACTIVE_KEY (1<<4) -#define SEC_AUTH_MODE (1<<5) -#define SEC_UNICAST_GROUP (1<<6) -#define SEC_LEVEL (1<<7) -#define SEC_ENABLED (1<<8) - -#define SEC_LEVEL_0 0 /* None */ -#define SEC_LEVEL_1 1 /* WEP 40 and 104 bit */ -#define SEC_LEVEL_2 2 /* Level 1 + TKIP */ -#define SEC_LEVEL_2_CKIP 3 /* Level 1 + CKIP */ -#define SEC_LEVEL_3 4 /* Level 2 + CCMP */ - -#define WEP_KEYS 4 -#define WEP_KEY_LEN 13 - -#define WEP_KEY_LEN_MODIF 32 - -struct ieee80211_security { - u16 active_key:2, - enabled:1, - auth_mode:2, - auth_algo:4, - unicast_uses_group:1; - u8 key_sizes[WEP_KEYS]; - u8 keys[WEP_KEYS][WEP_KEY_LEN_MODIF]; - u8 level; - u16 flags; -} __attribute__ ((packed)); - - -/* - - 802.11 data frame from AP - - ,-------------------------------------------------------------------. -Bytes | 2 | 2 | 6 | 6 | 6 | 2 | 0..2312 | 4 | - |------|------|---------|---------|---------|------|---------|------| -Desc. | ctrl | dura | DA/RA | TA | SA | Sequ | frame | fcs | - | | tion | (BSSID) | | | ence | data | | - `-------------------------------------------------------------------' - -Total: 28-2340 bytes - -*/ - -/* Management Frame Information Element Types */ -enum { - MFIE_TYPE_SSID = 0, - MFIE_TYPE_RATES = 1, - MFIE_TYPE_FH_SET = 2, - MFIE_TYPE_DS_SET = 3, - MFIE_TYPE_CF_SET = 4, - MFIE_TYPE_TIM = 5, - MFIE_TYPE_IBSS_SET = 6, - MFIE_TYPE_COUNTRY = 7, - MFIE_TYPE_CHALLENGE = 16, - MFIE_TYPE_ERP = 42, - MFIE_TYPE_RSN = 48, - MFIE_TYPE_RATES_EX = 50, - MFIE_TYPE_GENERIC = 221, -}; - -struct ieee80211_header_data { - __le16 frame_ctl; - u16 duration_id; - u8 addr1[6]; - u8 addr2[6]; - u8 addr3[6]; - u16 seq_ctrl; -}; - -struct ieee80211_hdr_4addr { - __le16 frame_ctl; - u16 duration_id; - u8 addr1[ETH_ALEN]; - u8 addr2[ETH_ALEN]; - u8 addr3[ETH_ALEN]; - u16 seq_ctl; - u8 addr4[ETH_ALEN]; -} __attribute__ ((packed)); - -struct ieee80211_hdr_3addrqos { - u16 frame_ctl; - u16 duration_id; - u8 addr1[ETH_ALEN]; - u8 addr2[ETH_ALEN]; - u8 addr3[ETH_ALEN]; - u16 seq_ctl; - u16 qos_ctl; -} __attribute__ ((packed)); - -struct ieee80211_hdr_4addrqos { - u16 frame_ctl; - u16 duration_id; - u8 addr1[ETH_ALEN]; - u8 addr2[ETH_ALEN]; - u8 addr3[ETH_ALEN]; - u16 seq_ctl; - u8 addr4[ETH_ALEN]; - u16 qos_ctl; -} __attribute__ ((packed)); - -struct ieee80211_info_element_hdr { - u8 id; - u8 len; -} __attribute__ ((packed)); - -struct ieee80211_info_element { - u8 id; - u8 len; - u8 data[0]; -} __attribute__ ((packed)); - -struct ieee80211_authentication { - struct ieee80211_header_data header; - u16 algorithm; - u16 transaction; - u16 status; - //struct ieee80211_info_element_hdr info_element; -} __attribute__ ((packed)); - -struct ieee80211_disassoc_frame { - struct ieee80211_hdr_3addr header; - u16 reasoncode; -} __attribute__ ((packed)); - -struct ieee80211_probe_request { - struct ieee80211_header_data header; - /* struct ieee80211_info_element info_element; */ -} __attribute__ ((packed)); - -struct ieee80211_probe_response { - struct ieee80211_header_data header; - u32 time_stamp[2]; - u16 beacon_interval; - u16 capability; - struct ieee80211_info_element info_element; -} __attribute__ ((packed)); - -struct ieee80211_assoc_request_frame { - struct ieee80211_hdr_3addr header; - u16 capability; - u16 listen_interval; - //u8 current_ap[ETH_ALEN]; - struct ieee80211_info_element_hdr info_element; -} __attribute__ ((packed)); - -struct ieee80211_assoc_response_frame { - struct ieee80211_hdr_3addr header; - u16 capability; - u16 status; - u16 aid; - struct ieee80211_info_element info_element; /* supported rates */ -} __attribute__ ((packed)); - -struct ieee80211_txb { - u8 nr_frags; - u8 encrypted; - u16 reserved; - u16 frag_size; - u16 payload_size; - struct sk_buff *fragments[0]; -}; - -/* SWEEP TABLE ENTRIES NUMBER */ -#define MAX_SWEEP_TAB_ENTRIES 42 -#define MAX_SWEEP_TAB_ENTRIES_PER_PACKET 7 - -/* MAX_RATES_LENGTH needs to be 12. The spec says 8, and many APs - * only use 8, and then use extended rates for the remaining supported - * rates. Other APs, however, stick all of their supported rates on the - * main rates information element... */ -#define MAX_RATES_LENGTH ((u8)12) -#define MAX_RATES_EX_LENGTH ((u8)16) - -#define MAX_NETWORK_COUNT 128 - -#define MAX_CHANNEL_NUMBER 165 - -#define IEEE80211_SOFTMAC_SCAN_TIME 100 /* (HZ / 2) */ -#define IEEE80211_SOFTMAC_ASSOC_RETRY_TIME (HZ * 2) - -#define CRC_LENGTH 4U - -#define MAX_WPA_IE_LEN 64 - -#define NETWORK_EMPTY_ESSID (1 << 0) -#define NETWORK_HAS_OFDM (1 << 1) -#define NETWORK_HAS_CCK (1 << 2) - -struct ieee80211_wmm_ac_param { - u8 ac_aci_acm_aifsn; - u8 ac_ecwmin_ecwmax; - u16 ac_txop_limit; -}; - -struct ieee80211_wmm_ts_info { - u8 ac_dir_tid; - u8 ac_up_psb; - u8 reserved; -} __attribute__ ((packed)); - -struct ieee80211_wmm_tspec_elem { - struct ieee80211_wmm_ts_info ts_info; - u16 norm_msdu_size; - u16 max_msdu_size; - u32 min_serv_inter; - u32 max_serv_inter; - u32 inact_inter; - u32 suspen_inter; - u32 serv_start_time; - u32 min_data_rate; - u32 mean_data_rate; - u32 peak_data_rate; - u32 max_burst_size; - u32 delay_bound; - u32 min_phy_rate; - u16 surp_band_allow; - u16 medium_time; -}__attribute__((packed)); - -enum eap_type { - EAP_PACKET = 0, - EAPOL_START, - EAPOL_LOGOFF, - EAPOL_KEY, - EAPOL_ENCAP_ASF_ALERT -}; - -static const char *eap_types[] = { - [EAP_PACKET] = "EAP-Packet", - [EAPOL_START] = "EAPOL-Start", - [EAPOL_LOGOFF] = "EAPOL-Logoff", - [EAPOL_KEY] = "EAPOL-Key", - [EAPOL_ENCAP_ASF_ALERT] = "EAPOL-Encap-ASF-Alert" -}; - -static inline const char *eap_get_type(int type) -{ - return (type >= ARRAY_SIZE(eap_types)) ? "Unknown" : eap_types[type]; -} - -struct eapol { - u8 snap[6]; - u16 ethertype; - u8 version; - u8 type; - u16 length; -} __attribute__ ((packed)); - -struct ieee80211_softmac_stats { - unsigned int rx_ass_ok; - unsigned int rx_ass_err; - unsigned int rx_probe_rq; - unsigned int tx_probe_rs; - unsigned int tx_beacons; - unsigned int rx_auth_rq; - unsigned int rx_auth_rs_ok; - unsigned int rx_auth_rs_err; - unsigned int tx_auth_rq; - unsigned int no_auth_rs; - unsigned int no_ass_rs; - unsigned int tx_ass_rq; - unsigned int rx_ass_rq; - unsigned int tx_probe_rq; - unsigned int reassoc; - unsigned int swtxstop; - unsigned int swtxawake; -}; - -#define BEACON_PROBE_SSID_ID_POSITION 12 - -/* - * These are the data types that can make up management packets - * - u16 auth_algorithm; - u16 auth_sequence; - u16 beacon_interval; - u16 capability; - u8 current_ap[ETH_ALEN]; - u16 listen_interval; - struct { - u16 association_id:14, reserved:2; - } __attribute__ ((packed)); - u32 time_stamp[2]; - u16 reason; - u16 status; -*/ - -#define IEEE80211_DEFAULT_TX_ESSID "Penguin" -#define IEEE80211_DEFAULT_BASIC_RATE 10 - -enum {WMM_all_frame, WMM_two_frame, WMM_four_frame, WMM_six_frame}; -#define MAX_SP_Len (WMM_all_frame << 4) -#define IEEE80211_QOS_TID 0x0f -#define QOS_CTL_NOTCONTAIN_ACK (0x01 << 5) - -#define MAX_IE_LEN 0xFF //+YJ,080625 - -struct rtl8187se_channel_list { - u8 channel[MAX_CHANNEL_NUMBER + 1]; - u8 len; -}; - -//by amy for ps -#define IEEE80211_WATCH_DOG_TIME 2000 -//by amy for ps -//by amy for antenna -#define ANTENNA_DIVERSITY_TIMER_PERIOD 1000 // 1000 m -//by amy for antenna - -#define IEEE80211_DTIM_MBCAST 4 -#define IEEE80211_DTIM_UCAST 2 -#define IEEE80211_DTIM_VALID 1 -#define IEEE80211_DTIM_INVALID 0 - -#define IEEE80211_PS_DISABLED 0 -#define IEEE80211_PS_UNICAST IEEE80211_DTIM_UCAST -#define IEEE80211_PS_MBCAST IEEE80211_DTIM_MBCAST -#define IEEE80211_PS_ENABLE IEEE80211_DTIM_VALID -//added by David for QoS 2006/6/30 -//#define WMM_Hang_8187 -#ifdef WMM_Hang_8187 -#undef WMM_Hang_8187 -#endif - -#define WME_AC_BE 0x00 -#define WME_AC_BK 0x01 -#define WME_AC_VI 0x02 -#define WME_AC_VO 0x03 -#define WME_ACI_MASK 0x03 -#define WME_AIFSN_MASK 0x03 -#define WME_AC_PRAM_LEN 16 - -//UP Mapping to AC, using in MgntQuery_SequenceNumber() and maybe for DSCP -//#define UP2AC(up) ((up<3) ? ((up==0)?1:0) : (up>>1)) -#define UP2AC(up) ( \ - ((up) < 1) ? WME_AC_BE : \ - ((up) < 3) ? WME_AC_BK : \ - ((up) < 4) ? WME_AC_BE : \ - ((up) < 6) ? WME_AC_VI : \ - WME_AC_VO) -//AC Mapping to UP, using in Tx part for selecting the corresponding TX queue -#define AC2UP(_ac) ( \ - ((_ac) == WME_AC_VO) ? 6 : \ - ((_ac) == WME_AC_VI) ? 5 : \ - ((_ac) == WME_AC_BK) ? 1 : \ - 0) - -#define ETHER_ADDR_LEN 6 /* length of an Ethernet address */ -struct ether_header { - u8 ether_dhost[ETHER_ADDR_LEN]; - u8 ether_shost[ETHER_ADDR_LEN]; - u16 ether_type; -} __attribute__((packed)); - -#ifndef ETHERTYPE_PAE -#define ETHERTYPE_PAE 0x888e /* EAPOL PAE/802.1x */ -#endif -#ifndef ETHERTYPE_IP -#define ETHERTYPE_IP 0x0800 /* IP protocol */ -#endif - -struct ieee80211_network { - /* These entries are used to identify a unique network */ - u8 bssid[ETH_ALEN]; - u8 channel; - /* Ensure null-terminated for any debug msgs */ - u8 ssid[IW_ESSID_MAX_SIZE + 1]; - u8 ssid_len; - - /* These are network statistics */ - struct ieee80211_rx_stats stats; - u16 capability; - u8 rates[MAX_RATES_LENGTH]; - u8 rates_len; - u8 rates_ex[MAX_RATES_EX_LENGTH]; - u8 rates_ex_len; - unsigned long last_scanned; - u8 mode; - u8 flags; - u32 last_associate; - u32 time_stamp[2]; - u16 beacon_interval; - u16 listen_interval; - u16 atim_window; - u8 wpa_ie[MAX_WPA_IE_LEN]; - size_t wpa_ie_len; - u8 rsn_ie[MAX_WPA_IE_LEN]; - size_t rsn_ie_len; - u8 dtim_period; - u8 dtim_data; - u32 last_dtim_sta_time[2]; - struct list_head list; - //appeded for QoS - u8 wmm_info; - struct ieee80211_wmm_ac_param wmm_param[4]; - u8 QoS_Enable; - u8 SignalStrength; -//by amy 080312 - u8 HighestOperaRate; -//by amy 080312 - u8 Turbo_Enable;//enable turbo mode, added by thomas - u16 CountryIeLen; - u8 CountryIeBuf[MAX_IE_LEN]; -}; - -enum ieee80211_state { - - /* the card is not linked at all */ - IEEE80211_NOLINK = 0, - - /* IEEE80211_ASSOCIATING* are for BSS client mode - * the driver shall not perform RX filtering unless - * the state is LINKED. - * The driver shall just check for the state LINKED and - * defaults to NOLINK for ALL the other states (including - * LINKED_SCANNING) - */ - - /* the association procedure will start (wq scheduling)*/ - IEEE80211_ASSOCIATING, - IEEE80211_ASSOCIATING_RETRY, - - /* the association procedure is sending AUTH request*/ - IEEE80211_ASSOCIATING_AUTHENTICATING, - - /* the association procedure has successfully authenticated - * and is sending association request - */ - IEEE80211_ASSOCIATING_AUTHENTICATED, - - /* the link is ok. the card associated to a BSS or linked - * to a ibss cell or acting as an AP and creating the bss - */ - IEEE80211_LINKED, - - /* same as LINKED, but the driver shall apply RX filter - * rules as we are in NO_LINK mode. As the card is still - * logically linked, but it is doing a syncro site survey - * then it will be back to LINKED state. - */ - IEEE80211_LINKED_SCANNING, - -}; - -#define DEFAULT_MAX_SCAN_AGE (15 * HZ) -#define DEFAULT_FTS 2346 - -#define CFG_IEEE80211_RESERVE_FCS (1<<0) -#define CFG_IEEE80211_COMPUTE_FCS (1<<1) - -typedef struct tx_pending_t{ - int frag; - struct ieee80211_txb *txb; -}tx_pending_t; - -enum { - COUNTRY_CODE_FCC = 0, - COUNTRY_CODE_IC = 1, - COUNTRY_CODE_ETSI = 2, - COUNTRY_CODE_SPAIN = 3, - COUNTRY_CODE_FRANCE = 4, - COUNTRY_CODE_MKK = 5, - COUNTRY_CODE_MKK1 = 6, - COUNTRY_CODE_ISRAEL = 7, - COUNTRY_CODE_TELEC = 8, - COUNTRY_CODE_GLOBAL_DOMAIN = 9, - COUNTRY_CODE_WORLD_WIDE_13_INDEX = 10 -}; - -struct ieee80211_device { - struct net_device *dev; - - /* Bookkeeping structures */ - struct net_device_stats stats; - struct ieee80211_stats ieee_stats; - struct ieee80211_softmac_stats softmac_stats; - - /* Probe / Beacon management */ - struct list_head network_free_list; - struct list_head network_list; - struct ieee80211_network *networks; - int scans; - int scan_age; - - int iw_mode; /* operating mode (IW_MODE_*) */ - - spinlock_t lock; - spinlock_t wpax_suitlist_lock; - - int tx_headroom; /* Set to size of any additional room needed at front - * of allocated Tx SKBs */ - u32 config; - - /* WEP and other encryption related settings at the device level */ - int open_wep; /* Set to 1 to allow unencrypted frames */ - - int reset_on_keychange; /* Set to 1 if the HW needs to be reset on - * WEP key changes */ - - /* If the host performs {en,de}cryption, then set to 1 */ - int host_encrypt; - int host_decrypt; - int ieee802_1x; /* is IEEE 802.1X used */ - - /* WPA data */ - int wpa_enabled; - int drop_unencrypted; - int tkip_countermeasures; - int privacy_invoked; - size_t wpa_ie_len; - u8 *wpa_ie; - - u8 ap_mac_addr[6]; - u16 pairwise_key_type; - u16 broadcast_key_type; - - struct list_head crypt_deinit_list; - struct ieee80211_crypt_data *crypt[WEP_KEYS]; - int tx_keyidx; /* default TX key index (crypt[tx_keyidx]) */ - struct timer_list crypt_deinit_timer; - - int bcrx_sta_key; /* use individual keys to override default keys even - * with RX of broad/multicast frames */ - - /* Fragmentation structures */ - /* each stream contains an entry */ - struct ieee80211_frag_entry frag_cache[17][IEEE80211_FRAG_CACHE_LEN]; - unsigned int frag_next_idx[17]; - u16 fts; /* Fragmentation Threshold */ - - /* This stores infos for the current network. - * Either the network we are associated in INFRASTRUCTURE - * or the network that we are creating in MASTER mode. - * ad-hoc is a mixture ;-). - * Note that in infrastructure mode, even when not associated, - * fields bssid and essid may be valid (if wpa_set and essid_set - * are true) as thy carry the value set by the user via iwconfig - */ - struct ieee80211_network current_network; - - - enum ieee80211_state state; - - int short_slot; - int mode; /* A, B, G */ - int modulation; /* CCK, OFDM */ - int freq_band; /* 2.4Ghz, 5.2Ghz, Mixed */ - int abg_true; /* ABG flag */ - - /* used for forcing the ibss workqueue to terminate - * without wait for the syncro scan to terminate - */ - short sync_scan_hurryup; - - void * pDot11dInfo; - bool bGlobalDomain; - - // For Liteon Ch12~13 passive scan - u8 MinPassiveChnlNum; - u8 IbssStartChnl; - - int rate; /* current rate */ - int basic_rate; - //FIXME: please callback, see if redundant with softmac_features - short active_scan; - - /* this contains flags for selectively enable softmac support */ - u16 softmac_features; - - /* if the sequence control field is not filled by HW */ - u16 seq_ctrl[5]; - - /* association procedure transaction sequence number */ - u16 associate_seq; - - /* AID for RTXed association responses */ - u16 assoc_id; - - /* power save mode related*/ - short ps; - short sta_sleep; - int ps_timeout; - struct tasklet_struct ps_task; - u32 ps_th; - u32 ps_tl; - - short raw_tx; - /* used if IEEE_SOFTMAC_TX_QUEUE is set */ - short queue_stop; - short scanning; - short proto_started; - - struct semaphore wx_sem; - struct semaphore scan_sem; - - spinlock_t mgmt_tx_lock; - spinlock_t beacon_lock; - - short beacon_txing; - - short wap_set; - short ssid_set; - - u8 wpax_type_set; //{added by David, 2006.9.28} - u32 wpax_type_notify; //{added by David, 2006.9.26} - - /* QoS related flag */ - char init_wmmparam_flag; - - /* for discarding duplicated packets in IBSS */ - struct list_head ibss_mac_hash[IEEE_IBSS_MAC_HASH_SIZE]; - - /* for discarding duplicated packets in BSS */ - u16 last_rxseq_num[17]; /* rx seq previous per-tid */ - u16 last_rxfrag_num[17];/* tx frag previous per-tid */ - unsigned long last_packet_time[17]; - - /* for PS mode */ - unsigned long last_rx_ps_time; - - /* used if IEEE_SOFTMAC_SINGLE_QUEUE is set */ - struct sk_buff *mgmt_queue_ring[MGMT_QUEUE_NUM]; - int mgmt_queue_head; - int mgmt_queue_tail; - - - /* used if IEEE_SOFTMAC_TX_QUEUE is set */ - struct tx_pending_t tx_pending; - - /* used if IEEE_SOFTMAC_ASSOCIATE is set */ - struct timer_list associate_timer; - - /* used if IEEE_SOFTMAC_BEACONS is set */ - struct timer_list beacon_timer; - - struct work_struct associate_complete_wq; -// struct work_struct associate_retry_wq; - struct work_struct associate_procedure_wq; -// struct work_struct softmac_scan_wq; - struct work_struct wx_sync_scan_wq; - struct work_struct wmm_param_update_wq; - struct work_struct ps_request_tx_ack_wq;//for ps -// struct work_struct hw_wakeup_wq; -// struct work_struct hw_sleep_wq; -// struct work_struct watch_dog_wq; - bool bInactivePs; - bool actscanning; - bool beinretry; - u16 ListenInterval; - unsigned long NumRxDataInPeriod; //YJ,add,080828 - unsigned long NumRxBcnInPeriod; //YJ,add,080828 - unsigned long NumRxOkTotal; - unsigned long NumRxUnicast;//YJ,add,080828,for keep alive - bool bHwRadioOff; - struct delayed_work softmac_scan_wq; - struct delayed_work associate_retry_wq; - struct delayed_work hw_wakeup_wq; - struct delayed_work hw_sleep_wq;//+by amy 080324 - struct delayed_work watch_dog_wq; - struct delayed_work sw_antenna_wq; - struct delayed_work start_ibss_wq; -//by amy for rate adaptive 080312 - struct delayed_work rate_adapter_wq; -//by amy for rate adaptive - struct delayed_work hw_dig_wq; - struct delayed_work tx_pw_wq; - -//Added for RF power on power off by lizhaoming 080512 - struct delayed_work GPIOChangeRFWorkItem; - - struct workqueue_struct *wq; - - /* Callback functions */ - void (*set_security)(struct net_device *dev, - struct ieee80211_security *sec); - - /* Used to TX data frame by using txb structs. - * this is not used if in the softmac_features - * is set the flag IEEE_SOFTMAC_TX_QUEUE - */ - int (*hard_start_xmit)(struct ieee80211_txb *txb, - struct net_device *dev); - - int (*reset_port)(struct net_device *dev); - - /* Softmac-generated frames (management) are TXed via this - * callback if the flag IEEE_SOFTMAC_SINGLE_QUEUE is - * not set. As some cards may have different HW queues that - * one might want to use for data and management frames - * the option to have two callbacks might be useful. - * This function can't sleep. - */ - int (*softmac_hard_start_xmit)(struct sk_buff *skb, - struct net_device *dev); - - /* used instead of hard_start_xmit (not softmac_hard_start_xmit) - * if the IEEE_SOFTMAC_TX_QUEUE feature is used to TX data - * frames. If the option IEEE_SOFTMAC_SINGLE_QUEUE is also set - * then also management frames are sent via this callback. - * This function can't sleep. - */ - void (*softmac_data_hard_start_xmit)(struct sk_buff *skb, - struct net_device *dev,int rate); - - /* stops the HW queue for DATA frames. Useful to avoid - * waste time to TX data frame when we are reassociating - * This function can sleep. - */ - void (*data_hard_stop)(struct net_device *dev); - - /* OK this is complementar to data_poll_hard_stop */ - void (*data_hard_resume)(struct net_device *dev); - - /* ask to the driver to retune the radio . - * This function can sleep. the driver should ensure - * the radio has been switched before return. - */ - void (*set_chan)(struct net_device *dev,short ch); - - /* These are not used if the ieee stack takes care of - * scanning (IEEE_SOFTMAC_SCAN feature set). - * In this case only the set_chan is used. - * - * The syncro version is similar to the start_scan but - * does not return until all channels has been scanned. - * this is called in user context and should sleep, - * it is called in a work_queue when switching to ad-hoc mode - * or in behalf of iwlist scan when the card is associated - * and root user ask for a scan. - * the function stop_scan should stop both the syncro and - * background scanning and can sleep. - * The function start_scan should initiate the background - * scanning and can't sleep. - */ - void (*scan_syncro)(struct net_device *dev); - void (*start_scan)(struct net_device *dev); - void (*stop_scan)(struct net_device *dev); - - /* indicate the driver that the link state is changed - * for example it may indicate the card is associated now. - * Driver might be interested in this to apply RX filter - * rules or simply light the LINK led - */ - void (*link_change)(struct net_device *dev); - - /* these two function indicates to the HW when to start - * and stop to send beacons. This is used when the - * IEEE_SOFTMAC_BEACONS is not set. For now the - * stop_send_bacons is NOT guaranteed to be called only - * after start_send_beacons. - */ - void (*start_send_beacons) (struct net_device *dev); - void (*stop_send_beacons) (struct net_device *dev); - - /* power save mode related */ - void (*sta_wake_up) (struct net_device *dev); - void (*ps_request_tx_ack) (struct net_device *dev); - void (*enter_sleep_state) (struct net_device *dev, u32 th, u32 tl); - short (*ps_is_queue_empty) (struct net_device *dev); - - /* QoS related */ - //void (*wmm_param_update) (struct net_device *dev, u8 *ac_param); - //void (*wmm_param_update) (struct ieee80211_device *ieee); - - /* This must be the last item so that it points to the data - * allocated beyond this structure by alloc_ieee80211 */ - u8 priv[0]; -}; - -#define IEEE_A (1<<0) -#define IEEE_B (1<<1) -#define IEEE_G (1<<2) -#define IEEE_MODE_MASK (IEEE_A|IEEE_B|IEEE_G) - -/* Generate a 802.11 header */ - -/* Uses the channel change callback directly - * instead of [start/stop] scan callbacks - */ -#define IEEE_SOFTMAC_SCAN (1<<2) - -/* Perform authentication and association handshake */ -#define IEEE_SOFTMAC_ASSOCIATE (1<<3) - -/* Generate probe requests */ -#define IEEE_SOFTMAC_PROBERQ (1<<4) - -/* Generate response to probe requests */ -#define IEEE_SOFTMAC_PROBERS (1<<5) - -/* The ieee802.11 stack will manages the netif queue - * wake/stop for the driver, taking care of 802.11 - * fragmentation. See softmac.c for details. */ -#define IEEE_SOFTMAC_TX_QUEUE (1<<7) - -/* Uses only the softmac_data_hard_start_xmit - * even for TX management frames. - */ -#define IEEE_SOFTMAC_SINGLE_QUEUE (1<<8) - -/* Generate beacons. The stack will enqueue beacons - * to the card - */ -#define IEEE_SOFTMAC_BEACONS (1<<6) - - - -static inline void *ieee80211_priv(struct net_device *dev) -{ - return ((struct ieee80211_device *)netdev_priv(dev))->priv; -} - -static inline int ieee80211_is_empty_essid(const char *essid, int essid_len) -{ - /* Single white space is for Linksys APs */ - if (essid_len == 1 && essid[0] == ' ') - return 1; - - /* Otherwise, if the entire essid is 0, we assume it is hidden */ - while (essid_len) { - essid_len--; - if (essid[essid_len] != '\0') - return 0; - } - - return 1; -} - -static inline int ieee80211_is_valid_mode(struct ieee80211_device *ieee, - int mode) -{ - /* - * It is possible for both access points and our device to support - * combinations of modes, so as long as there is one valid combination - * of ap/device supported modes, then return success - * - */ - if ((mode & IEEE_A) && - (ieee->modulation & IEEE80211_OFDM_MODULATION) && - (ieee->freq_band & IEEE80211_52GHZ_BAND)) - return 1; - - if ((mode & IEEE_G) && - (ieee->modulation & IEEE80211_OFDM_MODULATION) && - (ieee->freq_band & IEEE80211_24GHZ_BAND)) - return 1; - - if ((mode & IEEE_B) && - (ieee->modulation & IEEE80211_CCK_MODULATION) && - (ieee->freq_band & IEEE80211_24GHZ_BAND)) - return 1; - - return 0; -} - -static inline int ieee80211_get_hdrlen(u16 fc) -{ - int hdrlen = 24; - - switch (WLAN_FC_GET_TYPE(fc)) { - case IEEE80211_FTYPE_DATA: - if ((fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS)) - hdrlen = 30; /* Addr4 */ - if(IEEE80211_QOS_HAS_SEQ(fc)) - hdrlen += 2; /* QOS ctrl*/ - break; - case IEEE80211_FTYPE_CTL: - switch (WLAN_FC_GET_STYPE(fc)) { - case IEEE80211_STYPE_CTS: - case IEEE80211_STYPE_ACK: - hdrlen = 10; - break; - default: - hdrlen = 16; - break; - } - break; - } - - return hdrlen; -} - - - -/* ieee80211.c */ -extern void free_ieee80211(struct net_device *dev); -extern struct net_device *alloc_ieee80211(int sizeof_priv); - -extern int ieee80211_set_encryption(struct ieee80211_device *ieee); - -/* ieee80211_tx.c */ - -extern int ieee80211_encrypt_fragment(struct ieee80211_device *ieee, - struct sk_buff *frag, int hdr_len); - -extern int ieee80211_rtl_xmit(struct sk_buff *skb, struct net_device *dev); -extern void ieee80211_txb_free(struct ieee80211_txb *); - - -/* ieee80211_rx.c */ -extern int ieee80211_rtl_rx(struct ieee80211_device *ieee, struct sk_buff *skb, - struct ieee80211_rx_stats *rx_stats); -extern void ieee80211_rx_mgt(struct ieee80211_device *ieee, - struct ieee80211_hdr_4addr *header, - struct ieee80211_rx_stats *stats); - -/* ieee80211_wx.c */ -extern int ieee80211_wx_get_scan(struct ieee80211_device *ieee, - struct iw_request_info *info, - union iwreq_data *wrqu, char *key); -extern int ieee80211_wx_set_encode(struct ieee80211_device *ieee, - struct iw_request_info *info, - union iwreq_data *wrqu, char *key); -extern int ieee80211_wx_get_encode(struct ieee80211_device *ieee, - struct iw_request_info *info, - union iwreq_data *wrqu, char *key); -extern int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra); -int ieee80211_wx_set_auth(struct ieee80211_device *ieee, - struct iw_request_info *info, - struct iw_param *data, char *extra); -int ieee80211_wx_set_mlme(struct ieee80211_device *ieee, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra); - -int ieee80211_wx_set_gen_ie(struct ieee80211_device *ieee, u8 *ie, size_t len); -/* ieee80211_softmac.c */ -extern short ieee80211_is_54g(const struct ieee80211_network *net); -extern short ieee80211_is_shortslot(const struct ieee80211_network *net); -extern int ieee80211_rx_frame_softmac(struct ieee80211_device *ieee, - struct sk_buff *skb, - struct ieee80211_rx_stats *rx_stats, - u16 type, u16 stype); -extern void ieee80211_softmac_new_net(struct ieee80211_device *ieee, - struct ieee80211_network *net); - -extern void ieee80211_softmac_xmit(struct ieee80211_txb *txb, - struct ieee80211_device *ieee); -extern void ieee80211_softmac_check_all_nets(struct ieee80211_device *ieee); -extern void ieee80211_start_bss(struct ieee80211_device *ieee); -extern void ieee80211_start_master_bss(struct ieee80211_device *ieee); -extern void ieee80211_start_ibss(struct ieee80211_device *ieee); -extern void ieee80211_softmac_init(struct ieee80211_device *ieee); -extern void ieee80211_softmac_free(struct ieee80211_device *ieee); -extern void ieee80211_associate_abort(struct ieee80211_device *ieee); -extern void ieee80211_disassociate(struct ieee80211_device *ieee); -extern void ieee80211_stop_scan(struct ieee80211_device *ieee); -extern void ieee80211_start_scan_syncro(struct ieee80211_device *ieee); -extern void ieee80211_check_all_nets(struct ieee80211_device *ieee); -extern void ieee80211_start_protocol(struct ieee80211_device *ieee); -extern void ieee80211_stop_protocol(struct ieee80211_device *ieee); -extern void ieee80211_softmac_start_protocol(struct ieee80211_device *ieee); -extern void ieee80211_softmac_stop_protocol(struct ieee80211_device *ieee); -extern void ieee80211_reset_queue(struct ieee80211_device *ieee); -extern void ieee80211_rtl_wake_queue(struct ieee80211_device *ieee); -extern void ieee80211_rtl_stop_queue(struct ieee80211_device *ieee); -extern struct sk_buff *ieee80211_get_beacon(struct ieee80211_device *ieee); -extern void ieee80211_start_send_beacons(struct ieee80211_device *ieee); -extern void ieee80211_stop_send_beacons(struct ieee80211_device *ieee); -extern int ieee80211_wpa_supplicant_ioctl(struct ieee80211_device *ieee, - struct iw_point *p); -extern void notify_wx_assoc_event(struct ieee80211_device *ieee); -extern void ieee80211_ps_tx_ack(struct ieee80211_device *ieee, short success); -extern void SendDisassociation(struct ieee80211_device *ieee, u8 *asSta, - u8 asRsn); -extern void ieee80211_rtl_start_scan(struct ieee80211_device *ieee); - -//Add for RF power on power off by lizhaoming 080512 -extern void SendDisassociation(struct ieee80211_device *ieee, u8 *asSta, - u8 asRsn); - -/* ieee80211_crypt_ccmp&tkip&wep.c */ -extern void ieee80211_tkip_null(void); -extern void ieee80211_wep_null(void); -extern void ieee80211_ccmp_null(void); -/* ieee80211_softmac_wx.c */ - -extern int ieee80211_wx_get_wap(struct ieee80211_device *ieee, - struct iw_request_info *info, - union iwreq_data *wrqu, char *ext); - -extern int ieee80211_wx_set_wap(struct ieee80211_device *ieee, - struct iw_request_info *info, - union iwreq_data *awrq, - char *extra); - -extern int ieee80211_wx_get_essid(struct ieee80211_device *ieee, - struct iw_request_info *a, - union iwreq_data *wrqu, char *b); - -extern int ieee80211_wx_set_rate(struct ieee80211_device *ieee, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra); - -extern int ieee80211_wx_get_rate(struct ieee80211_device *ieee, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra); - -extern int ieee80211_wx_set_mode(struct ieee80211_device *ieee, - struct iw_request_info *a, - union iwreq_data *wrqu, char *b); - -extern int ieee80211_wx_set_scan(struct ieee80211_device *ieee, - struct iw_request_info *a, - union iwreq_data *wrqu, char *b); - -extern int ieee80211_wx_set_essid(struct ieee80211_device *ieee, - struct iw_request_info *a, - union iwreq_data *wrqu, char *extra); - -extern int ieee80211_wx_get_mode(struct ieee80211_device *ieee, - struct iw_request_info *a, - union iwreq_data *wrqu, char *b); - -extern int ieee80211_wx_set_freq(struct ieee80211_device *ieee, - struct iw_request_info *a, - union iwreq_data *wrqu, char *b); - -extern int ieee80211_wx_get_freq(struct ieee80211_device *ieee, - struct iw_request_info *a, - union iwreq_data *wrqu, char *b); - -extern void ieee80211_wx_sync_scan_wq(struct work_struct *work); - -extern int ieee80211_wx_set_rawtx(struct ieee80211_device *ieee, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra); - -extern int ieee80211_wx_get_name(struct ieee80211_device *ieee, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra); - -extern int ieee80211_wx_set_power(struct ieee80211_device *ieee, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra); - -extern int ieee80211_wx_get_power(struct ieee80211_device *ieee, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra); - -extern void ieee80211_softmac_ips_scan_syncro(struct ieee80211_device *ieee); - -extern void ieee80211_sta_ps_send_null_frame(struct ieee80211_device *ieee, - short pwr); - -extern const long ieee80211_wlan_frequencies[]; - -extern inline void ieee80211_increment_scans(struct ieee80211_device *ieee) -{ - ieee->scans++; -} - -extern inline int ieee80211_get_scans(struct ieee80211_device *ieee) -{ - return ieee->scans; -} - -static inline const char *escape_essid(const char *essid, u8 essid_len) { - static char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; - const char *s = essid; - char *d = escaped; - - if (ieee80211_is_empty_essid(essid, essid_len)) { - memcpy(escaped, "", sizeof("")); - return escaped; - } - - essid_len = min(essid_len, (u8)IW_ESSID_MAX_SIZE); - while (essid_len--) { - if (*s == '\0') { - *d++ = '\\'; - *d++ = '0'; - s++; - } else { - *d++ = *s++; - } - } - *d = '\0'; - return escaped; -} -#endif /* IEEE80211_H */ diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt.c deleted file mode 100644 index 101f0c0cdb0..00000000000 --- a/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt.c +++ /dev/null @@ -1,240 +0,0 @@ -/* - * Host AP crypto routines - * - * Copyright (c) 2002-2003, Jouni Malinen - * Portions Copyright (C) 2004, Intel Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. See README and COPYING for - * more details. - * - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -//#include -#include -#include -#include -#include - -#include "ieee80211.h" - -MODULE_AUTHOR("Jouni Malinen"); -MODULE_DESCRIPTION("HostAP crypto"); -MODULE_LICENSE("GPL"); - -struct ieee80211_crypto_alg { - struct list_head list; - struct ieee80211_crypto_ops *ops; -}; - - -struct ieee80211_crypto { - struct list_head algs; - spinlock_t lock; -}; - -static struct ieee80211_crypto *hcrypt; - -void ieee80211_crypt_deinit_entries(struct ieee80211_device *ieee, int force) -{ - struct list_head *ptr, *n; - struct ieee80211_crypt_data *entry; - - for (ptr = ieee->crypt_deinit_list.next, n = ptr->next; - ptr != &ieee->crypt_deinit_list; ptr = n, n = ptr->next) { - entry = list_entry(ptr, struct ieee80211_crypt_data, list); - - if (atomic_read(&entry->refcnt) != 0 && !force) - continue; - - list_del(ptr); - - if (entry->ops) - entry->ops->deinit(entry->priv); - kfree(entry); - } -} - -void ieee80211_crypt_deinit_handler(unsigned long data) -{ - struct ieee80211_device *ieee = (struct ieee80211_device *)data; - unsigned long flags; - - spin_lock_irqsave(&ieee->lock, flags); - ieee80211_crypt_deinit_entries(ieee, 0); - if (!list_empty(&ieee->crypt_deinit_list)) { - pr_debug("entries remaining in delayed crypt deletion list\n"); - ieee->crypt_deinit_timer.expires = jiffies + HZ; - add_timer(&ieee->crypt_deinit_timer); - } - spin_unlock_irqrestore(&ieee->lock, flags); - -} - -void ieee80211_crypt_delayed_deinit(struct ieee80211_device *ieee, - struct ieee80211_crypt_data **crypt) -{ - struct ieee80211_crypt_data *tmp; - unsigned long flags; - - if (*crypt == NULL) - return; - - tmp = *crypt; - *crypt = NULL; - - /* must not run ops->deinit() while there may be pending encrypt or - * decrypt operations. Use a list of delayed deinits to avoid needing - * locking. */ - - spin_lock_irqsave(&ieee->lock, flags); - list_add(&tmp->list, &ieee->crypt_deinit_list); - if (!timer_pending(&ieee->crypt_deinit_timer)) { - ieee->crypt_deinit_timer.expires = jiffies + HZ; - add_timer(&ieee->crypt_deinit_timer); - } - spin_unlock_irqrestore(&ieee->lock, flags); -} - -int ieee80211_register_crypto_ops(struct ieee80211_crypto_ops *ops) -{ - unsigned long flags; - struct ieee80211_crypto_alg *alg; - - if (hcrypt == NULL) - return -1; - - alg = kzalloc(sizeof(*alg), GFP_KERNEL); - if (alg == NULL) - return -ENOMEM; - - alg->ops = ops; - - spin_lock_irqsave(&hcrypt->lock, flags); - list_add(&alg->list, &hcrypt->algs); - spin_unlock_irqrestore(&hcrypt->lock, flags); - - pr_debug("registered algorithm '%s'\n", ops->name); - - return 0; -} - -int ieee80211_unregister_crypto_ops(struct ieee80211_crypto_ops *ops) -{ - unsigned long flags; - struct list_head *ptr; - struct ieee80211_crypto_alg *del_alg = NULL; - - if (hcrypt == NULL) - return -1; - - spin_lock_irqsave(&hcrypt->lock, flags); - for (ptr = hcrypt->algs.next; ptr != &hcrypt->algs; ptr = ptr->next) { - struct ieee80211_crypto_alg *alg = - (struct ieee80211_crypto_alg *) ptr; - if (alg->ops == ops) { - list_del(&alg->list); - del_alg = alg; - break; - } - } - spin_unlock_irqrestore(&hcrypt->lock, flags); - - if (del_alg) { - pr_debug("unregistered algorithm '%s'\n", ops->name); - kfree(del_alg); - } - - return del_alg ? 0 : -1; -} - - -struct ieee80211_crypto_ops *ieee80211_get_crypto_ops(const char *name) -{ - unsigned long flags; - struct list_head *ptr; - struct ieee80211_crypto_alg *found_alg = NULL; - - if (hcrypt == NULL) - return NULL; - - spin_lock_irqsave(&hcrypt->lock, flags); - for (ptr = hcrypt->algs.next; ptr != &hcrypt->algs; ptr = ptr->next) { - struct ieee80211_crypto_alg *alg = - (struct ieee80211_crypto_alg *) ptr; - if (strcmp(alg->ops->name, name) == 0) { - found_alg = alg; - break; - } - } - spin_unlock_irqrestore(&hcrypt->lock, flags); - - if (found_alg) - return found_alg->ops; - else - return NULL; -} - - -static void *ieee80211_crypt_null_init(int keyidx) { return (void *) 1; } -static void ieee80211_crypt_null_deinit(void *priv) {} - -static struct ieee80211_crypto_ops ieee80211_crypt_null = { - .name = "NULL", - .init = ieee80211_crypt_null_init, - .deinit = ieee80211_crypt_null_deinit, - .encrypt_mpdu = NULL, - .decrypt_mpdu = NULL, - .encrypt_msdu = NULL, - .decrypt_msdu = NULL, - .set_key = NULL, - .get_key = NULL, - .extra_prefix_len = 0, - .extra_postfix_len = 0, - .owner = THIS_MODULE, -}; - - -int ieee80211_crypto_init(void) -{ - int ret = -ENOMEM; - - hcrypt = kzalloc(sizeof(*hcrypt), GFP_KERNEL); - if (!hcrypt) - goto out; - - INIT_LIST_HEAD(&hcrypt->algs); - spin_lock_init(&hcrypt->lock); - - ret = ieee80211_register_crypto_ops(&ieee80211_crypt_null); - if (ret < 0) { - kfree(hcrypt); - hcrypt = NULL; - } -out: - return ret; -} - - -void ieee80211_crypto_deinit(void) -{ - struct list_head *ptr, *n; - struct ieee80211_crypto_alg *alg = NULL; - - if (hcrypt == NULL) - return; - - list_for_each_safe(ptr, n, &hcrypt->algs) { - alg = list_entry(ptr, struct ieee80211_crypto_alg, list); - if (alg) { - list_del(ptr); - pr_debug("unregistered algorithm '%s' (deinit)\n", - alg->ops->name); - kfree(alg); - } - } - kfree(hcrypt); -} diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt.h b/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt.h deleted file mode 100644 index 0b4ea431982..00000000000 --- a/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Original code based on Host AP (software wireless LAN access point) driver - * for Intersil Prism2/2.5/3. - * - * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen - * - * Copyright (c) 2002-2003, Jouni Malinen - * - * Adaption to a generic IEEE 802.11 stack by James Ketrenos - * - * - * Copyright (c) 2004, Intel Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. See README and COPYING for - * more details. - */ - -/* - * This file defines the interface to the ieee80211 crypto module. - */ -#ifndef IEEE80211_CRYPT_H -#define IEEE80211_CRYPT_H - -#include - -struct ieee80211_crypto_ops { - const char *name; - - /* init new crypto context (e.g., allocate private data space, - * select IV, etc.); returns NULL on failure or pointer to allocated - * private data on success */ - void * (*init)(int keyidx); - - /* deinitialize crypto context and free allocated private data */ - void (*deinit)(void *priv); - - /* encrypt/decrypt return < 0 on error or >= 0 on success. The return - * value from decrypt_mpdu is passed as the keyidx value for - * decrypt_msdu. skb must have enough head and tail room for the - * encryption; if not, error will be returned; these functions are - * called for all MPDUs (i.e., fragments). - */ - int (*encrypt_mpdu)(struct sk_buff *skb, int hdr_len, void *priv); - int (*decrypt_mpdu)(struct sk_buff *skb, int hdr_len, void *priv); - - /* These functions are called for full MSDUs, i.e. full frames. - * These can be NULL if full MSDU operations are not needed. */ - int (*encrypt_msdu)(struct sk_buff *skb, int hdr_len, void *priv); - int (*decrypt_msdu)(struct sk_buff *skb, int keyidx, int hdr_len, - void *priv); - - int (*set_key)(void *key, int len, u8 *seq, void *priv); - int (*get_key)(void *key, int len, u8 *seq, void *priv); - - /* procfs handler for printing out key information and possible - * statistics */ - char * (*print_stats)(char *p, void *priv); - - /* maximum number of bytes added by encryption; encrypt buf is - * allocated with extra_prefix_len bytes, copy of in_buf, and - * extra_postfix_len; encrypt need not use all this space, but - * the result must start at the beginning of the buffer and correct - * length must be returned */ - int extra_prefix_len, extra_postfix_len; - - struct module *owner; -}; - -struct ieee80211_crypt_data { - struct list_head list; /* delayed deletion list */ - struct ieee80211_crypto_ops *ops; - void *priv; - atomic_t refcnt; -}; - -int ieee80211_register_crypto_ops(struct ieee80211_crypto_ops *ops); -int ieee80211_unregister_crypto_ops(struct ieee80211_crypto_ops *ops); -struct ieee80211_crypto_ops *ieee80211_get_crypto_ops(const char *name); -void ieee80211_crypt_deinit_entries(struct ieee80211_device *, int); -void ieee80211_crypt_deinit_handler(unsigned long); -void ieee80211_crypt_delayed_deinit(struct ieee80211_device *ieee, - struct ieee80211_crypt_data **crypt); - -#endif diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_ccmp.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_ccmp.c deleted file mode 100644 index 4fe25381863..00000000000 --- a/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_ccmp.c +++ /dev/null @@ -1,455 +0,0 @@ -/* - * Host AP crypt: host-based CCMP encryption implementation for Host AP driver - * - * Copyright (c) 2003-2004, Jouni Malinen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. See README and COPYING for - * more details. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ieee80211.h" - -#include -#include - -MODULE_AUTHOR("Jouni Malinen"); -MODULE_DESCRIPTION("Host AP crypt: CCMP"); -MODULE_LICENSE("GPL"); - - -#define AES_BLOCK_LEN 16 -#define CCMP_HDR_LEN 8 -#define CCMP_MIC_LEN 8 -#define CCMP_TK_LEN 16 -#define CCMP_PN_LEN 6 - -struct ieee80211_ccmp_data { - u8 key[CCMP_TK_LEN]; - int key_set; - - u8 tx_pn[CCMP_PN_LEN]; - u8 rx_pn[CCMP_PN_LEN]; - - u32 dot11RSNAStatsCCMPFormatErrors; - u32 dot11RSNAStatsCCMPReplays; - u32 dot11RSNAStatsCCMPDecryptErrors; - - int key_idx; - - struct crypto_tfm *tfm; - - /* scratch buffers for virt_to_page() (crypto API) */ - u8 tx_b0[AES_BLOCK_LEN], tx_b[AES_BLOCK_LEN], - tx_e[AES_BLOCK_LEN], tx_s0[AES_BLOCK_LEN]; - u8 rx_b0[AES_BLOCK_LEN], rx_b[AES_BLOCK_LEN], rx_a[AES_BLOCK_LEN]; -}; - -static void ieee80211_ccmp_aes_encrypt(struct crypto_tfm *tfm, - const u8 pt[16], u8 ct[16]) -{ - crypto_cipher_encrypt_one((void *)tfm, ct, pt); -} - -static void *ieee80211_ccmp_init(int key_idx) -{ - struct ieee80211_ccmp_data *priv; - - priv = kzalloc(sizeof(*priv), GFP_ATOMIC); - if (priv == NULL) - goto fail; - priv->key_idx = key_idx; - - priv->tfm = (void *)crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC); - if (IS_ERR(priv->tfm)) { - pr_debug("could not allocate crypto API aes\n"); - priv->tfm = NULL; - goto fail; - } - - return priv; - -fail: - if (priv) { - if (priv->tfm) - crypto_free_cipher((void *)priv->tfm); - kfree(priv); - } - - return NULL; -} - - -static void ieee80211_ccmp_deinit(void *priv) -{ - struct ieee80211_ccmp_data *_priv = priv; - - if (_priv && _priv->tfm) - crypto_free_cipher((void *)_priv->tfm); - kfree(priv); -} - - -static inline void xor_block(u8 *b, u8 *a, size_t len) -{ - int i; - for (i = 0; i < len; i++) - b[i] ^= a[i]; -} - -static void ccmp_init_blocks(struct crypto_tfm *tfm, - struct ieee80211_hdr_4addr *hdr, - u8 *pn, size_t dlen, u8 *b0, u8 *auth, - u8 *s0) -{ - u8 *pos, qc = 0; - size_t aad_len; - u16 fc; - int a4_included, qc_included; - u8 aad[2 * AES_BLOCK_LEN]; - - fc = le16_to_cpu(hdr->frame_ctl); - a4_included = ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == - (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)); - /* - qc_included = ((WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA) && - (WLAN_FC_GET_STYPE(fc) & 0x08)); - */ - qc_included = ((WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA) && - (WLAN_FC_GET_STYPE(fc) & 0x80)); - aad_len = 22; - if (a4_included) - aad_len += 6; - if (qc_included) { - pos = (u8 *) &hdr->addr4; - if (a4_included) - pos += 6; - qc = *pos & 0x0f; - aad_len += 2; - } - /* CCM Initial Block: - * Flag (Include authentication header, M=3 (8-octet MIC), - * L=1 (2-octet Dlen)) - * Nonce: 0x00 | A2 | PN - * Dlen */ - b0[0] = 0x59; - b0[1] = qc; - memcpy(b0 + 2, hdr->addr2, ETH_ALEN); - memcpy(b0 + 8, pn, CCMP_PN_LEN); - b0[14] = (dlen >> 8) & 0xff; - b0[15] = dlen & 0xff; - - /* AAD: - * FC with bits 4..6 and 11..13 masked to zero; 14 is always one - * A1 | A2 | A3 - * SC with bits 4..15 (seq#) masked to zero - * A4 (if present) - * QC (if present) - */ - pos = (u8 *) hdr; - aad[0] = 0; /* aad_len >> 8 */ - aad[1] = aad_len & 0xff; - aad[2] = pos[0] & 0x8f; - aad[3] = pos[1] & 0xc7; - memcpy(aad + 4, hdr->addr1, 3 * ETH_ALEN); - pos = (u8 *) &hdr->seq_ctl; - aad[22] = pos[0] & 0x0f; - aad[23] = 0; /* all bits masked */ - memset(aad + 24, 0, 8); - if (a4_included) - memcpy(aad + 24, hdr->addr4, ETH_ALEN); - if (qc_included) { - aad[a4_included ? 30 : 24] = qc; - /* rest of QC masked */ - } - - /* Start with the first block and AAD */ - ieee80211_ccmp_aes_encrypt(tfm, b0, auth); - xor_block(auth, aad, AES_BLOCK_LEN); - ieee80211_ccmp_aes_encrypt(tfm, auth, auth); - xor_block(auth, &aad[AES_BLOCK_LEN], AES_BLOCK_LEN); - ieee80211_ccmp_aes_encrypt(tfm, auth, auth); - b0[0] &= 0x07; - b0[14] = b0[15] = 0; - ieee80211_ccmp_aes_encrypt(tfm, b0, s0); -} - -static int ieee80211_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv) -{ - struct ieee80211_ccmp_data *key = priv; - int data_len, i; - u8 *pos; - struct ieee80211_hdr_4addr *hdr; - int blocks, last, len; - u8 *mic; - u8 *b0 = key->tx_b0; - u8 *b = key->tx_b; - u8 *e = key->tx_e; - u8 *s0 = key->tx_s0; - - if (skb_headroom(skb) < CCMP_HDR_LEN || - skb_tailroom(skb) < CCMP_MIC_LEN || - skb->len < hdr_len) - return -1; - - data_len = skb->len - hdr_len; - pos = skb_push(skb, CCMP_HDR_LEN); - memmove(pos, pos + CCMP_HDR_LEN, hdr_len); - pos += hdr_len; - - i = CCMP_PN_LEN - 1; - while (i >= 0) { - key->tx_pn[i]++; - if (key->tx_pn[i] != 0) - break; - i--; - } - - *pos++ = key->tx_pn[5]; - *pos++ = key->tx_pn[4]; - *pos++ = 0; - *pos++ = (key->key_idx << 6) | (1 << 5) /* Ext IV included */; - *pos++ = key->tx_pn[3]; - *pos++ = key->tx_pn[2]; - *pos++ = key->tx_pn[1]; - *pos++ = key->tx_pn[0]; - - hdr = (struct ieee80211_hdr_4addr *)skb->data; - mic = skb_put(skb, CCMP_MIC_LEN); - - ccmp_init_blocks(key->tfm, hdr, key->tx_pn, data_len, b0, b, s0); - - blocks = (data_len + AES_BLOCK_LEN - 1) / AES_BLOCK_LEN; - last = data_len % AES_BLOCK_LEN; - - for (i = 1; i <= blocks; i++) { - len = (i == blocks && last) ? last : AES_BLOCK_LEN; - /* Authentication */ - xor_block(b, pos, len); - ieee80211_ccmp_aes_encrypt(key->tfm, b, b); - /* Encryption, with counter */ - b0[14] = (i >> 8) & 0xff; - b0[15] = i & 0xff; - ieee80211_ccmp_aes_encrypt(key->tfm, b0, e); - xor_block(pos, e, len); - pos += len; - } - - for (i = 0; i < CCMP_MIC_LEN; i++) - mic[i] = b[i] ^ s0[i]; - - return 0; -} - - -static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv) -{ - struct ieee80211_ccmp_data *key = priv; - u8 keyidx, *pos; - struct ieee80211_hdr_4addr *hdr; - u8 pn[6]; - size_t data_len = skb->len - hdr_len - CCMP_HDR_LEN - CCMP_MIC_LEN; - u8 *mic = skb->data + skb->len - CCMP_MIC_LEN; - u8 *b0 = key->rx_b0; - u8 *b = key->rx_b; - u8 *a = key->rx_a; - int i, blocks, last, len; - - if (skb->len < hdr_len + CCMP_HDR_LEN + CCMP_MIC_LEN) { - key->dot11RSNAStatsCCMPFormatErrors++; - return -1; - } - - hdr = (struct ieee80211_hdr_4addr *)skb->data; - pos = skb->data + hdr_len; - keyidx = pos[3]; - if (!(keyidx & (1 << 5))) { - if (net_ratelimit()) { - pr_debug("received packet without ExtIV flag from %pM\n", - hdr->addr2); - } - key->dot11RSNAStatsCCMPFormatErrors++; - return -2; - } - keyidx >>= 6; - if (key->key_idx != keyidx) { - pr_debug("RX tkey->key_idx=%d frame keyidx=%d priv=%p\n", - key->key_idx, keyidx, priv); - return -6; - } - if (!key->key_set) { - if (net_ratelimit()) { - pr_debug("received packet from %pM with keyid=%d that does not have a configured key\n", - hdr->addr2, keyidx); - } - return -3; - } - - pn[0] = pos[7]; - pn[1] = pos[6]; - pn[2] = pos[5]; - pn[3] = pos[4]; - pn[4] = pos[1]; - pn[5] = pos[0]; - pos += 8; - - if (memcmp(pn, key->rx_pn, CCMP_PN_LEN) <= 0) { - if (net_ratelimit()) { - pr_debug("replay detected: STA=%pM previous PN %pm received PN %pm\n", - hdr->addr2, key->rx_pn, pn); - } - key->dot11RSNAStatsCCMPReplays++; - return -4; - } - - ccmp_init_blocks(key->tfm, hdr, pn, data_len, b0, a, b); - xor_block(mic, b, CCMP_MIC_LEN); - - blocks = (data_len + AES_BLOCK_LEN - 1) / AES_BLOCK_LEN; - last = data_len % AES_BLOCK_LEN; - - for (i = 1; i <= blocks; i++) { - len = (i == blocks && last) ? last : AES_BLOCK_LEN; - /* Decrypt, with counter */ - b0[14] = (i >> 8) & 0xff; - b0[15] = i & 0xff; - ieee80211_ccmp_aes_encrypt(key->tfm, b0, b); - xor_block(pos, b, len); - /* Authentication */ - xor_block(a, pos, len); - ieee80211_ccmp_aes_encrypt(key->tfm, a, a); - pos += len; - } - - if (memcmp(mic, a, CCMP_MIC_LEN) != 0) { - if (net_ratelimit()) - pr_debug("decrypt failed: STA=%pM\n", hdr->addr2); - - key->dot11RSNAStatsCCMPDecryptErrors++; - return -5; - } - - memcpy(key->rx_pn, pn, CCMP_PN_LEN); - - /* Remove hdr and MIC */ - memmove(skb->data + CCMP_HDR_LEN, skb->data, hdr_len); - skb_pull(skb, CCMP_HDR_LEN); - skb_trim(skb, skb->len - CCMP_MIC_LEN); - - return keyidx; -} - - -static int ieee80211_ccmp_set_key(void *key, int len, u8 *seq, void *priv) -{ - struct ieee80211_ccmp_data *data = priv; - int keyidx; - struct crypto_tfm *tfm = data->tfm; - - keyidx = data->key_idx; - memset(data, 0, sizeof(*data)); - data->key_idx = keyidx; - data->tfm = tfm; - if (len == CCMP_TK_LEN) { - memcpy(data->key, key, CCMP_TK_LEN); - data->key_set = 1; - if (seq) { - data->rx_pn[0] = seq[5]; - data->rx_pn[1] = seq[4]; - data->rx_pn[2] = seq[3]; - data->rx_pn[3] = seq[2]; - data->rx_pn[4] = seq[1]; - data->rx_pn[5] = seq[0]; - } - crypto_cipher_setkey((void *)data->tfm, data->key, CCMP_TK_LEN); - } else if (len == 0) - data->key_set = 0; - else - return -1; - - return 0; -} - - -static int ieee80211_ccmp_get_key(void *key, int len, u8 *seq, void *priv) -{ - struct ieee80211_ccmp_data *data = priv; - - if (len < CCMP_TK_LEN) - return -1; - - if (!data->key_set) - return 0; - memcpy(key, data->key, CCMP_TK_LEN); - - if (seq) { - seq[0] = data->tx_pn[5]; - seq[1] = data->tx_pn[4]; - seq[2] = data->tx_pn[3]; - seq[3] = data->tx_pn[2]; - seq[4] = data->tx_pn[1]; - seq[5] = data->tx_pn[0]; - } - - return CCMP_TK_LEN; -} - - -static char *ieee80211_ccmp_print_stats(char *p, void *priv) -{ - struct ieee80211_ccmp_data *ccmp = priv; - p += sprintf(p, - "key[%d] alg=CCMP key_set=%d tx_pn=%pm rx_pn=%pm format_errors=%d replays=%d decrypt_errors=%d\n", - ccmp->key_idx, ccmp->key_set, - ccmp->tx_pn, ccmp->rx_pn, - ccmp->dot11RSNAStatsCCMPFormatErrors, - ccmp->dot11RSNAStatsCCMPReplays, - ccmp->dot11RSNAStatsCCMPDecryptErrors); - - return p; -} - -void ieee80211_ccmp_null(void) -{ - return; -} -static struct ieee80211_crypto_ops ieee80211_crypt_ccmp = { - .name = "CCMP", - .init = ieee80211_ccmp_init, - .deinit = ieee80211_ccmp_deinit, - .encrypt_mpdu = ieee80211_ccmp_encrypt, - .decrypt_mpdu = ieee80211_ccmp_decrypt, - .encrypt_msdu = NULL, - .decrypt_msdu = NULL, - .set_key = ieee80211_ccmp_set_key, - .get_key = ieee80211_ccmp_get_key, - .print_stats = ieee80211_ccmp_print_stats, - .extra_prefix_len = CCMP_HDR_LEN, - .extra_postfix_len = CCMP_MIC_LEN, - .owner = THIS_MODULE, -}; - - -int ieee80211_crypto_ccmp_init(void) -{ - return ieee80211_register_crypto_ops(&ieee80211_crypt_ccmp); -} - - -void ieee80211_crypto_ccmp_exit(void) -{ - ieee80211_unregister_crypto_ops(&ieee80211_crypt_ccmp); -} diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_tkip.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_tkip.c deleted file mode 100644 index 6c1acc5dfba..00000000000 --- a/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_tkip.c +++ /dev/null @@ -1,740 +0,0 @@ -/* - * Host AP crypt: host-based TKIP encryption implementation for Host AP driver - * - * Copyright (c) 2003-2004, Jouni Malinen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. See README and COPYING for - * more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ieee80211.h" - -#include -#include -#include - -MODULE_AUTHOR("Jouni Malinen"); -MODULE_DESCRIPTION("Host AP crypt: TKIP"); -MODULE_LICENSE("GPL"); - - -struct ieee80211_tkip_data { -#define TKIP_KEY_LEN 32 - u8 key[TKIP_KEY_LEN]; - int key_set; - - u32 tx_iv32; - u16 tx_iv16; - u16 tx_ttak[5]; - int tx_phase1_done; - - u32 rx_iv32; - u16 rx_iv16; - u16 rx_ttak[5]; - int rx_phase1_done; - u32 rx_iv32_new; - u16 rx_iv16_new; - - u32 dot11RSNAStatsTKIPReplays; - u32 dot11RSNAStatsTKIPICVErrors; - u32 dot11RSNAStatsTKIPLocalMICFailures; - - int key_idx; - - struct crypto_blkcipher *rx_tfm_arc4; - struct crypto_hash *rx_tfm_michael; - struct crypto_blkcipher *tx_tfm_arc4; - struct crypto_hash *tx_tfm_michael; - struct crypto_tfm *tfm_arc4; - struct crypto_tfm *tfm_michael; - - /* scratch buffers for virt_to_page() (crypto API) */ - u8 rx_hdr[16], tx_hdr[16]; -}; - -static void *ieee80211_tkip_init(int key_idx) -{ - struct ieee80211_tkip_data *priv; - - priv = kzalloc(sizeof(*priv), GFP_ATOMIC); - if (priv == NULL) - goto fail; - priv->key_idx = key_idx; - - priv->tx_tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0, - CRYPTO_ALG_ASYNC); - if (IS_ERR(priv->tx_tfm_arc4)) { - printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate " - "crypto API arc4\n"); - priv->tx_tfm_arc4 = NULL; - goto fail; - } - - priv->tx_tfm_michael = crypto_alloc_hash("michael_mic", 0, - CRYPTO_ALG_ASYNC); - if (IS_ERR(priv->tx_tfm_michael)) { - printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate " - "crypto API michael_mic\n"); - priv->tx_tfm_michael = NULL; - goto fail; - } - - priv->rx_tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0, - CRYPTO_ALG_ASYNC); - if (IS_ERR(priv->rx_tfm_arc4)) { - printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate " - "crypto API arc4\n"); - priv->rx_tfm_arc4 = NULL; - goto fail; - } - - priv->rx_tfm_michael = crypto_alloc_hash("michael_mic", 0, - CRYPTO_ALG_ASYNC); - if (IS_ERR(priv->rx_tfm_michael)) { - printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate " - "crypto API michael_mic\n"); - priv->rx_tfm_michael = NULL; - goto fail; - } - - return priv; - -fail: - if (priv) { - if (priv->tx_tfm_michael) - crypto_free_hash(priv->tx_tfm_michael); - if (priv->tx_tfm_arc4) - crypto_free_blkcipher(priv->tx_tfm_arc4); - if (priv->rx_tfm_michael) - crypto_free_hash(priv->rx_tfm_michael); - if (priv->rx_tfm_arc4) - crypto_free_blkcipher(priv->rx_tfm_arc4); - kfree(priv); - } - - return NULL; -} - - -static void ieee80211_tkip_deinit(void *priv) -{ - struct ieee80211_tkip_data *_priv = priv; - - if (_priv) { - if (_priv->tx_tfm_michael) - crypto_free_hash(_priv->tx_tfm_michael); - if (_priv->tx_tfm_arc4) - crypto_free_blkcipher(_priv->tx_tfm_arc4); - if (_priv->rx_tfm_michael) - crypto_free_hash(_priv->rx_tfm_michael); - if (_priv->rx_tfm_arc4) - crypto_free_blkcipher(_priv->rx_tfm_arc4); - } - kfree(priv); -} - - -static inline u16 RotR1(u16 val) -{ - return (val >> 1) | (val << 15); -} - - -static inline u8 Lo8(u16 val) -{ - return val & 0xff; -} - - -static inline u8 Hi8(u16 val) -{ - return val >> 8; -} - - -static inline u16 Lo16(u32 val) -{ - return val & 0xffff; -} - - -static inline u16 Hi16(u32 val) -{ - return val >> 16; -} - - -static inline u16 Mk16(u8 hi, u8 lo) -{ - return lo | (((u16) hi) << 8); -} - - -static inline u16 Mk16_le(u16 *v) -{ - return le16_to_cpu(*v); -} - - -static const u16 Sbox[256] = { - 0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154, - 0x6050, 0x0203, 0xCEA9, 0x567D, 0xE719, 0xB562, 0x4DE6, 0xEC9A, - 0x8F45, 0x1F9D, 0x8940, 0xFA87, 0xEF15, 0xB2EB, 0x8EC9, 0xFB0B, - 0x41EC, 0xB367, 0x5FFD, 0x45EA, 0x23BF, 0x53F7, 0xE496, 0x9B5B, - 0x75C2, 0xE11C, 0x3DAE, 0x4C6A, 0x6C5A, 0x7E41, 0xF502, 0x834F, - 0x685C, 0x51F4, 0xD134, 0xF908, 0xE293, 0xAB73, 0x6253, 0x2A3F, - 0x080C, 0x9552, 0x4665, 0x9D5E, 0x3028, 0x37A1, 0x0A0F, 0x2FB5, - 0x0E09, 0x2436, 0x1B9B, 0xDF3D, 0xCD26, 0x4E69, 0x7FCD, 0xEA9F, - 0x121B, 0x1D9E, 0x5874, 0x342E, 0x362D, 0xDCB2, 0xB4EE, 0x5BFB, - 0xA4F6, 0x764D, 0xB761, 0x7DCE, 0x527B, 0xDD3E, 0x5E71, 0x1397, - 0xA6F5, 0xB968, 0x0000, 0xC12C, 0x4060, 0xE31F, 0x79C8, 0xB6ED, - 0xD4BE, 0x8D46, 0x67D9, 0x724B, 0x94DE, 0x98D4, 0xB0E8, 0x854A, - 0xBB6B, 0xC52A, 0x4FE5, 0xED16, 0x86C5, 0x9AD7, 0x6655, 0x1194, - 0x8ACF, 0xE910, 0x0406, 0xFE81, 0xA0F0, 0x7844, 0x25BA, 0x4BE3, - 0xA2F3, 0x5DFE, 0x80C0, 0x058A, 0x3FAD, 0x21BC, 0x7048, 0xF104, - 0x63DF, 0x77C1, 0xAF75, 0x4263, 0x2030, 0xE51A, 0xFD0E, 0xBF6D, - 0x814C, 0x1814, 0x2635, 0xC32F, 0xBEE1, 0x35A2, 0x88CC, 0x2E39, - 0x9357, 0x55F2, 0xFC82, 0x7A47, 0xC8AC, 0xBAE7, 0x322B, 0xE695, - 0xC0A0, 0x1998, 0x9ED1, 0xA37F, 0x4466, 0x547E, 0x3BAB, 0x0B83, - 0x8CCA, 0xC729, 0x6BD3, 0x283C, 0xA779, 0xBCE2, 0x161D, 0xAD76, - 0xDB3B, 0x6456, 0x744E, 0x141E, 0x92DB, 0x0C0A, 0x486C, 0xB8E4, - 0x9F5D, 0xBD6E, 0x43EF, 0xC4A6, 0x39A8, 0x31A4, 0xD337, 0xF28B, - 0xD532, 0x8B43, 0x6E59, 0xDAB7, 0x018C, 0xB164, 0x9CD2, 0x49E0, - 0xD8B4, 0xACFA, 0xF307, 0xCF25, 0xCAAF, 0xF48E, 0x47E9, 0x1018, - 0x6FD5, 0xF088, 0x4A6F, 0x5C72, 0x3824, 0x57F1, 0x73C7, 0x9751, - 0xCB23, 0xA17C, 0xE89C, 0x3E21, 0x96DD, 0x61DC, 0x0D86, 0x0F85, - 0xE090, 0x7C42, 0x71C4, 0xCCAA, 0x90D8, 0x0605, 0xF701, 0x1C12, - 0xC2A3, 0x6A5F, 0xAEF9, 0x69D0, 0x1791, 0x9958, 0x3A27, 0x27B9, - 0xD938, 0xEB13, 0x2BB3, 0x2233, 0xD2BB, 0xA970, 0x0789, 0x33A7, - 0x2DB6, 0x3C22, 0x1592, 0xC920, 0x8749, 0xAAFF, 0x5078, 0xA57A, - 0x038F, 0x59F8, 0x0980, 0x1A17, 0x65DA, 0xD731, 0x84C6, 0xD0B8, - 0x82C3, 0x29B0, 0x5A77, 0x1E11, 0x7BCB, 0xA8FC, 0x6DD6, 0x2C3A, -}; - - -static inline u16 _S_(u16 v) -{ - u16 t = Sbox[Hi8(v)]; - return Sbox[Lo8(v)] ^ ((t << 8) | (t >> 8)); -} - -#define PHASE1_LOOP_COUNT 8 - -static void tkip_mixing_phase1(u16 *TTAK, const u8 *TK, const u8 *TA, u32 IV32) -{ - int i, j; - - /* Initialize the 80-bit TTAK from TSC (IV32) and TA[0..5] */ - TTAK[0] = Lo16(IV32); - TTAK[1] = Hi16(IV32); - TTAK[2] = Mk16(TA[1], TA[0]); - TTAK[3] = Mk16(TA[3], TA[2]); - TTAK[4] = Mk16(TA[5], TA[4]); - - for (i = 0; i < PHASE1_LOOP_COUNT; i++) { - j = 2 * (i & 1); - TTAK[0] += _S_(TTAK[4] ^ Mk16(TK[1 + j], TK[0 + j])); - TTAK[1] += _S_(TTAK[0] ^ Mk16(TK[5 + j], TK[4 + j])); - TTAK[2] += _S_(TTAK[1] ^ Mk16(TK[9 + j], TK[8 + j])); - TTAK[3] += _S_(TTAK[2] ^ Mk16(TK[13 + j], TK[12 + j])); - TTAK[4] += _S_(TTAK[3] ^ Mk16(TK[1 + j], TK[0 + j])) + i; - } -} - - -static void tkip_mixing_phase2(u8 *WEPSeed, const u8 *TK, const u16 *TTAK, - u16 IV16) -{ - /* Make temporary area overlap WEP seed so that the final copy can be - * avoided on little endian hosts. */ - u16 *PPK = (u16 *) &WEPSeed[4]; - - /* Step 1 - make copy of TTAK and bring in TSC */ - PPK[0] = TTAK[0]; - PPK[1] = TTAK[1]; - PPK[2] = TTAK[2]; - PPK[3] = TTAK[3]; - PPK[4] = TTAK[4]; - PPK[5] = TTAK[4] + IV16; - - /* Step 2 - 96-bit bijective mixing using S-box */ - PPK[0] += _S_(PPK[5] ^ Mk16_le((u16 *) &TK[0])); - PPK[1] += _S_(PPK[0] ^ Mk16_le((u16 *) &TK[2])); - PPK[2] += _S_(PPK[1] ^ Mk16_le((u16 *) &TK[4])); - PPK[3] += _S_(PPK[2] ^ Mk16_le((u16 *) &TK[6])); - PPK[4] += _S_(PPK[3] ^ Mk16_le((u16 *) &TK[8])); - PPK[5] += _S_(PPK[4] ^ Mk16_le((u16 *) &TK[10])); - - PPK[0] += RotR1(PPK[5] ^ Mk16_le((u16 *) &TK[12])); - PPK[1] += RotR1(PPK[0] ^ Mk16_le((u16 *) &TK[14])); - PPK[2] += RotR1(PPK[1]); - PPK[3] += RotR1(PPK[2]); - PPK[4] += RotR1(PPK[3]); - PPK[5] += RotR1(PPK[4]); - - /* Step 3 - bring in last of TK bits, assign 24-bit WEP IV value - * WEPSeed[0..2] is transmitted as WEP IV */ - WEPSeed[0] = Hi8(IV16); - WEPSeed[1] = (Hi8(IV16) | 0x20) & 0x7F; - WEPSeed[2] = Lo8(IV16); - WEPSeed[3] = Lo8((PPK[5] ^ Mk16_le((u16 *) &TK[0])) >> 1); - -#ifdef __BIG_ENDIAN - { - int i; - for (i = 0; i < 6; i++) - PPK[i] = (PPK[i] << 8) | (PPK[i] >> 8); - } -#endif -} - -static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv) -{ - struct ieee80211_tkip_data *tkey = priv; - struct blkcipher_desc desc = {.tfm = tkey->tx_tfm_arc4}; - int len; - u8 *pos; - struct ieee80211_hdr_4addr *hdr; - u8 rc4key[16], *icv; - u32 crc; - struct scatterlist sg; - int ret; - - ret = 0; - if (skb_headroom(skb) < 8 || skb_tailroom(skb) < 4 || - skb->len < hdr_len) - return -1; - - hdr = (struct ieee80211_hdr_4addr *)skb->data; - - if (!tkey->tx_phase1_done) { - tkip_mixing_phase1(tkey->tx_ttak, tkey->key, hdr->addr2, - tkey->tx_iv32); - tkey->tx_phase1_done = 1; - } - tkip_mixing_phase2(rc4key, tkey->key, tkey->tx_ttak, tkey->tx_iv16); - - len = skb->len - hdr_len; - pos = skb_push(skb, 8); - memmove(pos, pos + 8, hdr_len); - pos += hdr_len; - - *pos++ = rc4key[0]; - *pos++ = rc4key[1]; - *pos++ = rc4key[2]; - *pos++ = (tkey->key_idx << 6) | (1 << 5) /* Ext IV included */; - *pos++ = tkey->tx_iv32 & 0xff; - *pos++ = (tkey->tx_iv32 >> 8) & 0xff; - *pos++ = (tkey->tx_iv32 >> 16) & 0xff; - *pos++ = (tkey->tx_iv32 >> 24) & 0xff; - - icv = skb_put(skb, 4); - crc = ~crc32_le(~0, pos, len); - icv[0] = crc; - icv[1] = crc >> 8; - icv[2] = crc >> 16; - icv[3] = crc >> 24; - crypto_blkcipher_setkey(tkey->tx_tfm_arc4, rc4key, 16); - sg_init_one(&sg, pos, len + 4); - ret = crypto_blkcipher_encrypt(&desc, &sg, &sg, len + 4); - - tkey->tx_iv16++; - if (tkey->tx_iv16 == 0) { - tkey->tx_phase1_done = 0; - tkey->tx_iv32++; - } - return ret; -} - -static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv) -{ - struct ieee80211_tkip_data *tkey = priv; - struct blkcipher_desc desc = { .tfm = tkey->rx_tfm_arc4 }; - u8 keyidx, *pos; - u32 iv32; - u16 iv16; - struct ieee80211_hdr_4addr *hdr; - u8 icv[4]; - u32 crc; - struct scatterlist sg; - u8 rc4key[16]; - int plen; - - if (skb->len < hdr_len + 8 + 4) - return -1; - - hdr = (struct ieee80211_hdr_4addr *)skb->data; - pos = skb->data + hdr_len; - keyidx = pos[3]; - if (!(keyidx & (1 << 5))) { - if (net_ratelimit()) { - printk(KERN_DEBUG "TKIP: received packet without ExtIV" - " flag from %pM\n", hdr->addr2); - } - return -2; - } - keyidx >>= 6; - if (tkey->key_idx != keyidx) { - printk(KERN_DEBUG "TKIP: RX tkey->key_idx=%d frame " - "keyidx=%d priv=%p\n", tkey->key_idx, keyidx, priv); - return -6; - } - if (!tkey->key_set) { - if (net_ratelimit()) { - printk(KERN_DEBUG "TKIP: received packet from %pM" - " with keyid=%d that does not have a configured" - " key\n", hdr->addr2, keyidx); - } - return -3; - } - iv16 = (pos[0] << 8) | pos[2]; - iv32 = pos[4] | (pos[5] << 8) | (pos[6] << 16) | (pos[7] << 24); - pos += 8; - - if (iv32 < tkey->rx_iv32 || - (iv32 == tkey->rx_iv32 && iv16 <= tkey->rx_iv16)) { - if (net_ratelimit()) { - printk(KERN_DEBUG "TKIP: replay detected: STA=%pM" - " previous TSC %08x%04x received TSC " - "%08x%04x\n", hdr->addr2, - tkey->rx_iv32, tkey->rx_iv16, iv32, iv16); - } - tkey->dot11RSNAStatsTKIPReplays++; - return -4; - } - - if (iv32 != tkey->rx_iv32 || !tkey->rx_phase1_done) { - tkip_mixing_phase1(tkey->rx_ttak, tkey->key, hdr->addr2, iv32); - tkey->rx_phase1_done = 1; - } - tkip_mixing_phase2(rc4key, tkey->key, tkey->rx_ttak, iv16); - - plen = skb->len - hdr_len - 12; - crypto_blkcipher_setkey(tkey->rx_tfm_arc4, rc4key, 16); - sg_init_one(&sg, pos, plen + 4); - if (crypto_blkcipher_decrypt(&desc, &sg, &sg, plen + 4)) { - if (net_ratelimit()) { - printk(KERN_DEBUG ": TKIP: failed to decrypt " - "received packet from %pM\n", - hdr->addr2); - } - return -7; - } - - crc = ~crc32_le(~0, pos, plen); - icv[0] = crc; - icv[1] = crc >> 8; - icv[2] = crc >> 16; - icv[3] = crc >> 24; - if (memcmp(icv, pos + plen, 4) != 0) { - if (iv32 != tkey->rx_iv32) { - /* Previously cached Phase1 result was already lost, so - * it needs to be recalculated for the next packet. */ - tkey->rx_phase1_done = 0; - } - if (net_ratelimit()) { - printk(KERN_DEBUG "TKIP: ICV error detected: STA=" - "%pM\n", hdr->addr2); - } - tkey->dot11RSNAStatsTKIPICVErrors++; - return -5; - } - - /* Update real counters only after Michael MIC verification has - * completed */ - tkey->rx_iv32_new = iv32; - tkey->rx_iv16_new = iv16; - - /* Remove IV and ICV */ - memmove(skb->data + 8, skb->data, hdr_len); - skb_pull(skb, 8); - skb_trim(skb, skb->len - 4); - - return keyidx; -} - -static int michael_mic(struct crypto_hash *tfm_michael, u8 *key, u8 *hdr, - u8 *data, size_t data_len, u8 *mic) -{ - struct hash_desc desc; - struct scatterlist sg[2]; - - if (tfm_michael == NULL) { - printk(KERN_WARNING "michael_mic: tfm_michael == NULL\n"); - return -1; - } - - sg_init_table(sg, 2); - sg_set_buf(&sg[0], hdr, 16); - sg_set_buf(&sg[1], data, data_len); - - if (crypto_hash_setkey(tfm_michael, key, 8)) - return -1; - - desc.tfm = tfm_michael; - desc.flags = 0; - return crypto_hash_digest(&desc, sg, data_len + 16, mic); -} - -static void michael_mic_hdr(struct sk_buff *skb, u8 *hdr) -{ - struct ieee80211_hdr_4addr *hdr11; - - hdr11 = (struct ieee80211_hdr_4addr *)skb->data; - switch (le16_to_cpu(hdr11->frame_ctl) & - (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) { - case IEEE80211_FCTL_TODS: - memcpy(hdr, hdr11->addr3, ETH_ALEN); /* DA */ - memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */ - break; - case IEEE80211_FCTL_FROMDS: - memcpy(hdr, hdr11->addr1, ETH_ALEN); /* DA */ - memcpy(hdr + ETH_ALEN, hdr11->addr3, ETH_ALEN); /* SA */ - break; - case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS: - memcpy(hdr, hdr11->addr3, ETH_ALEN); /* DA */ - memcpy(hdr + ETH_ALEN, hdr11->addr4, ETH_ALEN); /* SA */ - break; - case 0: - memcpy(hdr, hdr11->addr1, ETH_ALEN); /* DA */ - memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */ - break; - } - - hdr[12] = 0; /* priority */ - - hdr[13] = hdr[14] = hdr[15] = 0; /* reserved */ -} - - -static int ieee80211_michael_mic_add(struct sk_buff *skb, int hdr_len, - void *priv) -{ - struct ieee80211_tkip_data *tkey = priv; - u8 *pos; - struct ieee80211_hdr_4addr *hdr; - - hdr = (struct ieee80211_hdr_4addr *)skb->data; - - if (skb_tailroom(skb) < 8 || skb->len < hdr_len) { - printk(KERN_DEBUG "Invalid packet for Michael MIC add " - "(tailroom=%d hdr_len=%d skb->len=%d)\n", - skb_tailroom(skb), hdr_len, skb->len); - return -1; - } - - michael_mic_hdr(skb, tkey->tx_hdr); - - if (IEEE80211_QOS_HAS_SEQ(le16_to_cpu(hdr->frame_ctl))) - tkey->tx_hdr[12] = *(skb->data + hdr_len - 2) & 0x07; - - pos = skb_put(skb, 8); - - if (michael_mic(tkey->tx_tfm_michael, &tkey->key[16], tkey->tx_hdr, - skb->data + hdr_len, skb->len - 8 - hdr_len, pos)) - return -1; - - return 0; -} - -static void ieee80211_michael_mic_failure(struct net_device *dev, - struct ieee80211_hdr_4addr *hdr, - int keyidx) -{ - union iwreq_data wrqu; - struct iw_michaelmicfailure ev; - - /* TODO: needed parameters: count, keyid, key type, TSC */ - memset(&ev, 0, sizeof(ev)); - ev.flags = keyidx & IW_MICFAILURE_KEY_ID; - if (hdr->addr1[0] & 0x01) - ev.flags |= IW_MICFAILURE_GROUP; - else - ev.flags |= IW_MICFAILURE_PAIRWISE; - ev.src_addr.sa_family = ARPHRD_ETHER; - memcpy(ev.src_addr.sa_data, hdr->addr2, ETH_ALEN); - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.length = sizeof(ev); - wireless_send_event(dev, IWEVMICHAELMICFAILURE, &wrqu, (char *) &ev); -} - -static int ieee80211_michael_mic_verify(struct sk_buff *skb, int keyidx, - int hdr_len, void *priv) -{ - struct ieee80211_tkip_data *tkey = priv; - u8 mic[8]; - struct ieee80211_hdr_4addr *hdr; - - hdr = (struct ieee80211_hdr_4addr *)skb->data; - - if (!tkey->key_set) - return -1; - - michael_mic_hdr(skb, tkey->rx_hdr); - if (IEEE80211_QOS_HAS_SEQ(le16_to_cpu(hdr->frame_ctl))) - tkey->rx_hdr[12] = *(skb->data + hdr_len - 2) & 0x07; - - if (michael_mic(tkey->rx_tfm_michael, &tkey->key[24], tkey->rx_hdr, - skb->data + hdr_len, skb->len - 8 - hdr_len, mic)) - return -1; - - if (memcmp(mic, skb->data + skb->len - 8, 8) != 0) { - struct ieee80211_hdr_4addr *hdr; - hdr = (struct ieee80211_hdr_4addr *)skb->data; - printk(KERN_DEBUG "%s: Michael MIC verification failed for " - "MSDU from %pM keyidx=%d\n", - skb->dev ? skb->dev->name : "N/A", hdr->addr2, - keyidx); - if (skb->dev) - ieee80211_michael_mic_failure(skb->dev, hdr, keyidx); - tkey->dot11RSNAStatsTKIPLocalMICFailures++; - return -1; - } - - /* Update TSC counters for RX now that the packet verification has - * completed. */ - tkey->rx_iv32 = tkey->rx_iv32_new; - tkey->rx_iv16 = tkey->rx_iv16_new; - - skb_trim(skb, skb->len - 8); - - return 0; -} - - -static int ieee80211_tkip_set_key(void *key, int len, u8 *seq, void *priv) -{ - struct ieee80211_tkip_data *tkey = priv; - int keyidx; - struct crypto_hash *tfm = tkey->tx_tfm_michael; - struct crypto_blkcipher *tfm2 = tkey->tx_tfm_arc4; - struct crypto_hash *tfm3 = tkey->rx_tfm_michael; - struct crypto_blkcipher *tfm4 = tkey->rx_tfm_arc4; - - keyidx = tkey->key_idx; - memset(tkey, 0, sizeof(*tkey)); - tkey->key_idx = keyidx; - - tkey->tx_tfm_michael = tfm; - tkey->tx_tfm_arc4 = tfm2; - tkey->rx_tfm_michael = tfm3; - tkey->rx_tfm_arc4 = tfm4; - - if (len == TKIP_KEY_LEN) { - memcpy(tkey->key, key, TKIP_KEY_LEN); - tkey->key_set = 1; - tkey->tx_iv16 = 1; /* TSC is initialized to 1 */ - if (seq) { - tkey->rx_iv32 = (seq[5] << 24) | (seq[4] << 16) | - (seq[3] << 8) | seq[2]; - tkey->rx_iv16 = (seq[1] << 8) | seq[0]; - } - } else if (len == 0) - tkey->key_set = 0; - else - return -1; - - return 0; -} - - -static int ieee80211_tkip_get_key(void *key, int len, u8 *seq, void *priv) -{ - struct ieee80211_tkip_data *tkey = priv; - - if (len < TKIP_KEY_LEN) - return -1; - - if (!tkey->key_set) - return 0; - memcpy(key, tkey->key, TKIP_KEY_LEN); - - if (seq) { - /* Return the sequence number of the last transmitted frame. */ - u16 iv16 = tkey->tx_iv16; - u32 iv32 = tkey->tx_iv32; - if (iv16 == 0) - iv32--; - iv16--; - seq[0] = tkey->tx_iv16; - seq[1] = tkey->tx_iv16 >> 8; - seq[2] = tkey->tx_iv32; - seq[3] = tkey->tx_iv32 >> 8; - seq[4] = tkey->tx_iv32 >> 16; - seq[5] = tkey->tx_iv32 >> 24; - } - - return TKIP_KEY_LEN; -} - - -static char *ieee80211_tkip_print_stats(char *p, void *priv) -{ - struct ieee80211_tkip_data *tkip = priv; - p += sprintf(p, "key[%d] alg=TKIP key_set=%d " - "tx_pn=%02x%02x%02x%02x%02x%02x " - "rx_pn=%02x%02x%02x%02x%02x%02x " - "replays=%d icv_errors=%d local_mic_failures=%d\n", - tkip->key_idx, tkip->key_set, - (tkip->tx_iv32 >> 24) & 0xff, - (tkip->tx_iv32 >> 16) & 0xff, - (tkip->tx_iv32 >> 8) & 0xff, - tkip->tx_iv32 & 0xff, - (tkip->tx_iv16 >> 8) & 0xff, - tkip->tx_iv16 & 0xff, - (tkip->rx_iv32 >> 24) & 0xff, - (tkip->rx_iv32 >> 16) & 0xff, - (tkip->rx_iv32 >> 8) & 0xff, - tkip->rx_iv32 & 0xff, - (tkip->rx_iv16 >> 8) & 0xff, - tkip->rx_iv16 & 0xff, - tkip->dot11RSNAStatsTKIPReplays, - tkip->dot11RSNAStatsTKIPICVErrors, - tkip->dot11RSNAStatsTKIPLocalMICFailures); - return p; -} - - -static struct ieee80211_crypto_ops ieee80211_crypt_tkip = { - .name = "TKIP", - .init = ieee80211_tkip_init, - .deinit = ieee80211_tkip_deinit, - .encrypt_mpdu = ieee80211_tkip_encrypt, - .decrypt_mpdu = ieee80211_tkip_decrypt, - .encrypt_msdu = ieee80211_michael_mic_add, - .decrypt_msdu = ieee80211_michael_mic_verify, - .set_key = ieee80211_tkip_set_key, - .get_key = ieee80211_tkip_get_key, - .print_stats = ieee80211_tkip_print_stats, - .extra_prefix_len = 4 + 4, /* IV + ExtIV */ - .extra_postfix_len = 8 + 4, /* MIC + ICV */ - .owner = THIS_MODULE, -}; - - -int ieee80211_crypto_tkip_init(void) -{ - return ieee80211_register_crypto_ops(&ieee80211_crypt_tkip); -} - - -void ieee80211_crypto_tkip_exit(void) -{ - ieee80211_unregister_crypto_ops(&ieee80211_crypt_tkip); -} - - -void ieee80211_tkip_null(void) -{ -} diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_wep.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_wep.c deleted file mode 100644 index f2536722494..00000000000 --- a/drivers/staging/rtl8187se/ieee80211/ieee80211_crypt_wep.c +++ /dev/null @@ -1,277 +0,0 @@ -/* - * Host AP crypt: host-based WEP encryption implementation for Host AP driver - * - * Copyright (c) 2002-2004, Jouni Malinen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. See README and COPYING for - * more details. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include - -#include "ieee80211.h" - -#include -#include -#include - -MODULE_AUTHOR("Jouni Malinen"); -MODULE_DESCRIPTION("Host AP crypt: WEP"); -MODULE_LICENSE("GPL"); - -struct prism2_wep_data { - u32 iv; -#define WEP_KEY_LEN 13 - u8 key[WEP_KEY_LEN + 1]; - u8 key_len; - u8 key_idx; - struct crypto_blkcipher *tx_tfm; - struct crypto_blkcipher *rx_tfm; -}; - -static void *prism2_wep_init(int keyidx) -{ - struct prism2_wep_data *priv; - - priv = kzalloc(sizeof(*priv), GFP_ATOMIC); - if (priv == NULL) - goto fail; - priv->key_idx = keyidx; - priv->tx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC); - if (IS_ERR(priv->tx_tfm)) { - pr_debug("could not allocate crypto API arc4\n"); - priv->tx_tfm = NULL; - goto fail; - } - priv->rx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC); - if (IS_ERR(priv->rx_tfm)) { - pr_debug("could not allocate crypto API arc4\n"); - priv->rx_tfm = NULL; - goto fail; - } - - /* start WEP IV from a random value */ - get_random_bytes(&priv->iv, 4); - - return priv; - -fail: - if (priv) { - if (priv->tx_tfm) - crypto_free_blkcipher(priv->tx_tfm); - if (priv->rx_tfm) - crypto_free_blkcipher(priv->rx_tfm); - kfree(priv); - } - - return NULL; -} - -static void prism2_wep_deinit(void *priv) -{ - struct prism2_wep_data *_priv = priv; - - if (_priv) { - if (_priv->tx_tfm) - crypto_free_blkcipher(_priv->tx_tfm); - if (_priv->rx_tfm) - crypto_free_blkcipher(_priv->rx_tfm); - } - - kfree(priv); -} - -/* Perform WEP encryption on given skb that has at least 4 bytes of headroom - * for IV and 4 bytes of tailroom for ICV. Both IV and ICV will be transmitted, - * so the payload length increases with 8 bytes. - * - * WEP frame payload: IV + TX key idx, RC4(data), ICV = RC4(CRC32(data)) - */ -static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv) -{ - struct prism2_wep_data *wep = priv; - struct blkcipher_desc desc = { .tfm = wep->tx_tfm }; - u32 klen, len; - u8 key[WEP_KEY_LEN + 3]; - u8 *pos; - u32 crc; - u8 *icv; - struct scatterlist sg; - - if (skb_headroom(skb) < 4 || skb_tailroom(skb) < 4 || - skb->len < hdr_len) - return -1; - - len = skb->len - hdr_len; - pos = skb_push(skb, 4); - memmove(pos, pos + 4, hdr_len); - pos += hdr_len; - - klen = 3 + wep->key_len; - - wep->iv++; - - /* Fluhrer, Mantin, and Shamir have reported weaknesses in the key - * scheduling algorithm of RC4. At least IVs (KeyByte + 3, 0xff, N) - * can be used to speedup attacks, so avoid using them. */ - if ((wep->iv & 0xff00) == 0xff00) { - u8 B = (wep->iv >> 16) & 0xff; - if (B >= 3 && B < klen) - wep->iv += 0x0100; - } - - /* Prepend 24-bit IV to RC4 key and TX frame */ - *pos++ = key[0] = (wep->iv >> 16) & 0xff; - *pos++ = key[1] = (wep->iv >> 8) & 0xff; - *pos++ = key[2] = wep->iv & 0xff; - *pos++ = wep->key_idx << 6; - - /* Copy rest of the WEP key (the secret part) */ - memcpy(key + 3, wep->key, wep->key_len); - - /* Append little-endian CRC32 and encrypt it to produce ICV */ - crc = ~crc32_le(~0, pos, len); - icv = skb_put(skb, 4); - icv[0] = crc; - icv[1] = crc >> 8; - icv[2] = crc >> 16; - icv[3] = crc >> 24; - - crypto_blkcipher_setkey(wep->tx_tfm, key, klen); - sg_init_one(&sg, pos, len + 4); - - return crypto_blkcipher_encrypt(&desc, &sg, &sg, len + 4); -} - -/* Perform WEP decryption on given buffer. Buffer includes whole WEP part of - * the frame: IV (4 bytes), encrypted payload (including SNAP header), - * ICV (4 bytes). len includes both IV and ICV. - * - * Returns 0 if frame was decrypted successfully and ICV was correct and -1 on - * failure. If frame is OK, IV and ICV will be removed. - */ -static int prism2_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv) -{ - struct prism2_wep_data *wep = priv; - struct blkcipher_desc desc = { .tfm = wep->rx_tfm }; - u32 klen, plen; - u8 key[WEP_KEY_LEN + 3]; - u8 keyidx, *pos; - u32 crc; - u8 icv[4]; - struct scatterlist sg; - - if (skb->len < hdr_len + 8) - return -1; - - pos = skb->data + hdr_len; - key[0] = *pos++; - key[1] = *pos++; - key[2] = *pos++; - keyidx = *pos++ >> 6; - if (keyidx != wep->key_idx) - return -1; - - klen = 3 + wep->key_len; - - /* Copy rest of the WEP key (the secret part) */ - memcpy(key + 3, wep->key, wep->key_len); - - /* Apply RC4 to data and compute CRC32 over decrypted data */ - plen = skb->len - hdr_len - 8; - - crypto_blkcipher_setkey(wep->rx_tfm, key, klen); - sg_init_one(&sg, pos, plen + 4); - - if (crypto_blkcipher_decrypt(&desc, &sg, &sg, plen + 4)) - return -7; - - crc = ~crc32_le(~0, pos, plen); - icv[0] = crc; - icv[1] = crc >> 8; - icv[2] = crc >> 16; - icv[3] = crc >> 24; - - if (memcmp(icv, pos + plen, 4) != 0) { - /* ICV mismatch - drop frame */ - return -2; - } - - /* Remove IV and ICV */ - memmove(skb->data + 4, skb->data, hdr_len); - skb_pull(skb, 4); - skb_trim(skb, skb->len - 4); - return 0; -} - -static int prism2_wep_set_key(void *key, int len, u8 *seq, void *priv) -{ - struct prism2_wep_data *wep = priv; - - if (len < 0 || len > WEP_KEY_LEN) - return -1; - - memcpy(wep->key, key, len); - wep->key_len = len; - - return 0; -} - -static int prism2_wep_get_key(void *key, int len, u8 *seq, void *priv) -{ - struct prism2_wep_data *wep = priv; - - if (len < wep->key_len) - return -1; - - memcpy(key, wep->key, wep->key_len); - - return wep->key_len; -} - -static char *prism2_wep_print_stats(char *p, void *priv) -{ - struct prism2_wep_data *wep = priv; - p += sprintf(p, "key[%d] alg=WEP len=%d\n", - wep->key_idx, wep->key_len); - return p; -} - -static struct ieee80211_crypto_ops ieee80211_crypt_wep = { - .name = "WEP", - .init = prism2_wep_init, - .deinit = prism2_wep_deinit, - .encrypt_mpdu = prism2_wep_encrypt, - .decrypt_mpdu = prism2_wep_decrypt, - .encrypt_msdu = NULL, - .decrypt_msdu = NULL, - .set_key = prism2_wep_set_key, - .get_key = prism2_wep_get_key, - .print_stats = prism2_wep_print_stats, - .extra_prefix_len = 4, /* IV */ - .extra_postfix_len = 4, /* ICV */ - .owner = THIS_MODULE, -}; - -int ieee80211_crypto_wep_init(void) -{ - return ieee80211_register_crypto_ops(&ieee80211_crypt_wep); -} - -void ieee80211_crypto_wep_exit(void) -{ - ieee80211_unregister_crypto_ops(&ieee80211_crypt_wep); -} - -void ieee80211_wep_null(void) -{ - return; -} diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_module.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_module.c deleted file mode 100644 index 07a1fbb6678..00000000000 --- a/drivers/staging/rtl8187se/ieee80211/ieee80211_module.c +++ /dev/null @@ -1,203 +0,0 @@ -/******************************************************************************* - - Copyright(c) 2004 Intel Corporation. All rights reserved. - - Portions of this file are based on the WEP enablement code provided by the - Host AP project hostap-drivers v0.1.3 - Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen - - Copyright (c) 2002-2003, Jouni Malinen - - This program is free software; you can redistribute it and/or modify it - under the terms of version 2 of the GNU General Public License as - published by the Free Software Foundation. - - This program is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., 59 - Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - The full GNU General Public License is included in this distribution in the - file called LICENSE. - - Contact Information: - James P. Ketrenos - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ - -#include -//#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ieee80211.h" - -MODULE_DESCRIPTION("802.11 data/management/control stack"); -MODULE_AUTHOR("Copyright (C) 2004 Intel Corporation "); -MODULE_LICENSE("GPL"); - -#define DRV_NAME "ieee80211" - -static inline int ieee80211_networks_allocate(struct ieee80211_device *ieee) -{ - if (ieee->networks) - return 0; - - ieee->networks = kcalloc( - MAX_NETWORK_COUNT, sizeof(struct ieee80211_network), - GFP_KERNEL); - if (!ieee->networks) - return -ENOMEM; - - return 0; -} - -static inline void ieee80211_networks_free(struct ieee80211_device *ieee) -{ - if (!ieee->networks) - return; - kfree(ieee->networks); - ieee->networks = NULL; -} - -static inline void ieee80211_networks_initialize(struct ieee80211_device *ieee) -{ - int i; - - INIT_LIST_HEAD(&ieee->network_free_list); - INIT_LIST_HEAD(&ieee->network_list); - for (i = 0; i < MAX_NETWORK_COUNT; i++) - list_add_tail(&ieee->networks[i].list, &ieee->network_free_list); -} - - -struct net_device *alloc_ieee80211(int sizeof_priv) -{ - struct ieee80211_device *ieee; - struct net_device *dev; - int i, err; - - IEEE80211_DEBUG_INFO("Initializing...\n"); - - dev = alloc_etherdev(sizeof(struct ieee80211_device) + sizeof_priv); - if (!dev) { - IEEE80211_ERROR("Unable to network device.\n"); - goto failed; - } - ieee = netdev_priv(dev); - - ieee->dev = dev; - - err = ieee80211_networks_allocate(ieee); - if (err) { - IEEE80211_ERROR("Unable to allocate beacon storage: %d\n", - err); - goto failed; - } - ieee80211_networks_initialize(ieee); - - /* Default fragmentation threshold is maximum payload size */ - ieee->fts = DEFAULT_FTS; - ieee->scan_age = DEFAULT_MAX_SCAN_AGE; - ieee->open_wep = 1; - - /* Default to enabling full open WEP with host based encrypt/decrypt */ - ieee->host_encrypt = 1; - ieee->host_decrypt = 1; - ieee->ieee802_1x = 1; /* Default to supporting 802.1x */ - - INIT_LIST_HEAD(&ieee->crypt_deinit_list); - init_timer(&ieee->crypt_deinit_timer); - ieee->crypt_deinit_timer.data = (unsigned long)ieee; - ieee->crypt_deinit_timer.function = ieee80211_crypt_deinit_handler; - - spin_lock_init(&ieee->lock); - spin_lock_init(&ieee->wpax_suitlist_lock); - - ieee->wpax_type_set = 0; - ieee->wpa_enabled = 0; - ieee->tkip_countermeasures = 0; - ieee->drop_unencrypted = 0; - ieee->privacy_invoked = 0; - ieee->ieee802_1x = 1; - ieee->raw_tx = 0; - - ieee80211_softmac_init(ieee); - - for (i = 0; i < IEEE_IBSS_MAC_HASH_SIZE; i++) - INIT_LIST_HEAD(&ieee->ibss_mac_hash[i]); - - for (i = 0; i < 17; i++) { - ieee->last_rxseq_num[i] = -1; - ieee->last_rxfrag_num[i] = -1; - ieee->last_packet_time[i] = 0; - } -//These function were added to load crypte module autoly - ieee80211_tkip_null(); - ieee80211_wep_null(); - ieee80211_ccmp_null(); - return dev; - - failed: - if (dev) - free_netdev(dev); - return NULL; -} - - -void free_ieee80211(struct net_device *dev) -{ - struct ieee80211_device *ieee = netdev_priv(dev); - - int i; - struct list_head *p, *q; - - - ieee80211_softmac_free(ieee); - del_timer_sync(&ieee->crypt_deinit_timer); - ieee80211_crypt_deinit_entries(ieee, 1); - - for (i = 0; i < WEP_KEYS; i++) { - struct ieee80211_crypt_data *crypt = ieee->crypt[i]; - if (crypt) { - if (crypt->ops) - crypt->ops->deinit(crypt->priv); - kfree(crypt); - ieee->crypt[i] = NULL; - } - } - - ieee80211_networks_free(ieee); - - for (i = 0; i < IEEE_IBSS_MAC_HASH_SIZE; i++) { - list_for_each_safe(p, q, &ieee->ibss_mac_hash[i]) { - kfree(list_entry(p, struct ieee_ibss_seq, list)); - list_del(p); - } - } - - - free_netdev(dev); -} diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_rx.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_rx.c deleted file mode 100644 index b522b57a269..00000000000 --- a/drivers/staging/rtl8187se/ieee80211/ieee80211_rx.c +++ /dev/null @@ -1,1486 +0,0 @@ -/* - * Original code based Host AP (software wireless LAN access point) driver - * for Intersil Prism2/2.5/3 - hostap.o module, common routines - * - * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen - * - * Copyright (c) 2002-2003, Jouni Malinen - * Copyright (c) 2004, Intel Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. See README and COPYING for - * more details. - ****************************************************************************** - - Few modifications for Realtek's Wi-Fi drivers by - Andrea Merello - - A special thanks goes to Realtek for their support ! - -******************************************************************************/ - - -#include -//#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ieee80211.h" -#include "dot11d.h" -static inline void ieee80211_monitor_rx(struct ieee80211_device *ieee, - struct sk_buff *skb, - struct ieee80211_rx_stats *rx_stats) -{ - struct ieee80211_hdr_4addr *hdr = - (struct ieee80211_hdr_4addr *)skb->data; - u16 fc = le16_to_cpu(hdr->frame_ctl); - - skb->dev = ieee->dev; - skb_reset_mac_header(skb); - skb_pull(skb, ieee80211_get_hdrlen(fc)); - skb->pkt_type = PACKET_OTHERHOST; - skb->protocol = __constant_htons(ETH_P_80211_RAW); - memset(skb->cb, 0, sizeof(skb->cb)); - netif_rx(skb); -} - - -/* Called only as a tasklet (software IRQ) */ -static struct ieee80211_frag_entry * -ieee80211_frag_cache_find(struct ieee80211_device *ieee, unsigned int seq, - unsigned int frag, u8 tid, u8 *src, u8 *dst) -{ - struct ieee80211_frag_entry *entry; - int i; - - for (i = 0; i < IEEE80211_FRAG_CACHE_LEN; i++) { - entry = &ieee->frag_cache[tid][i]; - if (entry->skb != NULL && - time_after(jiffies, entry->first_frag_time + 2 * HZ)) { - IEEE80211_DEBUG_FRAG( - "expiring fragment cache entry " - "seq=%u last_frag=%u\n", - entry->seq, entry->last_frag); - dev_kfree_skb_any(entry->skb); - entry->skb = NULL; - } - - if (entry->skb != NULL && entry->seq == seq && - (entry->last_frag + 1 == frag || frag == -1) && - memcmp(entry->src_addr, src, ETH_ALEN) == 0 && - memcmp(entry->dst_addr, dst, ETH_ALEN) == 0) - return entry; - } - - return NULL; -} - -/* Called only as a tasklet (software IRQ) */ -static struct sk_buff * -ieee80211_frag_cache_get(struct ieee80211_device *ieee, - struct ieee80211_hdr_4addr *hdr) -{ - struct sk_buff *skb = NULL; - u16 fc = le16_to_cpu(hdr->frame_ctl); - u16 sc = le16_to_cpu(hdr->seq_ctl); - unsigned int frag = WLAN_GET_SEQ_FRAG(sc); - unsigned int seq = WLAN_GET_SEQ_SEQ(sc); - struct ieee80211_frag_entry *entry; - struct ieee80211_hdr_3addrqos *hdr_3addrqos; - struct ieee80211_hdr_4addrqos *hdr_4addrqos; - u8 tid; - - if (((fc & IEEE80211_FCTL_DSTODS) == IEEE80211_FCTL_DSTODS) && IEEE80211_QOS_HAS_SEQ(fc)) { - hdr_4addrqos = (struct ieee80211_hdr_4addrqos *)hdr; - tid = le16_to_cpu(hdr_4addrqos->qos_ctl) & IEEE80211_QOS_TID; - tid = UP2AC(tid); - tid++; - } else if (IEEE80211_QOS_HAS_SEQ(fc)) { - hdr_3addrqos = (struct ieee80211_hdr_3addrqos *)hdr; - tid = le16_to_cpu(hdr_3addrqos->qos_ctl) & IEEE80211_QOS_TID; - tid = UP2AC(tid); - tid++; - } else { - tid = 0; - } - - if (frag == 0) { - /* Reserve enough space to fit maximum frame length */ - skb = dev_alloc_skb(ieee->dev->mtu + - sizeof(struct ieee80211_hdr_4addr) + - 8 /* LLC */ + - 2 /* alignment */ + - 8 /* WEP */ + - ETH_ALEN /* WDS */ + - (IEEE80211_QOS_HAS_SEQ(fc) ? 2 : 0) /* QOS Control */); - if (skb == NULL) - return NULL; - - entry = &ieee->frag_cache[tid][ieee->frag_next_idx[tid]]; - ieee->frag_next_idx[tid]++; - if (ieee->frag_next_idx[tid] >= IEEE80211_FRAG_CACHE_LEN) - ieee->frag_next_idx[tid] = 0; - - if (entry->skb != NULL) - dev_kfree_skb_any(entry->skb); - - entry->first_frag_time = jiffies; - entry->seq = seq; - entry->last_frag = frag; - entry->skb = skb; - memcpy(entry->src_addr, hdr->addr2, ETH_ALEN); - memcpy(entry->dst_addr, hdr->addr1, ETH_ALEN); - } else { - /* received a fragment of a frame for which the head fragment - * should have already been received */ - entry = ieee80211_frag_cache_find(ieee, seq, frag, tid, hdr->addr2, - hdr->addr1); - if (entry != NULL) { - entry->last_frag = frag; - skb = entry->skb; - } - } - - return skb; -} - - -/* Called only as a tasklet (software IRQ) */ -static int ieee80211_frag_cache_invalidate(struct ieee80211_device *ieee, - struct ieee80211_hdr_4addr *hdr) -{ - u16 fc = le16_to_cpu(hdr->frame_ctl); - u16 sc = le16_to_cpu(hdr->seq_ctl); - unsigned int seq = WLAN_GET_SEQ_SEQ(sc); - struct ieee80211_frag_entry *entry; - struct ieee80211_hdr_3addrqos *hdr_3addrqos; - struct ieee80211_hdr_4addrqos *hdr_4addrqos; - u8 tid; - - if (((fc & IEEE80211_FCTL_DSTODS) == IEEE80211_FCTL_DSTODS) && IEEE80211_QOS_HAS_SEQ(fc)) { - hdr_4addrqos = (struct ieee80211_hdr_4addrqos *)hdr; - tid = le16_to_cpu(hdr_4addrqos->qos_ctl) & IEEE80211_QOS_TID; - tid = UP2AC(tid); - tid++; - } else if (IEEE80211_QOS_HAS_SEQ(fc)) { - hdr_3addrqos = (struct ieee80211_hdr_3addrqos *)hdr; - tid = le16_to_cpu(hdr_3addrqos->qos_ctl) & IEEE80211_QOS_TID; - tid = UP2AC(tid); - tid++; - } else { - tid = 0; - } - - entry = ieee80211_frag_cache_find(ieee, seq, -1, tid, hdr->addr2, - hdr->addr1); - - if (entry == NULL) { - IEEE80211_DEBUG_FRAG( - "could not invalidate fragment cache " - "entry (seq=%u)\n", seq); - return -1; - } - - entry->skb = NULL; - return 0; -} - - - -/* ieee80211_rx_frame_mgtmt - * - * Responsible for handling management control frames - * - * Called by ieee80211_rx */ -static inline int -ieee80211_rx_frame_mgmt(struct ieee80211_device *ieee, struct sk_buff *skb, - struct ieee80211_rx_stats *rx_stats, u16 type, - u16 stype) -{ - struct ieee80211_hdr_4addr *hdr; - - // cheat the the hdr type - hdr = (struct ieee80211_hdr_4addr *)skb->data; - - /* On the struct stats definition there is written that - * this is not mandatory.... but seems that the probe - * response parser uses it - */ - rx_stats->len = skb->len; - ieee80211_rx_mgt(ieee, (struct ieee80211_hdr_4addr *)skb->data, - rx_stats); - - if ((ieee->state == IEEE80211_LINKED) && (memcmp(hdr->addr3, ieee->current_network.bssid, ETH_ALEN))) { - dev_kfree_skb_any(skb); - return 0; - } - - ieee80211_rx_frame_softmac(ieee, skb, rx_stats, type, stype); - - dev_kfree_skb_any(skb); - - return 0; - -} - - - -/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */ -/* Ethernet-II snap header (RFC1042 for most EtherTypes) */ -static unsigned char rfc1042_header[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; -/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */ -static unsigned char bridge_tunnel_header[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; -/* No encapsulation header if EtherType < 0x600 (=length) */ - -/* Called by ieee80211_rx_frame_decrypt */ -static int ieee80211_is_eapol_frame(struct ieee80211_device *ieee, - struct sk_buff *skb, size_t hdrlen) -{ - struct net_device *dev = ieee->dev; - u16 fc, ethertype; - struct ieee80211_hdr_4addr *hdr; - u8 *pos; - - if (skb->len < 24) - return 0; - - hdr = (struct ieee80211_hdr_4addr *)skb->data; - fc = le16_to_cpu(hdr->frame_ctl); - - /* check that the frame is unicast frame to us */ - if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == - IEEE80211_FCTL_TODS && - memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN) == 0 && - memcmp(hdr->addr3, dev->dev_addr, ETH_ALEN) == 0) { - /* ToDS frame with own addr BSSID and DA */ - } else if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == - IEEE80211_FCTL_FROMDS && - memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN) == 0) { - /* FromDS frame with own addr as DA */ - } else - return 0; - - if (skb->len < 24 + 8) - return 0; - - /* check for port access entity Ethernet type */ -// pos = skb->data + 24; - pos = skb->data + hdrlen; - ethertype = (pos[6] << 8) | pos[7]; - if (ethertype == ETH_P_PAE) - return 1; - - return 0; -} - -/* Called only as a tasklet (software IRQ), by ieee80211_rx */ -static inline int -ieee80211_rx_frame_decrypt(struct ieee80211_device *ieee, struct sk_buff *skb, - struct ieee80211_crypt_data *crypt) -{ - struct ieee80211_hdr_4addr *hdr; - int res, hdrlen; - - if (crypt == NULL || crypt->ops->decrypt_mpdu == NULL) - return 0; - - hdr = (struct ieee80211_hdr_4addr *)skb->data; - hdrlen = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); - -#ifdef CONFIG_IEEE80211_CRYPT_TKIP - if (ieee->tkip_countermeasures && - strcmp(crypt->ops->name, "TKIP") == 0) { - if (net_ratelimit()) { - netdev_dbg(ieee->dev, - "TKIP countermeasures: dropped received packet from %pM\n", - ieee->dev->name, hdr->addr2); - } - return -1; - } -#endif - - atomic_inc(&crypt->refcnt); - res = crypt->ops->decrypt_mpdu(skb, hdrlen, crypt->priv); - atomic_dec(&crypt->refcnt); - if (res < 0) { - IEEE80211_DEBUG_DROP( - "decryption failed (SA=%pM" - ") res=%d\n", hdr->addr2, res); - if (res == -2) - IEEE80211_DEBUG_DROP("Decryption failed ICV " - "mismatch (key %d)\n", - skb->data[hdrlen + 3] >> 6); - ieee->ieee_stats.rx_discards_undecryptable++; - return -1; - } - - return res; -} - - -/* Called only as a tasklet (software IRQ), by ieee80211_rx */ -static inline int -ieee80211_rx_frame_decrypt_msdu(struct ieee80211_device *ieee, - struct sk_buff *skb, int keyidx, - struct ieee80211_crypt_data *crypt) -{ - struct ieee80211_hdr_4addr *hdr; - int res, hdrlen; - - if (crypt == NULL || crypt->ops->decrypt_msdu == NULL) - return 0; - - hdr = (struct ieee80211_hdr_4addr *)skb->data; - hdrlen = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); - - atomic_inc(&crypt->refcnt); - res = crypt->ops->decrypt_msdu(skb, keyidx, hdrlen, crypt->priv); - atomic_dec(&crypt->refcnt); - if (res < 0) { - netdev_dbg(ieee->dev, - "MSDU decryption/MIC verification failed (SA=%pM keyidx=%d)\n", - hdr->addr2, keyidx); - return -1; - } - - return 0; -} - - -/* this function is stolen from ipw2200 driver*/ -#define IEEE_PACKET_RETRY_TIME (5*HZ) -static int is_duplicate_packet(struct ieee80211_device *ieee, - struct ieee80211_hdr_4addr *header) -{ - u16 fc = le16_to_cpu(header->frame_ctl); - u16 sc = le16_to_cpu(header->seq_ctl); - u16 seq = WLAN_GET_SEQ_SEQ(sc); - u16 frag = WLAN_GET_SEQ_FRAG(sc); - u16 *last_seq, *last_frag; - unsigned long *last_time; - struct ieee80211_hdr_3addrqos *hdr_3addrqos; - struct ieee80211_hdr_4addrqos *hdr_4addrqos; - u8 tid; - - //TO2DS and QoS - if (((fc & IEEE80211_FCTL_DSTODS) == IEEE80211_FCTL_DSTODS) && IEEE80211_QOS_HAS_SEQ(fc)) { - hdr_4addrqos = (struct ieee80211_hdr_4addrqos *)header; - tid = le16_to_cpu(hdr_4addrqos->qos_ctl) & IEEE80211_QOS_TID; - tid = UP2AC(tid); - tid++; - } else if (IEEE80211_QOS_HAS_SEQ(fc)) { //QoS - hdr_3addrqos = (struct ieee80211_hdr_3addrqos *)header; - tid = le16_to_cpu(hdr_3addrqos->qos_ctl) & IEEE80211_QOS_TID; - tid = UP2AC(tid); - tid++; - } else { // no QoS - tid = 0; - } - switch (ieee->iw_mode) { - case IW_MODE_ADHOC: - { - struct list_head *p; - struct ieee_ibss_seq *entry = NULL; - u8 *mac = header->addr2; - int index = mac[5] % IEEE_IBSS_MAC_HASH_SIZE; - - list_for_each(p, &ieee->ibss_mac_hash[index]) { - entry = list_entry(p, struct ieee_ibss_seq, list); - if (!memcmp(entry->mac, mac, ETH_ALEN)) - break; - } - // if (memcmp(entry->mac, mac, ETH_ALEN)){ - if (p == &ieee->ibss_mac_hash[index]) { - entry = kmalloc(sizeof(struct ieee_ibss_seq), GFP_ATOMIC); - if (!entry) - return 0; - - memcpy(entry->mac, mac, ETH_ALEN); - entry->seq_num[tid] = seq; - entry->frag_num[tid] = frag; - entry->packet_time[tid] = jiffies; - list_add(&entry->list, &ieee->ibss_mac_hash[index]); - return 0; - } - last_seq = &entry->seq_num[tid]; - last_frag = &entry->frag_num[tid]; - last_time = &entry->packet_time[tid]; - break; - } - - case IW_MODE_INFRA: - last_seq = &ieee->last_rxseq_num[tid]; - last_frag = &ieee->last_rxfrag_num[tid]; - last_time = &ieee->last_packet_time[tid]; - - break; - default: - return 0; - } - -// if(tid != 0) { -// printk(KERN_WARNING ":)))))))))))%x %x %x, fc(%x)\n", tid, *last_seq, seq, header->frame_ctl); -// } - if ((*last_seq == seq) && - time_after(*last_time + IEEE_PACKET_RETRY_TIME, jiffies)) { - if (*last_frag == frag) { - //printk(KERN_WARNING "[1] go drop!\n"); - goto drop; - - } - if (*last_frag + 1 != frag) - /* out-of-order fragment */ - //printk(KERN_WARNING "[2] go drop!\n"); - goto drop; - } else - *last_seq = seq; - - *last_frag = frag; - *last_time = jiffies; - return 0; - -drop: -// BUG_ON(!(fc & IEEE80211_FCTL_RETRY)); -// printk("DUP\n"); - - return 1; -} - - -/* All received frames are sent to this function. @skb contains the frame in - * IEEE 802.11 format, i.e., in the format it was sent over air. - * This function is called only as a tasklet (software IRQ). */ -int ieee80211_rtl_rx(struct ieee80211_device *ieee, struct sk_buff *skb, - struct ieee80211_rx_stats *rx_stats) -{ - struct net_device *dev = ieee->dev; - //struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); - struct ieee80211_hdr_4addr *hdr; - - size_t hdrlen; - u16 fc, type, stype, sc; - struct net_device_stats *stats; - unsigned int frag; - u8 *payload; - u16 ethertype; - u8 dst[ETH_ALEN]; - u8 src[ETH_ALEN]; - u8 bssid[ETH_ALEN]; - struct ieee80211_crypt_data *crypt = NULL; - int keyidx = 0; - - // cheat the the hdr type - hdr = (struct ieee80211_hdr_4addr *)skb->data; - stats = &ieee->stats; - - if (skb->len < 10) { - netdev_info(ieee->dev, "SKB length < 10\n"); - goto rx_dropped; - } - - fc = le16_to_cpu(hdr->frame_ctl); - type = WLAN_FC_GET_TYPE(fc); - stype = WLAN_FC_GET_STYPE(fc); - sc = le16_to_cpu(hdr->seq_ctl); - - frag = WLAN_GET_SEQ_FRAG(sc); - -//YJ,add,080828,for keep alive - if ((fc & IEEE80211_FCTL_TODS) != IEEE80211_FCTL_TODS) { - if (!memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN)) - ieee->NumRxUnicast++; - } else { - if (!memcmp(hdr->addr3, dev->dev_addr, ETH_ALEN)) - ieee->NumRxUnicast++; - } -//YJ,add,080828,for keep alive,end - - hdrlen = ieee80211_get_hdrlen(fc); - - - if (ieee->iw_mode == IW_MODE_MONITOR) { - ieee80211_monitor_rx(ieee, skb, rx_stats); - stats->rx_packets++; - stats->rx_bytes += skb->len; - return 1; - } - - if (ieee->host_decrypt) { - int idx = 0; - if (skb->len >= hdrlen + 3) - idx = skb->data[hdrlen + 3] >> 6; - crypt = ieee->crypt[idx]; - - /* allow NULL decrypt to indicate an station specific override - * for default encryption */ - if (crypt && (crypt->ops == NULL || - crypt->ops->decrypt_mpdu == NULL)) - crypt = NULL; - - if (!crypt && (fc & IEEE80211_FCTL_WEP)) { - /* This seems to be triggered by some (multicast?) - * frames from other than current BSS, so just drop the - * frames silently instead of filling system log with - * these reports. */ - IEEE80211_DEBUG_DROP("Decryption failed (not set)" - " (SA=%pM)\n", - hdr->addr2); - ieee->ieee_stats.rx_discards_undecryptable++; - goto rx_dropped; - } - } - - if (skb->len < IEEE80211_DATA_HDR3_LEN) - goto rx_dropped; - - // if QoS enabled, should check the sequence for each of the AC - if (is_duplicate_packet(ieee, hdr)) - goto rx_dropped; - - - if (type == IEEE80211_FTYPE_MGMT) { - if (ieee80211_rx_frame_mgmt(ieee, skb, rx_stats, type, stype)) - goto rx_dropped; - else - goto rx_exit; - } - - /* Data frame - extract src/dst addresses */ - switch (fc & (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) { - case IEEE80211_FCTL_FROMDS: - memcpy(dst, hdr->addr1, ETH_ALEN); - memcpy(src, hdr->addr3, ETH_ALEN); - memcpy(bssid, hdr->addr2, ETH_ALEN); - break; - case IEEE80211_FCTL_TODS: - memcpy(dst, hdr->addr3, ETH_ALEN); - memcpy(src, hdr->addr2, ETH_ALEN); - memcpy(bssid, hdr->addr1, ETH_ALEN); - break; - case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS: - if (skb->len < IEEE80211_DATA_HDR4_LEN) - goto rx_dropped; - memcpy(dst, hdr->addr3, ETH_ALEN); - memcpy(src, hdr->addr4, ETH_ALEN); - memcpy(bssid, ieee->current_network.bssid, ETH_ALEN); - break; - case 0: - memcpy(dst, hdr->addr1, ETH_ALEN); - memcpy(src, hdr->addr2, ETH_ALEN); - memcpy(bssid, hdr->addr3, ETH_ALEN); - break; - } - - - dev->last_rx = jiffies; - - - /* Nullfunc frames may have PS-bit set, so they must be passed to - * hostap_handle_sta_rx() before being dropped here. */ - if (stype != IEEE80211_STYPE_DATA && - stype != IEEE80211_STYPE_DATA_CFACK && - stype != IEEE80211_STYPE_DATA_CFPOLL && - stype != IEEE80211_STYPE_DATA_CFACKPOLL && - stype != IEEE80211_STYPE_QOS_DATA//add by David,2006.8.4 - ) { - if (stype != IEEE80211_STYPE_NULLFUNC) - IEEE80211_DEBUG_DROP( - "RX: dropped data frame " - "with no data (type=0x%02x, " - "subtype=0x%02x, len=%d)\n", - type, stype, skb->len); - goto rx_dropped; - } - if (memcmp(bssid, ieee->current_network.bssid, ETH_ALEN)) - goto rx_dropped; - - ieee->NumRxDataInPeriod++; - ieee->NumRxOkTotal++; - /* skb: hdr + (possibly fragmented, possibly encrypted) payload */ - - if (ieee->host_decrypt && (fc & IEEE80211_FCTL_WEP) && - (keyidx = ieee80211_rx_frame_decrypt(ieee, skb, crypt)) < 0) - goto rx_dropped; - - hdr = (struct ieee80211_hdr_4addr *)skb->data; - - /* skb: hdr + (possibly fragmented) plaintext payload */ - // PR: FIXME: hostap has additional conditions in the "if" below: - // ieee->host_decrypt && (fc & IEEE80211_FCTL_WEP) && - if ((frag != 0 || (fc & IEEE80211_FCTL_MOREFRAGS))) { - int flen; - struct sk_buff *frag_skb = ieee80211_frag_cache_get(ieee, hdr); - IEEE80211_DEBUG_FRAG("Rx Fragment received (%u)\n", frag); - - if (!frag_skb) { - IEEE80211_DEBUG(IEEE80211_DL_RX | IEEE80211_DL_FRAG, - "Rx cannot get skb from fragment " - "cache (morefrag=%d seq=%u frag=%u)\n", - (fc & IEEE80211_FCTL_MOREFRAGS) != 0, - WLAN_GET_SEQ_SEQ(sc), frag); - goto rx_dropped; - } - flen = skb->len; - if (frag != 0) - flen -= hdrlen; - - if (frag_skb->tail + flen > frag_skb->end) { - netdev_warn(ieee->dev, - "host decrypted and reassembled frame did not fit skb\n"); - ieee80211_frag_cache_invalidate(ieee, hdr); - goto rx_dropped; - } - - if (frag == 0) { - /* copy first fragment (including full headers) into - * beginning of the fragment cache skb */ - memcpy(skb_put(frag_skb, flen), skb->data, flen); - } else { - /* append frame payload to the end of the fragment - * cache skb */ - memcpy(skb_put(frag_skb, flen), skb->data + hdrlen, - flen); - } - dev_kfree_skb_any(skb); - skb = NULL; - - if (fc & IEEE80211_FCTL_MOREFRAGS) { - /* more fragments expected - leave the skb in fragment - * cache for now; it will be delivered to upper layers - * after all fragments have been received */ - goto rx_exit; - } - - /* this was the last fragment and the frame will be - * delivered, so remove skb from fragment cache */ - skb = frag_skb; - hdr = (struct ieee80211_hdr_4addr *)skb->data; - ieee80211_frag_cache_invalidate(ieee, hdr); - } - - /* skb: hdr + (possible reassembled) full MSDU payload; possibly still - * encrypted/authenticated */ - if (ieee->host_decrypt && (fc & IEEE80211_FCTL_WEP) && - ieee80211_rx_frame_decrypt_msdu(ieee, skb, keyidx, crypt)) - goto rx_dropped; - - hdr = (struct ieee80211_hdr_4addr *)skb->data; - if (crypt && !(fc & IEEE80211_FCTL_WEP) && !ieee->open_wep) { - if (/*ieee->ieee802_1x &&*/ - ieee80211_is_eapol_frame(ieee, skb, hdrlen)) { - -#ifdef CONFIG_IEEE80211_DEBUG - /* pass unencrypted EAPOL frames even if encryption is - * configured */ - struct eapol *eap = (struct eapol *)(skb->data + - 24); - IEEE80211_DEBUG_EAP("RX: IEEE 802.1X EAPOL frame: %s\n", - eap_get_type(eap->type)); -#endif - } else { - IEEE80211_DEBUG_DROP( - "encryption configured, but RX " - "frame not encrypted (SA=%pM)\n", - hdr->addr2); - goto rx_dropped; - } - } - -#ifdef CONFIG_IEEE80211_DEBUG - if (crypt && !(fc & IEEE80211_FCTL_WEP) && - ieee80211_is_eapol_frame(ieee, skb, hdrlen)) { - struct eapol *eap = (struct eapol *)(skb->data + - 24); - IEEE80211_DEBUG_EAP("RX: IEEE 802.1X EAPOL frame: %s\n", - eap_get_type(eap->type)); - } -#endif - - if (crypt && !(fc & IEEE80211_FCTL_WEP) && !ieee->open_wep && - !ieee80211_is_eapol_frame(ieee, skb, hdrlen)) { - IEEE80211_DEBUG_DROP( - "dropped unencrypted RX data " - "frame from %pM" - " (drop_unencrypted=1)\n", - hdr->addr2); - goto rx_dropped; - } -/* - if(ieee80211_is_eapol_frame(ieee, skb, hdrlen)) { - printk(KERN_WARNING "RX: IEEE802.1X EPAOL frame!\n"); - } -*/ - /* skb: hdr + (possible reassembled) full plaintext payload */ - payload = skb->data + hdrlen; - ethertype = (payload[6] << 8) | payload[7]; - - - /* convert hdr + possible LLC headers into Ethernet header */ - if (skb->len - hdrlen >= 8 && - ((memcmp(payload, rfc1042_header, SNAP_SIZE) == 0 && - ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) || - memcmp(payload, bridge_tunnel_header, SNAP_SIZE) == 0)) { - /* remove RFC1042 or Bridge-Tunnel encapsulation and - * replace EtherType */ - skb_pull(skb, hdrlen + SNAP_SIZE); - memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN); - memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN); - } else { - u16 len; - /* Leave Ethernet header part of hdr and full payload */ - skb_pull(skb, hdrlen); - len = htons(skb->len); - memcpy(skb_push(skb, 2), &len, 2); - memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN); - memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN); - } - - - stats->rx_packets++; - stats->rx_bytes += skb->len; - - if (skb) { - skb->protocol = eth_type_trans(skb, dev); - memset(skb->cb, 0, sizeof(skb->cb)); - skb->dev = dev; - skb->ip_summed = CHECKSUM_NONE; /* 802.11 crc not sufficient */ - ieee->last_rx_ps_time = jiffies; - netif_rx(skb); - } - - rx_exit: - return 1; - - rx_dropped: - stats->rx_dropped++; - - /* Returning 0 indicates to caller that we have not handled the SKB-- - * so it is still allocated and can be used again by underlying - * hardware as a DMA target */ - return 0; -} - -#define MGMT_FRAME_FIXED_PART_LENGTH 0x24 - -static inline int ieee80211_is_ofdm_rate(u8 rate) -{ - switch (rate & ~IEEE80211_BASIC_RATE_MASK) { - case IEEE80211_OFDM_RATE_6MB: - case IEEE80211_OFDM_RATE_9MB: - case IEEE80211_OFDM_RATE_12MB: - case IEEE80211_OFDM_RATE_18MB: - case IEEE80211_OFDM_RATE_24MB: - case IEEE80211_OFDM_RATE_36MB: - case IEEE80211_OFDM_RATE_48MB: - case IEEE80211_OFDM_RATE_54MB: - return 1; - } - return 0; -} - -static inline int ieee80211_SignalStrengthTranslate(int CurrSS) -{ - int RetSS; - - // Step 1. Scale mapping. - if (CurrSS >= 71 && CurrSS <= 100) - RetSS = 90 + ((CurrSS - 70) / 3); - else if (CurrSS >= 41 && CurrSS <= 70) - RetSS = 78 + ((CurrSS - 40) / 3); - else if (CurrSS >= 31 && CurrSS <= 40) - RetSS = 66 + (CurrSS - 30); - else if (CurrSS >= 21 && CurrSS <= 30) - RetSS = 54 + (CurrSS - 20); - else if (CurrSS >= 5 && CurrSS <= 20) - RetSS = 42 + (((CurrSS - 5) * 2) / 3); - else if (CurrSS == 4) - RetSS = 36; - else if (CurrSS == 3) - RetSS = 27; - else if (CurrSS == 2) - RetSS = 18; - else if (CurrSS == 1) - RetSS = 9; - else - RetSS = CurrSS; - - //RT_TRACE(COMP_DBG, DBG_LOUD, ("##### After Mapping: LastSS: %d, CurrSS: %d, RetSS: %d\n", LastSS, CurrSS, RetSS)); - - // Step 2. Smoothing. - - //RT_TRACE(COMP_DBG, DBG_LOUD, ("$$$$$ After Smoothing: LastSS: %d, CurrSS: %d, RetSS: %d\n", LastSS, CurrSS, RetSS)); - - return RetSS; -} - -static inline void -ieee80211_extract_country_ie(struct ieee80211_device *ieee, - struct ieee80211_info_element *info_element, - struct ieee80211_network *network, u8 *addr2) -{ - if (IS_DOT11D_ENABLE(ieee)) { - if (info_element->len != 0) { - memcpy(network->CountryIeBuf, info_element->data, info_element->len); - network->CountryIeLen = info_element->len; - - if (!IS_COUNTRY_IE_VALID(ieee)) - Dot11d_UpdateCountryIe(ieee, addr2, info_element->len, info_element->data); - } - - // - // 070305, rcnjko: I update country IE watch dog here because - // some AP (e.g. Cisco 1242) don't include country IE in their - // probe response frame. - // - if (IS_EQUAL_CIE_SRC(ieee, addr2)) - UPDATE_CIE_WATCHDOG(ieee); - } - -} - -/* SignalStrengthIndex is 0-100 */ -static int ieee80211_TranslateToDbm(unsigned char SignalStrengthIndex) -{ - unsigned char SignalPower; // in dBm. - - // Translate to dBm (x=0.5y-95). - SignalPower = (int)SignalStrengthIndex * 7 / 10; - SignalPower -= 95; - - return SignalPower; -} -inline int ieee80211_network_init( - struct ieee80211_device *ieee, - struct ieee80211_probe_response *beacon, - struct ieee80211_network *network, - struct ieee80211_rx_stats *stats) -{ -#ifdef CONFIG_IEEE80211_DEBUG - char rates_str[64]; - char *p; -#endif - struct ieee80211_info_element *info_element; - u16 left; - u8 i; - short offset; - u8 curRate = 0, hOpRate = 0, curRate_ex = 0; - - /* Pull out fixed field data */ - memcpy(network->bssid, beacon->header.addr3, ETH_ALEN); - network->capability = beacon->capability; - network->last_scanned = jiffies; - network->time_stamp[0] = beacon->time_stamp[0]; - network->time_stamp[1] = beacon->time_stamp[1]; - network->beacon_interval = beacon->beacon_interval; - /* Where to pull this? beacon->listen_interval;*/ - network->listen_interval = 0x0A; - network->rates_len = network->rates_ex_len = 0; - network->last_associate = 0; - network->ssid_len = 0; - network->flags = 0; - network->atim_window = 0; - network->QoS_Enable = 0; -//by amy 080312 - network->HighestOperaRate = 0; -//by amy 080312 - network->Turbo_Enable = 0; - network->CountryIeLen = 0; - memset(network->CountryIeBuf, 0, MAX_IE_LEN); - - if (stats->freq == IEEE80211_52GHZ_BAND) { - /* for A band (No DS info) */ - network->channel = stats->received_channel; - } else - network->flags |= NETWORK_HAS_CCK; - - network->wpa_ie_len = 0; - network->rsn_ie_len = 0; - - info_element = &beacon->info_element; - left = stats->len - ((void *)info_element - (void *)beacon); - while (left >= sizeof(struct ieee80211_info_element_hdr)) { - if (sizeof(struct ieee80211_info_element_hdr) + info_element->len > left) { - IEEE80211_DEBUG_SCAN("SCAN: parse failed: info_element->len + 2 > left : info_element->len+2=%d left=%d.\n", - info_element->len + sizeof(struct ieee80211_info_element), - left); - return 1; - } - - switch (info_element->id) { - case MFIE_TYPE_SSID: - if (ieee80211_is_empty_essid(info_element->data, - info_element->len)) { - network->flags |= NETWORK_EMPTY_ESSID; - break; - } - - network->ssid_len = min(info_element->len, - (u8)IW_ESSID_MAX_SIZE); - memcpy(network->ssid, info_element->data, network->ssid_len); - if (network->ssid_len < IW_ESSID_MAX_SIZE) - memset(network->ssid + network->ssid_len, 0, - IW_ESSID_MAX_SIZE - network->ssid_len); - - IEEE80211_DEBUG_SCAN("MFIE_TYPE_SSID: '%s' len=%d.\n", - network->ssid, network->ssid_len); - break; - - case MFIE_TYPE_RATES: -#ifdef CONFIG_IEEE80211_DEBUG - p = rates_str; -#endif - network->rates_len = min(info_element->len, MAX_RATES_LENGTH); - for (i = 0; i < network->rates_len; i++) { - network->rates[i] = info_element->data[i]; - curRate = network->rates[i] & 0x7f; - if (hOpRate < curRate) - hOpRate = curRate; -#ifdef CONFIG_IEEE80211_DEBUG - p += snprintf(p, sizeof(rates_str) - (p - rates_str), "%02X ", network->rates[i]); -#endif - if (ieee80211_is_ofdm_rate(info_element->data[i])) { - network->flags |= NETWORK_HAS_OFDM; - if (info_element->data[i] & - IEEE80211_BASIC_RATE_MASK) - network->flags &= - ~NETWORK_HAS_CCK; - } - } - - IEEE80211_DEBUG_SCAN("MFIE_TYPE_RATES: '%s' (%d)\n", - rates_str, network->rates_len); - break; - - case MFIE_TYPE_RATES_EX: -#ifdef CONFIG_IEEE80211_DEBUG - p = rates_str; -#endif - network->rates_ex_len = min(info_element->len, MAX_RATES_EX_LENGTH); - for (i = 0; i < network->rates_ex_len; i++) { - network->rates_ex[i] = info_element->data[i]; - curRate_ex = network->rates_ex[i] & 0x7f; - if (hOpRate < curRate_ex) - hOpRate = curRate_ex; -#ifdef CONFIG_IEEE80211_DEBUG - p += snprintf(p, sizeof(rates_str) - (p - rates_str), "%02X ", network->rates[i]); -#endif - if (ieee80211_is_ofdm_rate(info_element->data[i])) { - network->flags |= NETWORK_HAS_OFDM; - if (info_element->data[i] & - IEEE80211_BASIC_RATE_MASK) - network->flags &= - ~NETWORK_HAS_CCK; - } - } - - IEEE80211_DEBUG_SCAN("MFIE_TYPE_RATES_EX: '%s' (%d)\n", - rates_str, network->rates_ex_len); - break; - - case MFIE_TYPE_DS_SET: - IEEE80211_DEBUG_SCAN("MFIE_TYPE_DS_SET: %d\n", - info_element->data[0]); - if (stats->freq == IEEE80211_24GHZ_BAND) - network->channel = info_element->data[0]; - break; - - case MFIE_TYPE_FH_SET: - IEEE80211_DEBUG_SCAN("MFIE_TYPE_FH_SET: ignored\n"); - break; - - case MFIE_TYPE_CF_SET: - IEEE80211_DEBUG_SCAN("MFIE_TYPE_CF_SET: ignored\n"); - break; - - case MFIE_TYPE_TIM: - - if (info_element->len < 4) - break; - - network->dtim_period = info_element->data[1]; - - if (ieee->state != IEEE80211_LINKED) - break; - - network->last_dtim_sta_time[0] = jiffies; - network->last_dtim_sta_time[1] = stats->mac_time[1]; - - network->dtim_data = IEEE80211_DTIM_VALID; - - if (info_element->data[0] != 0) - break; - - if (info_element->data[2] & 1) - network->dtim_data |= IEEE80211_DTIM_MBCAST; - - offset = (info_element->data[2] >> 1)*2; - - //printk("offset1:%x aid:%x\n",offset, ieee->assoc_id); - - /* add and modified for ps 2008.1.22 */ - if (ieee->assoc_id < 8*offset || - ieee->assoc_id > 8*(offset + info_element->len - 3)) { - break; - } - - offset = (ieee->assoc_id/8) - offset;// + ((aid % 8)? 0 : 1) ; - - // printk("offset:%x data:%x, ucast:%d\n", offset, - // info_element->data[3+offset] , - // info_element->data[3+offset] & (1<<(ieee->assoc_id%8))); - - if (info_element->data[3+offset] & (1<<(ieee->assoc_id%8))) - network->dtim_data |= IEEE80211_DTIM_UCAST; - - break; - - case MFIE_TYPE_IBSS_SET: - IEEE80211_DEBUG_SCAN("MFIE_TYPE_IBSS_SET: ignored\n"); - break; - - case MFIE_TYPE_CHALLENGE: - IEEE80211_DEBUG_SCAN("MFIE_TYPE_CHALLENGE: ignored\n"); - break; - - case MFIE_TYPE_GENERIC: - //nic is 87B - IEEE80211_DEBUG_SCAN("MFIE_TYPE_GENERIC: %d bytes\n", - info_element->len); - if (info_element->len >= 4 && - info_element->data[0] == 0x00 && - info_element->data[1] == 0x50 && - info_element->data[2] == 0xf2 && - info_element->data[3] == 0x01) { - network->wpa_ie_len = min(info_element->len + 2, - MAX_WPA_IE_LEN); - memcpy(network->wpa_ie, info_element, - network->wpa_ie_len); - } - - if (info_element->len == 7 && - info_element->data[0] == 0x00 && - info_element->data[1] == 0xe0 && - info_element->data[2] == 0x4c && - info_element->data[3] == 0x01 && - info_element->data[4] == 0x02) { - network->Turbo_Enable = 1; - } - if (1 == stats->nic_type) //nic 87 - break; - - if (info_element->len >= 5 && - info_element->data[0] == 0x00 && - info_element->data[1] == 0x50 && - info_element->data[2] == 0xf2 && - info_element->data[3] == 0x02 && - info_element->data[4] == 0x00) { - //printk(KERN_WARNING "wmm info updated: %x\n", info_element->data[6]); - //WMM Information Element - network->wmm_info = info_element->data[6]; - network->QoS_Enable = 1; - } - - if (info_element->len >= 8 && - info_element->data[0] == 0x00 && - info_element->data[1] == 0x50 && - info_element->data[2] == 0xf2 && - info_element->data[3] == 0x02 && - info_element->data[4] == 0x01) { - // Not care about version at present. - //WMM Information Element - //printk(KERN_WARNING "wmm info¶m updated: %x\n", info_element->data[6]); - network->wmm_info = info_element->data[6]; - //WMM Parameter Element - memcpy(network->wmm_param, (u8 *)(info_element->data + 8), (info_element->len - 8)); - network->QoS_Enable = 1; - } - break; - - case MFIE_TYPE_RSN: - IEEE80211_DEBUG_SCAN("MFIE_TYPE_RSN: %d bytes\n", - info_element->len); - network->rsn_ie_len = min(info_element->len + 2, - MAX_WPA_IE_LEN); - memcpy(network->rsn_ie, info_element, - network->rsn_ie_len); - break; - case MFIE_TYPE_COUNTRY: - IEEE80211_DEBUG_SCAN("MFIE_TYPE_COUNTRY: %d bytes\n", - info_element->len); -// printk("=====>Receive <%s> Country IE\n",network->ssid); - ieee80211_extract_country_ie(ieee, info_element, network, beacon->header.addr2); - break; - default: - IEEE80211_DEBUG_SCAN("unsupported IE %d\n", - info_element->id); - break; - } - - left -= sizeof(struct ieee80211_info_element_hdr) + - info_element->len; - info_element = (struct ieee80211_info_element *) - &info_element->data[info_element->len]; - } -//by amy 080312 - network->HighestOperaRate = hOpRate; -//by amy 080312 - network->mode = 0; - if (stats->freq == IEEE80211_52GHZ_BAND) - network->mode = IEEE_A; - else { - if (network->flags & NETWORK_HAS_OFDM) - network->mode |= IEEE_G; - if (network->flags & NETWORK_HAS_CCK) - network->mode |= IEEE_B; - } - - if (network->mode == 0) { - IEEE80211_DEBUG_SCAN("Filtered out '%s (%pM)' " - "network.\n", - escape_essid(network->ssid, - network->ssid_len), - network->bssid); - return 1; - } - - if (ieee80211_is_empty_essid(network->ssid, network->ssid_len)) - network->flags |= NETWORK_EMPTY_ESSID; - - stats->signal = ieee80211_TranslateToDbm(stats->signalstrength); - //stats->noise = stats->signal - stats->noise; - stats->noise = ieee80211_TranslateToDbm(100 - stats->signalstrength) - 25; - memcpy(&network->stats, stats, sizeof(network->stats)); - - return 0; -} - -static inline int is_same_network(struct ieee80211_network *src, - struct ieee80211_network *dst, - struct ieee80211_device *ieee) -{ - /* A network is only a duplicate if the channel, BSSID, ESSID - * and the capability field (in particular IBSS and BSS) all match. - * We treat all with the same BSSID and channel - * as one network */ - return (((src->ssid_len == dst->ssid_len) || (ieee->iw_mode == IW_MODE_INFRA)) && //YJ,mod,080819,for hidden ap - //((src->ssid_len == dst->ssid_len) && - (src->channel == dst->channel) && - !memcmp(src->bssid, dst->bssid, ETH_ALEN) && - (!memcmp(src->ssid, dst->ssid, src->ssid_len) || (ieee->iw_mode == IW_MODE_INFRA)) && //YJ,mod,080819,for hidden ap - //!memcmp(src->ssid, dst->ssid, src->ssid_len) && - ((src->capability & WLAN_CAPABILITY_IBSS) == - (dst->capability & WLAN_CAPABILITY_IBSS)) && - ((src->capability & WLAN_CAPABILITY_BSS) == - (dst->capability & WLAN_CAPABILITY_BSS))); -} - -inline void update_network(struct ieee80211_network *dst, - struct ieee80211_network *src) -{ - unsigned char quality = src->stats.signalstrength; - unsigned char signal = 0; - unsigned char noise = 0; - if (dst->stats.signalstrength > 0) - quality = (dst->stats.signalstrength * 5 + src->stats.signalstrength + 5)/6; - signal = ieee80211_TranslateToDbm(quality); - //noise = signal - src->stats.noise; - if (dst->stats.noise > 0) - noise = (dst->stats.noise * 5 + src->stats.noise)/6; - //if(strcmp(dst->ssid, "linksys_lzm000") == 0) -// printk("ssid:%s, quality:%d, signal:%d\n", dst->ssid, quality, signal); - memcpy(&dst->stats, &src->stats, sizeof(struct ieee80211_rx_stats)); - dst->stats.signalstrength = quality; - dst->stats.signal = signal; -// printk("==================>stats.signal is %d\n",dst->stats.signal); - dst->stats.noise = noise; - - - dst->capability = src->capability; - memcpy(dst->rates, src->rates, src->rates_len); - dst->rates_len = src->rates_len; - memcpy(dst->rates_ex, src->rates_ex, src->rates_ex_len); - dst->rates_ex_len = src->rates_ex_len; - dst->HighestOperaRate = src->HighestOperaRate; - //printk("==========>in %s: src->ssid is %s,chan is %d\n",__func__,src->ssid,src->channel); - - //YJ,add,080819,for hidden ap - if (src->ssid_len > 0) { - //if(src->ssid_len == 13) - // printk("=====================>>>>>>>> Dst ssid: %s Src ssid: %s\n", dst->ssid, src->ssid); - memset(dst->ssid, 0, dst->ssid_len); - dst->ssid_len = src->ssid_len; - memcpy(dst->ssid, src->ssid, src->ssid_len); - } - //YJ,add,080819,for hidden ap,end - - dst->channel = src->channel; - dst->mode = src->mode; - dst->flags = src->flags; - dst->time_stamp[0] = src->time_stamp[0]; - dst->time_stamp[1] = src->time_stamp[1]; - - dst->beacon_interval = src->beacon_interval; - dst->listen_interval = src->listen_interval; - dst->atim_window = src->atim_window; - dst->dtim_period = src->dtim_period; - dst->dtim_data = src->dtim_data; - dst->last_dtim_sta_time[0] = src->last_dtim_sta_time[0]; - dst->last_dtim_sta_time[1] = src->last_dtim_sta_time[1]; -// printk("update:%s, dtim_period:%x, dtim_data:%x\n", src->ssid, src->dtim_period, src->dtim_data); - memcpy(dst->wpa_ie, src->wpa_ie, src->wpa_ie_len); - dst->wpa_ie_len = src->wpa_ie_len; - memcpy(dst->rsn_ie, src->rsn_ie, src->rsn_ie_len); - dst->rsn_ie_len = src->rsn_ie_len; - - dst->last_scanned = jiffies; - /* dst->last_associate is not overwritten */ -// disable QoS process now, added by David 2006/7/25 -#if 1 - dst->wmm_info = src->wmm_info; //sure to exist in beacon or probe response frame. -/* - if((dst->wmm_info^src->wmm_info)&0x0f) {//Param Set Count change, update Parameter - memcpy(dst->wmm_param, src->wmm_param, IEEE80211_AC_PRAM_LEN); - } -*/ - if (src->wmm_param[0].ac_aci_acm_aifsn || \ - src->wmm_param[1].ac_aci_acm_aifsn || \ - src->wmm_param[2].ac_aci_acm_aifsn || \ - src->wmm_param[3].ac_aci_acm_aifsn) { - memcpy(dst->wmm_param, src->wmm_param, WME_AC_PRAM_LEN); - } - dst->QoS_Enable = src->QoS_Enable; -#else - dst->QoS_Enable = 1;//for Rtl8187 simulation -#endif - dst->SignalStrength = src->SignalStrength; - dst->Turbo_Enable = src->Turbo_Enable; - dst->CountryIeLen = src->CountryIeLen; - memcpy(dst->CountryIeBuf, src->CountryIeBuf, src->CountryIeLen); -} - - -inline void -ieee80211_process_probe_response(struct ieee80211_device *ieee, - struct ieee80211_probe_response *beacon, - struct ieee80211_rx_stats *stats) -{ - struct ieee80211_network network; - struct ieee80211_network *target; - struct ieee80211_network *oldest = NULL; -#ifdef CONFIG_IEEE80211_DEBUG - struct ieee80211_info_element *info_element = &beacon->info_element; -#endif - unsigned long flags; - short renew; - u8 wmm_info; - u8 is_beacon = (WLAN_FC_GET_STYPE(beacon->header.frame_ctl) == IEEE80211_STYPE_BEACON) ? 1 : 0; //YJ,add,080819,for hidden ap - - memset(&network, 0, sizeof(struct ieee80211_network)); - - IEEE80211_DEBUG_SCAN( - "'%s' (%pM): %c%c%c%c %c%c%c%c-%c%c%c%c %c%c%c%c\n", - escape_essid(info_element->data, info_element->len), - beacon->header.addr3, - (beacon->capability & (1<<0xf)) ? '1' : '0', - (beacon->capability & (1<<0xe)) ? '1' : '0', - (beacon->capability & (1<<0xd)) ? '1' : '0', - (beacon->capability & (1<<0xc)) ? '1' : '0', - (beacon->capability & (1<<0xb)) ? '1' : '0', - (beacon->capability & (1<<0xa)) ? '1' : '0', - (beacon->capability & (1<<0x9)) ? '1' : '0', - (beacon->capability & (1<<0x8)) ? '1' : '0', - (beacon->capability & (1<<0x7)) ? '1' : '0', - (beacon->capability & (1<<0x6)) ? '1' : '0', - (beacon->capability & (1<<0x5)) ? '1' : '0', - (beacon->capability & (1<<0x4)) ? '1' : '0', - (beacon->capability & (1<<0x3)) ? '1' : '0', - (beacon->capability & (1<<0x2)) ? '1' : '0', - (beacon->capability & (1<<0x1)) ? '1' : '0', - (beacon->capability & (1<<0x0)) ? '1' : '0'); - - if (ieee80211_network_init(ieee, beacon, &network, stats)) { - IEEE80211_DEBUG_SCAN("Dropped '%s' (%pM) via %s.\n", - escape_essid(info_element->data, - info_element->len), - beacon->header.addr3, - WLAN_FC_GET_STYPE(beacon->header.frame_ctl) == - IEEE80211_STYPE_PROBE_RESP ? - "PROBE RESPONSE" : "BEACON"); - return; - } - - // For Asus EeePc request, - // (1) if wireless adapter receive get any 802.11d country code in AP beacon, - // wireless adapter should follow the country code. - // (2) If there is no any country code in beacon, - // then wireless adapter should do active scan from ch1~11 and - // passive scan from ch12~14 - if (ieee->bGlobalDomain) { - if (WLAN_FC_GET_STYPE(beacon->header.frame_ctl) == IEEE80211_STYPE_PROBE_RESP) { - // Case 1: Country code - if (IS_COUNTRY_IE_VALID(ieee)) { - if (!IsLegalChannel(ieee, network.channel)) { - printk("GetScanInfo(): For Country code, filter probe response at channel(%d).\n", network.channel); - return; - } - } - // Case 2: No any country code. - else { - // Filter over channel ch12~14 - if (network.channel > 11) { - printk("GetScanInfo(): For Global Domain, filter probe response at channel(%d).\n", network.channel); - return; - } - } - } else { - // Case 1: Country code - if (IS_COUNTRY_IE_VALID(ieee)) { - if (!IsLegalChannel(ieee, network.channel)) { - printk("GetScanInfo(): For Country code, filter beacon at channel(%d).\n", network.channel); - return; - } - } - // Case 2: No any country code. - else { - // Filter over channel ch12~14 - if (network.channel > 14) { - printk("GetScanInfo(): For Global Domain, filter beacon at channel(%d).\n", network.channel); - return; - } - } - } - } - /* The network parsed correctly -- so now we scan our known networks - * to see if we can find it in our list. - * - * NOTE: This search is definitely not optimized. Once its doing - * the "right thing" we'll optimize it for efficiency if - * necessary */ - - /* Search for this entry in the list and update it if it is - * already there. */ - - spin_lock_irqsave(&ieee->lock, flags); - - if (is_same_network(&ieee->current_network, &network, ieee)) { - wmm_info = ieee->current_network.wmm_info; - //YJ,add,080819,for hidden ap - if (is_beacon == 0) - network.flags = (~NETWORK_EMPTY_ESSID & network.flags)|(NETWORK_EMPTY_ESSID & ieee->current_network.flags); - else if (ieee->state == IEEE80211_LINKED) - ieee->NumRxBcnInPeriod++; - //YJ,add,080819,for hidden ap,end - //printk("====>network.ssid=%s cur_ssid=%s\n", network.ssid, ieee->current_network.ssid); - update_network(&ieee->current_network, &network); - } - - list_for_each_entry(target, &ieee->network_list, list) { - if (is_same_network(target, &network, ieee)) - break; - if ((oldest == NULL) || - (target->last_scanned < oldest->last_scanned)) - oldest = target; - } - - /* If we didn't find a match, then get a new network slot to initialize - * with this beacon's information */ - if (&target->list == &ieee->network_list) { - if (list_empty(&ieee->network_free_list)) { - /* If there are no more slots, expire the oldest */ - list_del(&oldest->list); - target = oldest; - IEEE80211_DEBUG_SCAN("Expired '%s' (%pM) from " - "network list.\n", - escape_essid(target->ssid, - target->ssid_len), - target->bssid); - } else { - /* Otherwise just pull from the free list */ - target = list_entry(ieee->network_free_list.next, - struct ieee80211_network, list); - list_del(ieee->network_free_list.next); - } - - -#ifdef CONFIG_IEEE80211_DEBUG - IEEE80211_DEBUG_SCAN("Adding '%s' (%pM) via %s.\n", - escape_essid(network.ssid, - network.ssid_len), - network.bssid, - WLAN_FC_GET_STYPE(beacon->header.frame_ctl) == - IEEE80211_STYPE_PROBE_RESP ? - "PROBE RESPONSE" : "BEACON"); -#endif - - memcpy(target, &network, sizeof(*target)); - list_add_tail(&target->list, &ieee->network_list); - } else { - IEEE80211_DEBUG_SCAN("Updating '%s' (%pM) via %s.\n", - escape_essid(target->ssid, - target->ssid_len), - target->bssid, - WLAN_FC_GET_STYPE(beacon->header.frame_ctl) == - IEEE80211_STYPE_PROBE_RESP ? - "PROBE RESPONSE" : "BEACON"); - - /* we have an entry and we are going to update it. But this entry may - * be already expired. In this case we do the same as we found a new - * net and call the new_net handler - */ - renew = !time_after(target->last_scanned + ieee->scan_age, jiffies); - //YJ,add,080819,for hidden ap - if (is_beacon == 0) - network.flags = (~NETWORK_EMPTY_ESSID & network.flags)|(NETWORK_EMPTY_ESSID & target->flags); - //if(strncmp(network.ssid, "linksys-c",9) == 0) - // printk("====>2 network.ssid=%s FLAG=%d target.ssid=%s FLAG=%d\n", network.ssid, network.flags, target->ssid, target->flags); - if (((network.flags & NETWORK_EMPTY_ESSID) == NETWORK_EMPTY_ESSID) \ - && (((network.ssid_len > 0) && (strncmp(target->ssid, network.ssid, network.ssid_len)))\ - || ((ieee->current_network.ssid_len == network.ssid_len) && (strncmp(ieee->current_network.ssid, network.ssid, network.ssid_len) == 0) && (ieee->state == IEEE80211_NOLINK)))) - renew = 1; - //YJ,add,080819,for hidden ap,end - update_network(target, &network); - } - - spin_unlock_irqrestore(&ieee->lock, flags); -} - -void ieee80211_rx_mgt(struct ieee80211_device *ieee, - struct ieee80211_hdr_4addr *header, - struct ieee80211_rx_stats *stats) -{ - switch (WLAN_FC_GET_STYPE(header->frame_ctl)) { - - case IEEE80211_STYPE_BEACON: - IEEE80211_DEBUG_MGMT("received BEACON (%d)\n", - WLAN_FC_GET_STYPE(header->frame_ctl)); - IEEE80211_DEBUG_SCAN("Beacon\n"); - ieee80211_process_probe_response( - ieee, (struct ieee80211_probe_response *)header, stats); - break; - - case IEEE80211_STYPE_PROBE_RESP: - IEEE80211_DEBUG_MGMT("received PROBE RESPONSE (%d)\n", - WLAN_FC_GET_STYPE(header->frame_ctl)); - IEEE80211_DEBUG_SCAN("Probe response\n"); - ieee80211_process_probe_response( - ieee, (struct ieee80211_probe_response *)header, stats); - break; - } -} diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c deleted file mode 100644 index 03eb164798c..00000000000 --- a/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c +++ /dev/null @@ -1,2711 +0,0 @@ -/* IEEE 802.11 SoftMAC layer - * Copyright (c) 2005 Andrea Merello - * - * Mostly extracted from the rtl8180-sa2400 driver for the - * in-kernel generic ieee802.11 stack. - * - * Few lines might be stolen from other part of the ieee80211 - * stack. Copyright who own it's copyright - * - * WPA code stolen from the ipw2200 driver. - * Copyright who own it's copyright. - * - * released under the GPL - */ - -#include "ieee80211.h" - -#include -#include -#include -#include -#include -#include - -#include "dot11d.h" - -short ieee80211_is_54g(const struct ieee80211_network *net) -{ - return (net->rates_ex_len > 0) || (net->rates_len > 4); -} - -short ieee80211_is_shortslot(const struct ieee80211_network *net) -{ - return net->capability & WLAN_CAPABILITY_SHORT_SLOT; -} - -/* returns the total length needed for placing the RATE MFIE - * tag and the EXTENDED RATE MFIE tag if needed. - * It encludes two bytes per tag for the tag itself and its len - */ -static unsigned int ieee80211_MFIE_rate_len(struct ieee80211_device *ieee) -{ - unsigned int rate_len = 0; - - if (ieee->modulation & IEEE80211_CCK_MODULATION) - rate_len = IEEE80211_CCK_RATE_LEN + 2; - - if (ieee->modulation & IEEE80211_OFDM_MODULATION) - - rate_len += IEEE80211_OFDM_RATE_LEN + 2; - - return rate_len; -} - -/* place the MFIE rate, tag to the memory (double) poised. - * Then it updates the pointer so that it points after the new MFIE tag added. - */ -static void ieee80211_MFIE_Brate(struct ieee80211_device *ieee, u8 **tag_p) -{ - u8 *tag = *tag_p; - - if (ieee->modulation & IEEE80211_CCK_MODULATION) { - *tag++ = MFIE_TYPE_RATES; - *tag++ = 4; - *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_1MB; - *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_2MB; - *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_5MB; - *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_11MB; - } - - /* We may add an option for custom rates that specific HW might support */ - *tag_p = tag; -} - -static void ieee80211_MFIE_Grate(struct ieee80211_device *ieee, u8 **tag_p) -{ - u8 *tag = *tag_p; - - if (ieee->modulation & IEEE80211_OFDM_MODULATION) { - *tag++ = MFIE_TYPE_RATES_EX; - *tag++ = 8; - *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_6MB; - *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_9MB; - *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_12MB; - *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_18MB; - *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_24MB; - *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_36MB; - *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_48MB; - *tag++ = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_54MB; - - } - /* We may add an option for custom rates that specific HW might support */ - *tag_p = tag; -} - -static void ieee80211_WMM_Info(struct ieee80211_device *ieee, u8 **tag_p) -{ - u8 *tag = *tag_p; - - *tag++ = MFIE_TYPE_GENERIC; /* 0 */ - *tag++ = 7; - *tag++ = 0x00; - *tag++ = 0x50; - *tag++ = 0xf2; - *tag++ = 0x02; /* 5 */ - *tag++ = 0x00; - *tag++ = 0x01; -#ifdef SUPPORT_USPD - if (ieee->current_network.wmm_info & 0x80) - *tag++ = 0x0f|MAX_SP_Len; - else - *tag++ = MAX_SP_Len; -#else - *tag++ = MAX_SP_Len; -#endif - *tag_p = tag; -} - -static void ieee80211_TURBO_Info(struct ieee80211_device *ieee, u8 **tag_p) -{ - u8 *tag = *tag_p; - *tag++ = MFIE_TYPE_GENERIC; /* 0 */ - *tag++ = 7; - *tag++ = 0x00; - *tag++ = 0xe0; - *tag++ = 0x4c; - *tag++ = 0x01; /* 5 */ - *tag++ = 0x02; - *tag++ = 0x11; - *tag++ = 0x00; - *tag_p = tag; - printk(KERN_ALERT "This is enable turbo mode IE process\n"); -} - -static void enqueue_mgmt(struct ieee80211_device *ieee, struct sk_buff *skb) -{ - int nh; - nh = (ieee->mgmt_queue_head + 1) % MGMT_QUEUE_NUM; - - ieee->mgmt_queue_head = nh; - ieee->mgmt_queue_ring[nh] = skb; -} - -static struct sk_buff *dequeue_mgmt(struct ieee80211_device *ieee) -{ - struct sk_buff *ret; - - if (ieee->mgmt_queue_tail == ieee->mgmt_queue_head) - return NULL; - - ret = ieee->mgmt_queue_ring[ieee->mgmt_queue_tail]; - - ieee->mgmt_queue_tail = - (ieee->mgmt_queue_tail + 1) % MGMT_QUEUE_NUM; - - return ret; -} - -static void init_mgmt_queue(struct ieee80211_device *ieee) -{ - ieee->mgmt_queue_tail = ieee->mgmt_queue_head = 0; -} - -void ieee80211_sta_wakeup(struct ieee80211_device *ieee, short nl); - -inline void softmac_mgmt_xmit(struct sk_buff *skb, - struct ieee80211_device *ieee) -{ - unsigned long flags; - short single = ieee->softmac_features & IEEE_SOFTMAC_SINGLE_QUEUE; - struct ieee80211_hdr_3addr *header = - (struct ieee80211_hdr_3addr *) skb->data; - - spin_lock_irqsave(&ieee->lock, flags); - - /* called with 2nd param 0, no mgmt lock required */ - ieee80211_sta_wakeup(ieee, 0); - - if (single) { - if (ieee->queue_stop) { - enqueue_mgmt(ieee, skb); - } else { - header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0]<<4); - - if (ieee->seq_ctrl[0] == 0xFFF) - ieee->seq_ctrl[0] = 0; - else - ieee->seq_ctrl[0]++; - - /* avoid watchdog triggers */ - ieee->dev->trans_start = jiffies; - ieee->softmac_data_hard_start_xmit(skb, ieee->dev, ieee->basic_rate); - } - - spin_unlock_irqrestore(&ieee->lock, flags); - } else { - spin_unlock_irqrestore(&ieee->lock, flags); - spin_lock_irqsave(&ieee->mgmt_tx_lock, flags); - - header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4); - - if (ieee->seq_ctrl[0] == 0xFFF) - ieee->seq_ctrl[0] = 0; - else - ieee->seq_ctrl[0]++; - - /* avoid watchdog triggers */ - ieee->dev->trans_start = jiffies; - ieee->softmac_hard_start_xmit(skb, ieee->dev); - - spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags); - } -} - -inline void softmac_ps_mgmt_xmit(struct sk_buff *skb, - struct ieee80211_device *ieee) -{ - short single = ieee->softmac_features & IEEE_SOFTMAC_SINGLE_QUEUE; - struct ieee80211_hdr_3addr *header = - (struct ieee80211_hdr_3addr *) skb->data; - - if (single) { - header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4); - - if (ieee->seq_ctrl[0] == 0xFFF) - ieee->seq_ctrl[0] = 0; - else - ieee->seq_ctrl[0]++; - - /* avoid watchdog triggers */ - ieee->dev->trans_start = jiffies; - ieee->softmac_data_hard_start_xmit(skb, ieee->dev, ieee->basic_rate); - } else { - header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4); - - if (ieee->seq_ctrl[0] == 0xFFF) - ieee->seq_ctrl[0] = 0; - else - ieee->seq_ctrl[0]++; - - /* avoid watchdog triggers */ - ieee->dev->trans_start = jiffies; - ieee->softmac_hard_start_xmit(skb, ieee->dev); - } -} - -inline struct sk_buff * -ieee80211_disassociate_skb(struct ieee80211_network *beacon, - struct ieee80211_device *ieee, u8 asRsn) -{ - struct sk_buff *skb; - struct ieee80211_disassoc_frame *disass; - - skb = dev_alloc_skb(sizeof(struct ieee80211_disassoc_frame)); - if (!skb) - return NULL; - - disass = (struct ieee80211_disassoc_frame *) skb_put(skb, sizeof(struct ieee80211_disassoc_frame)); - disass->header.frame_control = cpu_to_le16(IEEE80211_STYPE_DISASSOC); - disass->header.duration_id = 0; - - memcpy(disass->header.addr1, beacon->bssid, ETH_ALEN); - memcpy(disass->header.addr2, ieee->dev->dev_addr, ETH_ALEN); - memcpy(disass->header.addr3, beacon->bssid, ETH_ALEN); - - disass->reasoncode = asRsn; - return skb; -} - -void SendDisassociation(struct ieee80211_device *ieee, u8 *asSta, u8 asRsn) -{ - struct ieee80211_network *beacon = &ieee->current_network; - struct sk_buff *skb; - skb = ieee80211_disassociate_skb(beacon, ieee, asRsn); - if (skb) - softmac_mgmt_xmit(skb, ieee); -} - -inline struct sk_buff *ieee80211_probe_req(struct ieee80211_device *ieee) -{ - unsigned int len, rate_len; - u8 *tag; - struct sk_buff *skb; - struct ieee80211_probe_request *req; - - len = ieee->current_network.ssid_len; - - rate_len = ieee80211_MFIE_rate_len(ieee); - - skb = dev_alloc_skb(sizeof(struct ieee80211_probe_request) + - 2 + len + rate_len); - if (!skb) - return NULL; - - req = (struct ieee80211_probe_request *) skb_put(skb, sizeof(struct ieee80211_probe_request)); - req->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ); - req->header.duration_id = 0; /* FIXME: is this OK ? */ - - memset(req->header.addr1, 0xff, ETH_ALEN); - memcpy(req->header.addr2, ieee->dev->dev_addr, ETH_ALEN); - memset(req->header.addr3, 0xff, ETH_ALEN); - - tag = (u8 *) skb_put(skb, len + 2 + rate_len); - - *tag++ = MFIE_TYPE_SSID; - *tag++ = len; - memcpy(tag, ieee->current_network.ssid, len); - tag += len; - ieee80211_MFIE_Brate(ieee, &tag); - ieee80211_MFIE_Grate(ieee, &tag); - - return skb; -} - -struct sk_buff *ieee80211_get_beacon_(struct ieee80211_device *ieee); - -static void ieee80211_send_beacon(struct ieee80211_device *ieee) -{ - struct sk_buff *skb; - - skb = ieee80211_get_beacon_(ieee); - - if (skb) { - softmac_mgmt_xmit(skb, ieee); - ieee->softmac_stats.tx_beacons++; - dev_kfree_skb_any(skb); - } - - ieee->beacon_timer.expires = jiffies + - (MSECS(ieee->current_network.beacon_interval - 5)); - - if (ieee->beacon_txing) - add_timer(&ieee->beacon_timer); -} - - -static void ieee80211_send_beacon_cb(unsigned long _ieee) -{ - struct ieee80211_device *ieee = - (struct ieee80211_device *) _ieee; - unsigned long flags; - - spin_lock_irqsave(&ieee->beacon_lock, flags); - ieee80211_send_beacon(ieee); - spin_unlock_irqrestore(&ieee->beacon_lock, flags); -} - -static void ieee80211_send_probe(struct ieee80211_device *ieee) -{ - struct sk_buff *skb; - - skb = ieee80211_probe_req(ieee); - if (skb) { - softmac_mgmt_xmit(skb, ieee); - ieee->softmac_stats.tx_probe_rq++; - } -} - -static void ieee80211_send_probe_requests(struct ieee80211_device *ieee) -{ - if (ieee->active_scan && (ieee->softmac_features & IEEE_SOFTMAC_PROBERQ)) { - ieee80211_send_probe(ieee); - ieee80211_send_probe(ieee); - } -} - -/* this performs syncro scan blocking the caller until all channels - * in the allowed channel map has been checked. - */ -static void ieee80211_softmac_scan_syncro(struct ieee80211_device *ieee) -{ - short ch = 0; - u8 channel_map[MAX_CHANNEL_NUMBER+1]; - memcpy(channel_map, GET_DOT11D_INFO(ieee)->channel_map, MAX_CHANNEL_NUMBER+1); - down(&ieee->scan_sem); - - while (1) { - do { - ch++; - if (ch > MAX_CHANNEL_NUMBER) - goto out; /* scan completed */ - - } while (!channel_map[ch]); - /* this function can be called in two situations - * 1- We have switched to ad-hoc mode and we are - * performing a complete syncro scan before conclude - * there are no interesting cell and to create a - * new one. In this case the link state is - * IEEE80211_NOLINK until we found an interesting cell. - * If so the ieee8021_new_net, called by the RX path - * will set the state to IEEE80211_LINKED, so we stop - * scanning - * 2- We are linked and the root uses run iwlist scan. - * So we switch to IEEE80211_LINKED_SCANNING to remember - * that we are still logically linked (not interested in - * new network events, despite for updating the net list, - * but we are temporarily 'unlinked' as the driver shall - * not filter RX frames and the channel is changing. - * So the only situation in witch are interested is to check - * if the state become LINKED because of the #1 situation - */ - - if (ieee->state == IEEE80211_LINKED) - goto out; - - ieee->set_chan(ieee->dev, ch); - if (channel_map[ch] == 1) - ieee80211_send_probe_requests(ieee); - - /* this prevent excessive time wait when we - * need to wait for a syncro scan to end.. - */ - if (ieee->sync_scan_hurryup) - goto out; - - msleep_interruptible_rtl(IEEE80211_SOFTMAC_SCAN_TIME); - } -out: - ieee->sync_scan_hurryup = 0; - up(&ieee->scan_sem); - if (IS_DOT11D_ENABLE(ieee)) - DOT11D_ScanComplete(ieee); -} - -void ieee80211_softmac_ips_scan_syncro(struct ieee80211_device *ieee) -{ - int ch; - unsigned int watch_dog = 0; - u8 channel_map[MAX_CHANNEL_NUMBER+1]; - memcpy(channel_map, GET_DOT11D_INFO(ieee)->channel_map, MAX_CHANNEL_NUMBER+1); - down(&ieee->scan_sem); - ch = ieee->current_network.channel; - - while (1) { - /* this function can be called in two situations - * 1- We have switched to ad-hoc mode and we are - * performing a complete syncro scan before conclude - * there are no interesting cell and to create a - * new one. In this case the link state is - * IEEE80211_NOLINK until we found an interesting cell. - * If so the ieee8021_new_net, called by the RX path - * will set the state to IEEE80211_LINKED, so we stop - * scanning - * 2- We are linked and the root uses run iwlist scan. - * So we switch to IEEE80211_LINKED_SCANNING to remember - * that we are still logically linked (not interested in - * new network events, despite for updating the net list, - * but we are temporarily 'unlinked' as the driver shall - * not filter RX frames and the channel is changing. - * So the only situation in witch are interested is to check - * if the state become LINKED because of the #1 situation - */ - if (ieee->state == IEEE80211_LINKED) - goto out; - - if (channel_map[ieee->current_network.channel] > 0) - ieee->set_chan(ieee->dev, ieee->current_network.channel); - - if (channel_map[ieee->current_network.channel] == 1) - ieee80211_send_probe_requests(ieee); - - msleep_interruptible_rtl(IEEE80211_SOFTMAC_SCAN_TIME); - - do { - if (watch_dog++ >= MAX_CHANNEL_NUMBER) - goto out; /* scan completed */ - - ieee->current_network.channel = (ieee->current_network.channel + 1)%MAX_CHANNEL_NUMBER; - } while (!channel_map[ieee->current_network.channel]); - } -out: - ieee->actscanning = false; - up(&ieee->scan_sem); - if (IS_DOT11D_ENABLE(ieee)) - DOT11D_ScanComplete(ieee); -} - -static void ieee80211_softmac_scan_wq(struct work_struct *work) -{ - struct delayed_work *dwork = to_delayed_work(work); - struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, softmac_scan_wq); - static short watchdog; - u8 channel_map[MAX_CHANNEL_NUMBER+1]; - memcpy(channel_map, GET_DOT11D_INFO(ieee)->channel_map, MAX_CHANNEL_NUMBER+1); - down(&ieee->scan_sem); - - do { - ieee->current_network.channel = - (ieee->current_network.channel + 1) % MAX_CHANNEL_NUMBER; - if (watchdog++ > MAX_CHANNEL_NUMBER) - goto out; /* no good chans */ - } while (!channel_map[ieee->current_network.channel]); - - if (ieee->scanning == 0) { - printk("error out, scanning = 0\n"); - goto out; - } - ieee->set_chan(ieee->dev, ieee->current_network.channel); - if (channel_map[ieee->current_network.channel] == 1) - ieee80211_send_probe_requests(ieee); - - queue_delayed_work(ieee->wq, &ieee->softmac_scan_wq, IEEE80211_SOFTMAC_SCAN_TIME); - up(&ieee->scan_sem); - return; -out: - ieee->actscanning = false; - watchdog = 0; - ieee->scanning = 0; - up(&ieee->scan_sem); - - if (IS_DOT11D_ENABLE(ieee)) - DOT11D_ScanComplete(ieee); - return; -} - -static void ieee80211_beacons_start(struct ieee80211_device *ieee) -{ - unsigned long flags; - - spin_lock_irqsave(&ieee->beacon_lock, flags); - - ieee->beacon_txing = 1; - ieee80211_send_beacon(ieee); - - spin_unlock_irqrestore(&ieee->beacon_lock, flags); -} - -static void ieee80211_beacons_stop(struct ieee80211_device *ieee) -{ - unsigned long flags; - - spin_lock_irqsave(&ieee->beacon_lock, flags); - - ieee->beacon_txing = 0; - del_timer_sync(&ieee->beacon_timer); - - spin_unlock_irqrestore(&ieee->beacon_lock, flags); -} - -void ieee80211_stop_send_beacons(struct ieee80211_device *ieee) -{ - if (ieee->stop_send_beacons) - ieee->stop_send_beacons(ieee->dev); - if (ieee->softmac_features & IEEE_SOFTMAC_BEACONS) - ieee80211_beacons_stop(ieee); -} - -void ieee80211_start_send_beacons(struct ieee80211_device *ieee) -{ - if (ieee->start_send_beacons) - ieee->start_send_beacons(ieee->dev); - if (ieee->softmac_features & IEEE_SOFTMAC_BEACONS) - ieee80211_beacons_start(ieee); -} - -static void ieee80211_softmac_stop_scan(struct ieee80211_device *ieee) -{ - down(&ieee->scan_sem); - - if (ieee->scanning == 1) { - ieee->scanning = 0; - cancel_delayed_work(&ieee->softmac_scan_wq); - } - - up(&ieee->scan_sem); -} - -void ieee80211_stop_scan(struct ieee80211_device *ieee) -{ - if (ieee->softmac_features & IEEE_SOFTMAC_SCAN) - ieee80211_softmac_stop_scan(ieee); - else - ieee->stop_scan(ieee->dev); -} - -/* called with ieee->lock held */ -void ieee80211_rtl_start_scan(struct ieee80211_device *ieee) -{ - if (IS_DOT11D_ENABLE(ieee)) { - if (IS_COUNTRY_IE_VALID(ieee)) - RESET_CIE_WATCHDOG(ieee); - } - - if (ieee->softmac_features & IEEE_SOFTMAC_SCAN) { - if (ieee->scanning == 0) { - ieee->scanning = 1; -#if 1 - queue_delayed_work(ieee->wq, &ieee->softmac_scan_wq, 0); -#endif - } - }else - ieee->start_scan(ieee->dev); -} - -/* called with wx_sem held */ -void ieee80211_start_scan_syncro(struct ieee80211_device *ieee) -{ - if (IS_DOT11D_ENABLE(ieee)) { - if (IS_COUNTRY_IE_VALID(ieee)) - RESET_CIE_WATCHDOG(ieee); - } - ieee->sync_scan_hurryup = 0; - - if (ieee->softmac_features & IEEE_SOFTMAC_SCAN) - ieee80211_softmac_scan_syncro(ieee); - else - ieee->scan_syncro(ieee->dev); -} - -inline struct sk_buff * -ieee80211_authentication_req(struct ieee80211_network *beacon, - struct ieee80211_device *ieee, int challengelen) -{ - struct sk_buff *skb; - struct ieee80211_authentication *auth; - - skb = dev_alloc_skb(sizeof(struct ieee80211_authentication) + challengelen); - - if (!skb) - return NULL; - - auth = (struct ieee80211_authentication *) - skb_put(skb, sizeof(struct ieee80211_authentication)); - - auth->header.frame_ctl = IEEE80211_STYPE_AUTH; - if (challengelen) - auth->header.frame_ctl |= IEEE80211_FCTL_WEP; - - auth->header.duration_id = 0x013a; /* FIXME */ - - memcpy(auth->header.addr1, beacon->bssid, ETH_ALEN); - memcpy(auth->header.addr2, ieee->dev->dev_addr, ETH_ALEN); - memcpy(auth->header.addr3, beacon->bssid, ETH_ALEN); - - auth->algorithm = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY; - - auth->transaction = cpu_to_le16(ieee->associate_seq); - ieee->associate_seq++; - - auth->status = cpu_to_le16(WLAN_STATUS_SUCCESS); - - return skb; -} - -static struct sk_buff *ieee80211_probe_resp(struct ieee80211_device *ieee, - u8 *dest) -{ - u8 *tag; - int beacon_size; - struct ieee80211_probe_response *beacon_buf; - struct sk_buff *skb; - int encrypt; - int atim_len, erp_len; - struct ieee80211_crypt_data *crypt; - - char *ssid = ieee->current_network.ssid; - int ssid_len = ieee->current_network.ssid_len; - int rate_len = ieee->current_network.rates_len+2; - int rate_ex_len = ieee->current_network.rates_ex_len; - int wpa_ie_len = ieee->wpa_ie_len; - if (rate_ex_len > 0) - rate_ex_len += 2; - - if (ieee->current_network.capability & WLAN_CAPABILITY_IBSS) - atim_len = 4; - else - atim_len = 0; - - if (ieee80211_is_54g(&ieee->current_network)) - erp_len = 3; - else - erp_len = 0; - - beacon_size = sizeof(struct ieee80211_probe_response)+ - ssid_len - +3 /* channel */ - +rate_len - +rate_ex_len - +atim_len - +wpa_ie_len - +erp_len; - - skb = dev_alloc_skb(beacon_size); - - if (!skb) - return NULL; - - beacon_buf = (struct ieee80211_probe_response *) skb_put(skb, beacon_size); - - memcpy(beacon_buf->header.addr1, dest, ETH_ALEN); - memcpy(beacon_buf->header.addr2, ieee->dev->dev_addr, ETH_ALEN); - memcpy(beacon_buf->header.addr3, ieee->current_network.bssid, ETH_ALEN); - - beacon_buf->header.duration_id = 0; /* FIXME */ - beacon_buf->beacon_interval = - cpu_to_le16(ieee->current_network.beacon_interval); - beacon_buf->capability = - cpu_to_le16(ieee->current_network.capability & WLAN_CAPABILITY_IBSS); - - if (ieee->short_slot && (ieee->current_network.capability & WLAN_CAPABILITY_SHORT_SLOT)) - beacon_buf->capability |= cpu_to_le16(WLAN_CAPABILITY_SHORT_SLOT); - - crypt = ieee->crypt[ieee->tx_keyidx]; - - encrypt = ieee->host_encrypt && crypt && crypt->ops && - ((0 == strcmp(crypt->ops->name, "WEP")) || wpa_ie_len); - - if (encrypt) - beacon_buf->capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY); - - - beacon_buf->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_PROBE_RESP); - - beacon_buf->info_element.id = MFIE_TYPE_SSID; - beacon_buf->info_element.len = ssid_len; - - tag = (u8 *) beacon_buf->info_element.data; - - memcpy(tag, ssid, ssid_len); - - tag += ssid_len; - - *(tag++) = MFIE_TYPE_RATES; - *(tag++) = rate_len - 2; - memcpy(tag, ieee->current_network.rates, rate_len-2); - tag += rate_len - 2; - - *(tag++) = MFIE_TYPE_DS_SET; - *(tag++) = 1; - *(tag++) = ieee->current_network.channel; - - if (atim_len) { - *(tag++) = MFIE_TYPE_IBSS_SET; - *(tag++) = 2; - *((u16 *)(tag)) = cpu_to_le16(ieee->current_network.atim_window); - tag += 2; - } - - if (erp_len) { - *(tag++) = MFIE_TYPE_ERP; - *(tag++) = 1; - *(tag++) = 0; - } - - if (rate_ex_len) { - *(tag++) = MFIE_TYPE_RATES_EX; - *(tag++) = rate_ex_len-2; - memcpy(tag, ieee->current_network.rates_ex, rate_ex_len-2); - tag += rate_ex_len - 2; - } - - if (wpa_ie_len) { - if (ieee->iw_mode == IW_MODE_ADHOC) { - /* as Windows will set pairwise key same as the group - * key which is not allowed in Linux, so set this for - * IOT issue. - */ - memcpy(&ieee->wpa_ie[14], &ieee->wpa_ie[8], 4); - } - - memcpy(tag, ieee->wpa_ie, ieee->wpa_ie_len); - } - skb->dev = ieee->dev; - return skb; -} - -static struct sk_buff *ieee80211_assoc_resp(struct ieee80211_device *ieee, - u8 *dest) -{ - struct sk_buff *skb; - u8 *tag; - - struct ieee80211_crypt_data *crypt; - struct ieee80211_assoc_response_frame *assoc; - short encrypt; - - unsigned int rate_len = ieee80211_MFIE_rate_len(ieee); - int len = sizeof(struct ieee80211_assoc_response_frame) + rate_len; - - skb = dev_alloc_skb(len); - - if (!skb) - return NULL; - - assoc = (struct ieee80211_assoc_response_frame *) - skb_put(skb, sizeof(struct ieee80211_assoc_response_frame)); - - assoc->header.frame_control = cpu_to_le16(IEEE80211_STYPE_ASSOC_RESP); - memcpy(assoc->header.addr1, dest, ETH_ALEN); - memcpy(assoc->header.addr3, ieee->dev->dev_addr, ETH_ALEN); - memcpy(assoc->header.addr2, ieee->dev->dev_addr, ETH_ALEN); - assoc->capability = cpu_to_le16(ieee->iw_mode == IW_MODE_MASTER ? - WLAN_CAPABILITY_BSS : WLAN_CAPABILITY_IBSS); - - if (ieee->short_slot) - assoc->capability |= cpu_to_le16(WLAN_CAPABILITY_SHORT_SLOT); - - if (ieee->host_encrypt) - crypt = ieee->crypt[ieee->tx_keyidx]; - else - crypt = NULL; - - encrypt = (crypt && crypt->ops); - - if (encrypt) - assoc->capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY); - - assoc->status = 0; - assoc->aid = cpu_to_le16(ieee->assoc_id); - if (ieee->assoc_id == 0x2007) - ieee->assoc_id = 0; - else - ieee->assoc_id++; - - tag = (u8 *) skb_put(skb, rate_len); - - ieee80211_MFIE_Brate(ieee, &tag); - ieee80211_MFIE_Grate(ieee, &tag); - - return skb; -} - -static struct sk_buff *ieee80211_auth_resp(struct ieee80211_device *ieee, - int status, u8 *dest) -{ - struct sk_buff *skb; - struct ieee80211_authentication *auth; - - skb = dev_alloc_skb(sizeof(struct ieee80211_authentication)+1); - - if (!skb) - return NULL; - - skb->len = sizeof(struct ieee80211_authentication); - - auth = (struct ieee80211_authentication *)skb->data; - - auth->status = cpu_to_le16(status); - auth->transaction = cpu_to_le16(2); - auth->algorithm = cpu_to_le16(WLAN_AUTH_OPEN); - - memcpy(auth->header.addr3, ieee->dev->dev_addr, ETH_ALEN); - memcpy(auth->header.addr2, ieee->dev->dev_addr, ETH_ALEN); - memcpy(auth->header.addr1, dest, ETH_ALEN); - auth->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_AUTH); - return skb; -} - -static struct sk_buff *ieee80211_null_func(struct ieee80211_device *ieee, short pwr) -{ - struct sk_buff *skb; - struct ieee80211_hdr_3addr *hdr; - - skb = dev_alloc_skb(sizeof(struct ieee80211_hdr_3addr)); - - if (!skb) - return NULL; - - hdr = (struct ieee80211_hdr_3addr *)skb_put(skb, sizeof(struct ieee80211_hdr_3addr)); - - memcpy(hdr->addr1, ieee->current_network.bssid, ETH_ALEN); - memcpy(hdr->addr2, ieee->dev->dev_addr, ETH_ALEN); - memcpy(hdr->addr3, ieee->current_network.bssid, ETH_ALEN); - - hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | - IEEE80211_STYPE_NULLFUNC | IEEE80211_FCTL_TODS | - (pwr ? IEEE80211_FCTL_PM:0)); - - return skb; -} - -static void ieee80211_resp_to_assoc_rq(struct ieee80211_device *ieee, u8 *dest) -{ - struct sk_buff *buf = ieee80211_assoc_resp(ieee, dest); - - if (buf) { - softmac_mgmt_xmit(buf, ieee); - dev_kfree_skb_any(buf); - } -} - -static void ieee80211_resp_to_auth(struct ieee80211_device *ieee, int s, u8 *dest) -{ - struct sk_buff *buf = ieee80211_auth_resp(ieee, s, dest); - - if (buf) { - softmac_mgmt_xmit(buf, ieee); - dev_kfree_skb_any(buf); - } -} - -static void ieee80211_resp_to_probe(struct ieee80211_device *ieee, u8 *dest) -{ - struct sk_buff *buf = ieee80211_probe_resp(ieee, dest); - - if (buf) { - softmac_mgmt_xmit(buf, ieee); - dev_kfree_skb_any(buf); - } -} - -inline struct sk_buff * -ieee80211_association_req(struct ieee80211_network *beacon, - struct ieee80211_device *ieee) -{ - struct sk_buff *skb; - - struct ieee80211_assoc_request_frame *hdr; - u8 *tag; - unsigned int wpa_len = beacon->wpa_ie_len; -#if 1 - /* for testing purpose */ - unsigned int rsn_len = beacon->rsn_ie_len; -#endif - unsigned int rate_len = ieee80211_MFIE_rate_len(ieee); - unsigned int wmm_info_len = beacon->QoS_Enable?9:0; - unsigned int turbo_info_len = beacon->Turbo_Enable?9:0; - - u8 encry_proto = ieee->wpax_type_notify & 0xff; - - int len = 0; - - /* [0] Notify type of encryption: WPA/WPA2 - * [1] pair wise type - * [2] authen type - */ - if (ieee->wpax_type_set) { - if (IEEE_PROTO_WPA == encry_proto) { - rsn_len = 0; - } else if (IEEE_PROTO_RSN == encry_proto) { - wpa_len = 0; - } - } - len = sizeof(struct ieee80211_assoc_request_frame)+ - + beacon->ssid_len /* essid tagged val */ - + rate_len /* rates tagged val */ - + wpa_len - + rsn_len - + wmm_info_len - + turbo_info_len; - - skb = dev_alloc_skb(len); - - if (!skb) - return NULL; - - hdr = (struct ieee80211_assoc_request_frame *) - skb_put(skb, sizeof(struct ieee80211_assoc_request_frame)); - - hdr->header.frame_control = IEEE80211_STYPE_ASSOC_REQ; - hdr->header.duration_id = 37; /* FIXME */ - memcpy(hdr->header.addr1, beacon->bssid, ETH_ALEN); - memcpy(hdr->header.addr2, ieee->dev->dev_addr, ETH_ALEN); - memcpy(hdr->header.addr3, beacon->bssid, ETH_ALEN); - memcpy(ieee->ap_mac_addr, beacon->bssid, ETH_ALEN); /* for HW security */ - - hdr->capability = cpu_to_le16(WLAN_CAPABILITY_BSS); - if (beacon->capability & WLAN_CAPABILITY_PRIVACY) - hdr->capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY); - if (beacon->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) - hdr->capability |= cpu_to_le16(WLAN_CAPABILITY_SHORT_PREAMBLE); - - if (ieee->short_slot) - hdr->capability |= cpu_to_le16(WLAN_CAPABILITY_SHORT_SLOT); - - hdr->listen_interval = 0xa; /* FIXME */ - - hdr->info_element.id = MFIE_TYPE_SSID; - - hdr->info_element.len = beacon->ssid_len; - tag = skb_put(skb, beacon->ssid_len); - memcpy(tag, beacon->ssid, beacon->ssid_len); - - tag = skb_put(skb, rate_len); - - ieee80211_MFIE_Brate(ieee, &tag); - ieee80211_MFIE_Grate(ieee, &tag); - - /* add rsn==0 condition for ap's mix security mode(wpa+wpa2) - * choose AES encryption as default algorithm while using mixed mode. - */ - - tag = skb_put(skb, ieee->wpa_ie_len); - memcpy(tag, ieee->wpa_ie, ieee->wpa_ie_len); - - tag = skb_put(skb, wmm_info_len); - if (wmm_info_len) - ieee80211_WMM_Info(ieee, &tag); - - tag = skb_put(skb, turbo_info_len); - if (turbo_info_len) - ieee80211_TURBO_Info(ieee, &tag); - - return skb; -} - -void ieee80211_associate_abort(struct ieee80211_device *ieee) -{ - unsigned long flags; - spin_lock_irqsave(&ieee->lock, flags); - - ieee->associate_seq++; - - /* don't scan, and avoid to have the RX path possibly - * try again to associate. Even do not react to AUTH or - * ASSOC response. Just wait for the retry wq to be scheduled. - * Here we will check if there are good nets to associate - * with, so we retry or just get back to NO_LINK and scanning - */ - if (ieee->state == IEEE80211_ASSOCIATING_AUTHENTICATING) { - IEEE80211_DEBUG_MGMT("Authentication failed\n"); - ieee->softmac_stats.no_auth_rs++; - } else { - IEEE80211_DEBUG_MGMT("Association failed\n"); - ieee->softmac_stats.no_ass_rs++; - } - - ieee->state = IEEE80211_ASSOCIATING_RETRY; - - queue_delayed_work(ieee->wq, &ieee->associate_retry_wq, IEEE80211_SOFTMAC_ASSOC_RETRY_TIME); - - spin_unlock_irqrestore(&ieee->lock, flags); -} - -static void ieee80211_associate_abort_cb(unsigned long dev) -{ - ieee80211_associate_abort((struct ieee80211_device *) dev); -} - -static void ieee80211_associate_step1(struct ieee80211_device *ieee) -{ - struct ieee80211_network *beacon = &ieee->current_network; - struct sk_buff *skb; - - IEEE80211_DEBUG_MGMT("Stopping scan\n"); - ieee->softmac_stats.tx_auth_rq++; - skb = ieee80211_authentication_req(beacon, ieee, 0); - if (!skb) { - ieee80211_associate_abort(ieee); - } else { - ieee->state = IEEE80211_ASSOCIATING_AUTHENTICATING; - IEEE80211_DEBUG_MGMT("Sending authentication request\n"); - softmac_mgmt_xmit(skb, ieee); - /* BUGON when you try to add_timer twice, using mod_timer may - * be better. - */ - if (!timer_pending(&ieee->associate_timer)) { - ieee->associate_timer.expires = jiffies + (HZ / 2); - add_timer(&ieee->associate_timer); - } - /* If call dev_kfree_skb_any,a warning will ocur.... - * KERNEL: assertion (!atomic_read(&skb->users)) failed at - * net/core/dev.c (1708) - */ - } -} - -static void ieee80211_rtl_auth_challenge(struct ieee80211_device *ieee, u8 *challenge, - int chlen) -{ - u8 *c; - struct sk_buff *skb; - struct ieee80211_network *beacon = &ieee->current_network; - del_timer_sync(&ieee->associate_timer); - ieee->associate_seq++; - ieee->softmac_stats.tx_auth_rq++; - - skb = ieee80211_authentication_req(beacon, ieee, chlen+2); - if (!skb) - ieee80211_associate_abort(ieee); - else { - c = skb_put(skb, chlen+2); - *(c++) = MFIE_TYPE_CHALLENGE; - *(c++) = chlen; - memcpy(c, challenge, chlen); - - IEEE80211_DEBUG_MGMT("Sending authentication challenge response\n"); - - ieee80211_encrypt_fragment(ieee, skb, sizeof(struct ieee80211_hdr_3addr)); - - softmac_mgmt_xmit(skb, ieee); - if (!timer_pending(&ieee->associate_timer)) { - ieee->associate_timer.expires = jiffies + (HZ / 2); - add_timer(&ieee->associate_timer); - } - dev_kfree_skb_any(skb); - } - kfree(challenge); -} - -static void ieee80211_associate_step2(struct ieee80211_device *ieee) -{ - struct sk_buff *skb; - struct ieee80211_network *beacon = &ieee->current_network; - - del_timer_sync(&ieee->associate_timer); - - IEEE80211_DEBUG_MGMT("Sending association request\n"); - ieee->softmac_stats.tx_ass_rq++; - skb = ieee80211_association_req(beacon, ieee); - if (!skb) - ieee80211_associate_abort(ieee); - else { - softmac_mgmt_xmit(skb, ieee); - if (!timer_pending(&ieee->associate_timer)) { - ieee->associate_timer.expires = jiffies + (HZ / 2); - add_timer(&ieee->associate_timer); - } - } -} - -static void ieee80211_associate_complete_wq(struct work_struct *work) -{ - struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, associate_complete_wq); - - printk(KERN_INFO "Associated successfully\n"); - if (ieee80211_is_54g(&ieee->current_network) && - (ieee->modulation & IEEE80211_OFDM_MODULATION)) { - ieee->rate = 540; - printk(KERN_INFO"Using G rates\n"); - } else { - ieee->rate = 110; - printk(KERN_INFO"Using B rates\n"); - } - ieee->link_change(ieee->dev); - notify_wx_assoc_event(ieee); - if (ieee->data_hard_resume) - ieee->data_hard_resume(ieee->dev); - netif_carrier_on(ieee->dev); -} - -static void ieee80211_associate_complete(struct ieee80211_device *ieee) -{ - del_timer_sync(&ieee->associate_timer); - - ieee->state = IEEE80211_LINKED; - IEEE80211_DEBUG_MGMT("Successfully associated\n"); - - queue_work(ieee->wq, &ieee->associate_complete_wq); -} - -static void ieee80211_associate_procedure_wq(struct work_struct *work) -{ - struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, associate_procedure_wq); - - ieee->sync_scan_hurryup = 1; - down(&ieee->wx_sem); - - if (ieee->data_hard_stop) - ieee->data_hard_stop(ieee->dev); - - ieee80211_stop_scan(ieee); - ieee->set_chan(ieee->dev, ieee->current_network.channel); - - ieee->associate_seq = 1; - ieee80211_associate_step1(ieee); - - up(&ieee->wx_sem); -} - -inline void ieee80211_softmac_new_net(struct ieee80211_device *ieee, - struct ieee80211_network *net) -{ - u8 tmp_ssid[IW_ESSID_MAX_SIZE+1]; - int tmp_ssid_len = 0; - - short apset, ssidset, ssidbroad, apmatch, ssidmatch; - - /* we are interested in new new only if we are not associated - * and we are not associating / authenticating - */ - if (ieee->state != IEEE80211_NOLINK) - return; - - if ((ieee->iw_mode == IW_MODE_INFRA) && !(net->capability & WLAN_CAPABILITY_BSS)) - return; - - if ((ieee->iw_mode == IW_MODE_ADHOC) && !(net->capability & WLAN_CAPABILITY_IBSS)) - return; - - if (ieee->iw_mode == IW_MODE_INFRA || ieee->iw_mode == IW_MODE_ADHOC) { - /* if the user specified the AP MAC, we need also the essid - * This could be obtained by beacons or, if the network does not - * broadcast it, it can be put manually. - */ - apset = ieee->wap_set; - ssidset = ieee->ssid_set; - ssidbroad = !(net->ssid_len == 0 || net->ssid[0] == '\0'); - apmatch = (memcmp(ieee->current_network.bssid, net->bssid, ETH_ALEN) == 0); - - if (ieee->current_network.ssid_len != net->ssid_len) - ssidmatch = 0; - else - ssidmatch = (0 == strncmp(ieee->current_network.ssid, net->ssid, net->ssid_len)); - - /* if the user set the AP check if match. - * if the network does not broadcast essid we check the user - * supplied ANY essid - * if the network does broadcast and the user does not set essid - * it is OK - * if the network does broadcast and the user did set essid - * chech if essid match - * (apset && apmatch && ((ssidset && ssidbroad && ssidmatch) || - * (ssidbroad && !ssidset) || (!ssidbroad && ssidset))) || - * if the ap is not set, check that the user set the bssid and - * the network does broadcast and that those two bssid matches - * (!apset && ssidset && ssidbroad && ssidmatch) - */ - if ((apset && apmatch && ((ssidset && ssidbroad && ssidmatch) || - (ssidbroad && !ssidset) || (!ssidbroad && ssidset))) || - (!apset && ssidset && ssidbroad && ssidmatch)) { - /* if the essid is hidden replace it with the - * essid provided by the user. - */ - if (!ssidbroad) { - strncpy(tmp_ssid, ieee->current_network.ssid, IW_ESSID_MAX_SIZE); - tmp_ssid_len = ieee->current_network.ssid_len; - } - memcpy(&ieee->current_network, net, sizeof(struct ieee80211_network)); - - if (!ssidbroad) { - strncpy(ieee->current_network.ssid, tmp_ssid, IW_ESSID_MAX_SIZE); - ieee->current_network.ssid_len = tmp_ssid_len; - } - printk(KERN_INFO"Linking with %s: channel is %d\n", ieee->current_network.ssid, ieee->current_network.channel); - - if (ieee->iw_mode == IW_MODE_INFRA) { - ieee->state = IEEE80211_ASSOCIATING; - ieee->beinretry = false; - queue_work(ieee->wq, &ieee->associate_procedure_wq); - } else { - if (ieee80211_is_54g(&ieee->current_network) && - (ieee->modulation & IEEE80211_OFDM_MODULATION)) { - ieee->rate = 540; - printk(KERN_INFO"Using G rates\n"); - } else { - ieee->rate = 110; - printk(KERN_INFO"Using B rates\n"); - } - ieee->state = IEEE80211_LINKED; - ieee->beinretry = false; - } - } - } -} - -void ieee80211_softmac_check_all_nets(struct ieee80211_device *ieee) -{ - unsigned long flags; - struct ieee80211_network *target; - - spin_lock_irqsave(&ieee->lock, flags); - list_for_each_entry(target, &ieee->network_list, list) { - /* if the state become different that NOLINK means - * we had found what we are searching for - */ - if (ieee->state != IEEE80211_NOLINK) - break; - - if (ieee->scan_age == 0 || time_after(target->last_scanned + ieee->scan_age, jiffies)) - ieee80211_softmac_new_net(ieee, target); - } - spin_unlock_irqrestore(&ieee->lock, flags); -} - -static inline u16 auth_parse(struct sk_buff *skb, u8 **challenge, int *chlen) -{ - struct ieee80211_authentication *a; - u8 *t; - if (skb->len < (sizeof(struct ieee80211_authentication) - sizeof(struct ieee80211_info_element))) { - IEEE80211_DEBUG_MGMT("invalid len in auth resp: %d\n", skb->len); - return 0xcafe; - } - *challenge = NULL; - a = (struct ieee80211_authentication *) skb->data; - if (skb->len > (sizeof(struct ieee80211_authentication) + 3)) { - t = skb->data + sizeof(struct ieee80211_authentication); - - if (*(t++) == MFIE_TYPE_CHALLENGE) { - *chlen = *(t++); - *challenge = kmemdup(t, *chlen, GFP_ATOMIC); - if (!*challenge) - return -ENOMEM; - } - } - return cpu_to_le16(a->status); -} - -static int auth_rq_parse(struct sk_buff *skb, u8 *dest) -{ - struct ieee80211_authentication *a; - - if (skb->len < (sizeof(struct ieee80211_authentication) - sizeof(struct ieee80211_info_element))) { - IEEE80211_DEBUG_MGMT("invalid len in auth request: %d\n", skb->len); - return -1; - } - a = (struct ieee80211_authentication *) skb->data; - - memcpy(dest, a->header.addr2, ETH_ALEN); - - if (le16_to_cpu(a->algorithm) != WLAN_AUTH_OPEN) - return WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG; - - return WLAN_STATUS_SUCCESS; -} - -static short probe_rq_parse(struct ieee80211_device *ieee, struct sk_buff *skb, - u8 *src) -{ - u8 *tag; - u8 *skbend; - u8 *ssid = NULL; - u8 ssidlen = 0; - - struct ieee80211_hdr_3addr *header = - (struct ieee80211_hdr_3addr *) skb->data; - - if (skb->len < sizeof(struct ieee80211_hdr_3addr)) - return -1; /* corrupted */ - - memcpy(src, header->addr2, ETH_ALEN); - - skbend = (u8 *)skb->data + skb->len; - - tag = skb->data + sizeof(struct ieee80211_hdr_3addr); - - while (tag+1 < skbend) { - if (*tag == 0) { - ssid = tag+2; - ssidlen = *(tag+1); - break; - } - tag++; /* point to the len field */ - tag = tag + *(tag); /* point to the last data byte of the tag */ - tag++; /* point to the next tag */ - } - - if (ssidlen == 0) - return 1; - - if (!ssid) - return 1; /* ssid not found in tagged param */ - - return (!strncmp(ssid, ieee->current_network.ssid, ssidlen)); - -} - -static int assoc_rq_parse(struct sk_buff *skb, u8 *dest) -{ - struct ieee80211_assoc_request_frame *a; - - if (skb->len < (sizeof(struct ieee80211_assoc_request_frame) - - sizeof(struct ieee80211_info_element))) { - - IEEE80211_DEBUG_MGMT("invalid len in auth request:%d\n", skb->len); - return -1; - } - - a = (struct ieee80211_assoc_request_frame *) skb->data; - - memcpy(dest, a->header.addr2, ETH_ALEN); - - return 0; -} - -static inline u16 assoc_parse(struct sk_buff *skb, int *aid) -{ - struct ieee80211_assoc_response_frame *a; - if (skb->len < sizeof(struct ieee80211_assoc_response_frame)) { - IEEE80211_DEBUG_MGMT("invalid len in auth resp: %d\n", skb->len); - return 0xcafe; - } - - a = (struct ieee80211_assoc_response_frame *) skb->data; - *aid = le16_to_cpu(a->aid) & 0x3fff; - return le16_to_cpu(a->status); -} - -static inline void ieee80211_rx_probe_rq(struct ieee80211_device *ieee, - struct sk_buff *skb) -{ - u8 dest[ETH_ALEN]; - - ieee->softmac_stats.rx_probe_rq++; - if (probe_rq_parse(ieee, skb, dest)) { - ieee->softmac_stats.tx_probe_rs++; - ieee80211_resp_to_probe(ieee, dest); - } -} - -inline void ieee80211_rx_auth_rq(struct ieee80211_device *ieee, - struct sk_buff *skb) -{ - u8 dest[ETH_ALEN]; - int status; - ieee->softmac_stats.rx_auth_rq++; - - status = auth_rq_parse(skb, dest); - if (status != -1) - ieee80211_resp_to_auth(ieee, status, dest); -} - -inline void -ieee80211_rx_assoc_rq(struct ieee80211_device *ieee, struct sk_buff *skb) -{ - - u8 dest[ETH_ALEN]; - - ieee->softmac_stats.rx_ass_rq++; - if (assoc_rq_parse(skb, dest) != -1) - ieee80211_resp_to_assoc_rq(ieee, dest); - - - printk(KERN_INFO"New client associated: %pM\n", dest); -} - -void ieee80211_sta_ps_send_null_frame(struct ieee80211_device *ieee, short pwr) -{ - struct sk_buff *buf = ieee80211_null_func(ieee, pwr); - - if (buf) - softmac_ps_mgmt_xmit(buf, ieee); -} - -static short ieee80211_sta_ps_sleep(struct ieee80211_device *ieee, u32 *time_h, - u32 *time_l) -{ - int timeout = 0; - - u8 dtim; - dtim = ieee->current_network.dtim_data; - - if (!(dtim & IEEE80211_DTIM_VALID)) - return 0; - else - timeout = ieee->current_network.beacon_interval; - - ieee->current_network.dtim_data = IEEE80211_DTIM_INVALID; - - if (dtim & ((IEEE80211_DTIM_UCAST | IEEE80211_DTIM_MBCAST) & ieee->ps)) - return 2; - - if (!time_after(jiffies, ieee->dev->trans_start + MSECS(timeout))) - return 0; - - if (!time_after(jiffies, ieee->last_rx_ps_time + MSECS(timeout))) - return 0; - - if ((ieee->softmac_features & IEEE_SOFTMAC_SINGLE_QUEUE) && - (ieee->mgmt_queue_tail != ieee->mgmt_queue_head)) - return 0; - - if (time_l) { - *time_l = ieee->current_network.last_dtim_sta_time[0] - + MSECS((ieee->current_network.beacon_interval)); - } - - if (time_h) { - *time_h = ieee->current_network.last_dtim_sta_time[1]; - if (time_l && *time_l < ieee->current_network.last_dtim_sta_time[0]) - *time_h += 1; - } - - return 1; -} - -static inline void ieee80211_sta_ps(struct ieee80211_device *ieee) -{ - - u32 th, tl; - short sleep; - - unsigned long flags, flags2; - - spin_lock_irqsave(&ieee->lock, flags); - - if ((ieee->ps == IEEE80211_PS_DISABLED || - ieee->iw_mode != IW_MODE_INFRA || - ieee->state != IEEE80211_LINKED)) { - - /* #warning CHECK_LOCK_HERE */ - spin_lock_irqsave(&ieee->mgmt_tx_lock, flags2); - - ieee80211_sta_wakeup(ieee, 1); - - spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags2); - } - - sleep = ieee80211_sta_ps_sleep(ieee, &th, &tl); - /* 2 wake, 1 sleep, 0 do nothing */ - if (sleep == 0) - goto out; - - if (sleep == 1) { - if (ieee->sta_sleep == 1) - ieee->enter_sleep_state(ieee->dev, th, tl); - - else if (ieee->sta_sleep == 0) { - spin_lock_irqsave(&ieee->mgmt_tx_lock, flags2); - if (ieee->ps_is_queue_empty(ieee->dev)) { - ieee->sta_sleep = 2; - - ieee->ps_request_tx_ack(ieee->dev); - - ieee80211_sta_ps_send_null_frame(ieee, 1); - - ieee->ps_th = th; - ieee->ps_tl = tl; - } - spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags2); - } - } else if (sleep == 2) { - /* #warning CHECK_LOCK_HERE */ - spin_lock_irqsave(&ieee->mgmt_tx_lock, flags2); - - ieee80211_sta_wakeup(ieee, 1); - - spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags2); - } -out: - spin_unlock_irqrestore(&ieee->lock, flags); -} - -void ieee80211_sta_wakeup(struct ieee80211_device *ieee, short nl) -{ - if (ieee->sta_sleep == 0) { - if (nl) { - ieee->ps_request_tx_ack(ieee->dev); - ieee80211_sta_ps_send_null_frame(ieee, 0); - } - return; - } - - if (ieee->sta_sleep == 1) - ieee->sta_wake_up(ieee->dev); - - ieee->sta_sleep = 0; - - if (nl) { - ieee->ps_request_tx_ack(ieee->dev); - ieee80211_sta_ps_send_null_frame(ieee, 0); - } -} - -void ieee80211_ps_tx_ack(struct ieee80211_device *ieee, short success) -{ - unsigned long flags, flags2; - - spin_lock_irqsave(&ieee->lock, flags); - if (ieee->sta_sleep == 2) { - /* Null frame with PS bit set */ - if (success) { - ieee->sta_sleep = 1; - ieee->enter_sleep_state(ieee->dev, ieee->ps_th, ieee->ps_tl); - } - /* if the card report not success we can't be sure the AP - * has not RXed so we can't assume the AP believe us awake - */ - } else { - if ((ieee->sta_sleep == 0) && !success) { - spin_lock_irqsave(&ieee->mgmt_tx_lock, flags2); - ieee80211_sta_ps_send_null_frame(ieee, 0); - spin_unlock_irqrestore(&ieee->mgmt_tx_lock, flags2); - } - } - spin_unlock_irqrestore(&ieee->lock, flags); -} - -inline int ieee80211_rx_frame_softmac(struct ieee80211_device *ieee, - struct sk_buff *skb, - struct ieee80211_rx_stats *rx_stats, - u16 type, u16 stype) -{ - struct ieee80211_hdr_3addr *header = (struct ieee80211_hdr_3addr *) skb->data; - u16 errcode; - u8 *challenge = NULL; - int chlen = 0; - int aid = 0; - struct ieee80211_assoc_response_frame *assoc_resp; - struct ieee80211_info_element *info_element; - - if (!ieee->proto_started) - return 0; - - if (ieee->sta_sleep || (ieee->ps != IEEE80211_PS_DISABLED && - ieee->iw_mode == IW_MODE_INFRA && - ieee->state == IEEE80211_LINKED)) - - tasklet_schedule(&ieee->ps_task); - - if (WLAN_FC_GET_STYPE(header->frame_control) != IEEE80211_STYPE_PROBE_RESP && - WLAN_FC_GET_STYPE(header->frame_control) != IEEE80211_STYPE_BEACON) - ieee->last_rx_ps_time = jiffies; - - switch (WLAN_FC_GET_STYPE(header->frame_control)) { - case IEEE80211_STYPE_ASSOC_RESP: - case IEEE80211_STYPE_REASSOC_RESP: - IEEE80211_DEBUG_MGMT("received [RE]ASSOCIATION RESPONSE (%d)\n", - WLAN_FC_GET_STYPE(header->frame_ctl)); - if ((ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE) && - ieee->state == IEEE80211_ASSOCIATING_AUTHENTICATED && - ieee->iw_mode == IW_MODE_INFRA) { - errcode = assoc_parse(skb, &aid); - if (0 == errcode) { - u16 left; - - ieee->state = IEEE80211_LINKED; - ieee->assoc_id = aid; - ieee->softmac_stats.rx_ass_ok++; - /* card type is 8187 */ - if (1 == rx_stats->nic_type) - goto associate_complete; - - assoc_resp = (struct ieee80211_assoc_response_frame *)skb->data; - info_element = &assoc_resp->info_element; - left = skb->len - ((void *)info_element - (void *)assoc_resp); - - while (left >= sizeof(struct ieee80211_info_element_hdr)) { - if (sizeof(struct ieee80211_info_element_hdr) + info_element->len > left) { - printk(KERN_WARNING "[re]associate response error!"); - return 1; - } - switch (info_element->id) { - case MFIE_TYPE_GENERIC: - IEEE80211_DEBUG_SCAN("MFIE_TYPE_GENERIC: %d bytes\n", info_element->len); - if (info_element->len >= 8 && - info_element->data[0] == 0x00 && - info_element->data[1] == 0x50 && - info_element->data[2] == 0xf2 && - info_element->data[3] == 0x02 && - info_element->data[4] == 0x01) { - /* Not care about version at present. - * WMM Parameter Element. - */ - memcpy(ieee->current_network.wmm_param, (u8 *)(info_element->data\ - + 8), (info_element->len - 8)); - - if (((ieee->current_network.wmm_info^info_element->data[6])& \ - 0x0f) || (!ieee->init_wmmparam_flag)) { - /* refresh parameter element for current network - * update the register parameter for hardware. - */ - ieee->init_wmmparam_flag = 1; - queue_work(ieee->wq, &ieee->wmm_param_update_wq); - } - /* update info_element for current network */ - ieee->current_network.wmm_info = info_element->data[6]; - } - break; - default: - /* nothing to do at present!!! */ - break; - } - - left -= sizeof(struct ieee80211_info_element_hdr) + - info_element->len; - info_element = (struct ieee80211_info_element *) - &info_element->data[info_element->len]; - } - /* legacy AP, reset the AC_xx_param register */ - if (!ieee->init_wmmparam_flag) { - queue_work(ieee->wq, &ieee->wmm_param_update_wq); - ieee->init_wmmparam_flag = 1; /* indicate AC_xx_param upated since last associate */ - } -associate_complete: - ieee80211_associate_complete(ieee); - } else { - ieee->softmac_stats.rx_ass_err++; - IEEE80211_DEBUG_MGMT( - "Association response status code 0x%x\n", - errcode); - ieee80211_associate_abort(ieee); - } - } - break; - case IEEE80211_STYPE_ASSOC_REQ: - case IEEE80211_STYPE_REASSOC_REQ: - if ((ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE) && - ieee->iw_mode == IW_MODE_MASTER) - - ieee80211_rx_assoc_rq(ieee, skb); - break; - case IEEE80211_STYPE_AUTH: - if (ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE) { - if (ieee->state == IEEE80211_ASSOCIATING_AUTHENTICATING && - ieee->iw_mode == IW_MODE_INFRA){ - IEEE80211_DEBUG_MGMT("Received authentication response"); - - errcode = auth_parse(skb, &challenge, &chlen); - if (0 == errcode) { - if (ieee->open_wep || !challenge) { - ieee->state = IEEE80211_ASSOCIATING_AUTHENTICATED; - ieee->softmac_stats.rx_auth_rs_ok++; - - ieee80211_associate_step2(ieee); - } else { - ieee80211_rtl_auth_challenge(ieee, challenge, chlen); - } - } else { - ieee->softmac_stats.rx_auth_rs_err++; - IEEE80211_DEBUG_MGMT("Authentication response status code 0x%x", errcode); - ieee80211_associate_abort(ieee); - } - - } else if (ieee->iw_mode == IW_MODE_MASTER) { - ieee80211_rx_auth_rq(ieee, skb); - } - } - break; - case IEEE80211_STYPE_PROBE_REQ: - if ((ieee->softmac_features & IEEE_SOFTMAC_PROBERS) && - ((ieee->iw_mode == IW_MODE_ADHOC || - ieee->iw_mode == IW_MODE_MASTER) && - ieee->state == IEEE80211_LINKED)) - - ieee80211_rx_probe_rq(ieee, skb); - break; - case IEEE80211_STYPE_DISASSOC: - case IEEE80211_STYPE_DEAUTH: - /* FIXME for now repeat all the association procedure - * both for disassociation and deauthentication - */ - if ((ieee->softmac_features & IEEE_SOFTMAC_ASSOCIATE) && - (ieee->state == IEEE80211_LINKED) && - (ieee->iw_mode == IW_MODE_INFRA) && - (!memcmp(header->addr2, ieee->current_network.bssid, ETH_ALEN))) { - ieee->state = IEEE80211_ASSOCIATING; - ieee->softmac_stats.reassoc++; - - queue_work(ieee->wq, &ieee->associate_procedure_wq); - } - break; - default: - return -1; - break; - } - return 0; -} - -/* following are for a simpler TX queue management. - * Instead of using netif_[stop/wake]_queue the driver - * will uses these two function (plus a reset one), that - * will internally uses the kernel netif_* and takes - * care of the ieee802.11 fragmentation. - * So the driver receives a fragment per time and might - * call the stop function when it want without take care - * to have enough room to TX an entire packet. - * This might be useful if each fragment need it's own - * descriptor, thus just keep a total free memory > than - * the max fragmentation threshold is not enough.. If the - * ieee802.11 stack passed a TXB struct then you needed - * to keep N free descriptors where - * N = MAX_PACKET_SIZE / MIN_FRAG_TRESHOLD - * In this way you need just one and the 802.11 stack - * will take care of buffering fragments and pass them to - * to the driver later, when it wakes the queue. - */ - -void ieee80211_softmac_xmit(struct ieee80211_txb *txb, - struct ieee80211_device *ieee) -{ - unsigned long flags; - int i; - - spin_lock_irqsave(&ieee->lock, flags); - - /* called with 2nd parm 0, no tx mgmt lock required */ - ieee80211_sta_wakeup(ieee, 0); - - for (i = 0; i < txb->nr_frags; i++) { - if (ieee->queue_stop) { - ieee->tx_pending.txb = txb; - ieee->tx_pending.frag = i; - goto exit; - } else { - ieee->softmac_data_hard_start_xmit( - txb->fragments[i], - ieee->dev, ieee->rate); - ieee->stats.tx_packets++; - ieee->stats.tx_bytes += txb->fragments[i]->len; - ieee->dev->trans_start = jiffies; - } - } - - ieee80211_txb_free(txb); - - exit: - spin_unlock_irqrestore(&ieee->lock, flags); -} - -/* called with ieee->lock acquired */ -static void ieee80211_resume_tx(struct ieee80211_device *ieee) -{ - int i; - for (i = ieee->tx_pending.frag; i < ieee->tx_pending.txb->nr_frags; i++) { - - if (ieee->queue_stop) { - ieee->tx_pending.frag = i; - return; - } else { - ieee->softmac_data_hard_start_xmit( - ieee->tx_pending.txb->fragments[i], - ieee->dev, ieee->rate); - ieee->stats.tx_packets++; - ieee->dev->trans_start = jiffies; - } - } - - ieee80211_txb_free(ieee->tx_pending.txb); - ieee->tx_pending.txb = NULL; -} - -void ieee80211_reset_queue(struct ieee80211_device *ieee) -{ - unsigned long flags; - - spin_lock_irqsave(&ieee->lock, flags); - init_mgmt_queue(ieee); - if (ieee->tx_pending.txb) { - ieee80211_txb_free(ieee->tx_pending.txb); - ieee->tx_pending.txb = NULL; - } - ieee->queue_stop = 0; - spin_unlock_irqrestore(&ieee->lock, flags); -} - -void ieee80211_rtl_wake_queue(struct ieee80211_device *ieee) -{ - unsigned long flags; - struct sk_buff *skb; - struct ieee80211_hdr_3addr *header; - - spin_lock_irqsave(&ieee->lock, flags); - if (!ieee->queue_stop) - goto exit; - - ieee->queue_stop = 0; - - if (ieee->softmac_features & IEEE_SOFTMAC_SINGLE_QUEUE) { - while (!ieee->queue_stop && (skb = dequeue_mgmt(ieee))) { - header = (struct ieee80211_hdr_3addr *) skb->data; - - header->seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4); - - if (ieee->seq_ctrl[0] == 0xFFF) - ieee->seq_ctrl[0] = 0; - else - ieee->seq_ctrl[0]++; - - ieee->softmac_data_hard_start_xmit(skb, ieee->dev, ieee->basic_rate); - dev_kfree_skb_any(skb); - } - } - if (!ieee->queue_stop && ieee->tx_pending.txb) - ieee80211_resume_tx(ieee); - - if (!ieee->queue_stop && netif_queue_stopped(ieee->dev)) { - ieee->softmac_stats.swtxawake++; - netif_wake_queue(ieee->dev); - } -exit: - spin_unlock_irqrestore(&ieee->lock, flags); -} - -void ieee80211_rtl_stop_queue(struct ieee80211_device *ieee) -{ - if (!netif_queue_stopped(ieee->dev)) { - netif_stop_queue(ieee->dev); - ieee->softmac_stats.swtxstop++; - } - ieee->queue_stop = 1; -} - -inline void ieee80211_randomize_cell(struct ieee80211_device *ieee) -{ - random_ether_addr(ieee->current_network.bssid); -} - -/* called in user context only */ -void ieee80211_start_master_bss(struct ieee80211_device *ieee) -{ - ieee->assoc_id = 1; - - if (ieee->current_network.ssid_len == 0) { - strncpy(ieee->current_network.ssid, - IEEE80211_DEFAULT_TX_ESSID, - IW_ESSID_MAX_SIZE); - - ieee->current_network.ssid_len = strlen(IEEE80211_DEFAULT_TX_ESSID); - ieee->ssid_set = 1; - } - - memcpy(ieee->current_network.bssid, ieee->dev->dev_addr, ETH_ALEN); - - ieee->set_chan(ieee->dev, ieee->current_network.channel); - ieee->state = IEEE80211_LINKED; - ieee->link_change(ieee->dev); - notify_wx_assoc_event(ieee); - - if (ieee->data_hard_resume) - ieee->data_hard_resume(ieee->dev); - - netif_carrier_on(ieee->dev); -} - -static void ieee80211_start_monitor_mode(struct ieee80211_device *ieee) -{ - if (ieee->raw_tx) { - - if (ieee->data_hard_resume) - ieee->data_hard_resume(ieee->dev); - - netif_carrier_on(ieee->dev); - } -} - -static void ieee80211_start_ibss_wq(struct work_struct *work) -{ - struct delayed_work *dwork = to_delayed_work(work); - struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, start_ibss_wq); - - /* iwconfig mode ad-hoc will schedule this and return - * on the other hand this will block further iwconfig SET - * operations because of the wx_sem hold. - * Anyway some most set operations set a flag to speed-up - * (abort) this wq (when syncro scanning) before sleeping - * on the semaphore - */ - - down(&ieee->wx_sem); - - if (ieee->current_network.ssid_len == 0) { - strcpy(ieee->current_network.ssid, IEEE80211_DEFAULT_TX_ESSID); - ieee->current_network.ssid_len = strlen(IEEE80211_DEFAULT_TX_ESSID); - ieee->ssid_set = 1; - } - - /* check if we have this cell in our network list */ - ieee80211_softmac_check_all_nets(ieee); - - if (ieee->state == IEEE80211_NOLINK) - ieee->current_network.channel = 10; - /* if not then the state is not linked. Maybe the user switched to - * ad-hoc mode just after being in monitor mode, or just after - * being very few time in managed mode (so the card have had no - * time to scan all the chans..) or we have just run up the iface - * after setting ad-hoc mode. So we have to give another try.. - * Here, in ibss mode, should be safe to do this without extra care - * (in bss mode we had to make sure no-one tried to associate when - * we had just checked the ieee->state and we was going to start the - * scan) because in ibss mode the ieee80211_new_net function, when - * finds a good net, just set the ieee->state to IEEE80211_LINKED, - * so, at worst, we waste a bit of time to initiate an unneeded syncro - * scan, that will stop at the first round because it sees the state - * associated. - */ - if (ieee->state == IEEE80211_NOLINK) - ieee80211_start_scan_syncro(ieee); - - /* the network definitively is not here.. create a new cell */ - if (ieee->state == IEEE80211_NOLINK) { - printk("creating new IBSS cell\n"); - if (!ieee->wap_set) - ieee80211_randomize_cell(ieee); - - if (ieee->modulation & IEEE80211_CCK_MODULATION) { - ieee->current_network.rates_len = 4; - - ieee->current_network.rates[0] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_1MB; - ieee->current_network.rates[1] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_2MB; - ieee->current_network.rates[2] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_5MB; - ieee->current_network.rates[3] = IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_11MB; - - } else - ieee->current_network.rates_len = 0; - - if (ieee->modulation & IEEE80211_OFDM_MODULATION) { - ieee->current_network.rates_ex_len = 8; - - ieee->current_network.rates_ex[0] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_6MB; - ieee->current_network.rates_ex[1] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_9MB; - ieee->current_network.rates_ex[2] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_12MB; - ieee->current_network.rates_ex[3] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_18MB; - ieee->current_network.rates_ex[4] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_24MB; - ieee->current_network.rates_ex[5] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_36MB; - ieee->current_network.rates_ex[6] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_48MB; - ieee->current_network.rates_ex[7] = IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_54MB; - - ieee->rate = 540; - } else { - ieee->current_network.rates_ex_len = 0; - ieee->rate = 110; - } - - /* By default, WMM function will be disabled in IBSS mode */ - ieee->current_network.QoS_Enable = 0; - - ieee->current_network.atim_window = 0; - ieee->current_network.capability = WLAN_CAPABILITY_IBSS; - if (ieee->short_slot) - ieee->current_network.capability |= WLAN_CAPABILITY_SHORT_SLOT; - } - - ieee->state = IEEE80211_LINKED; - ieee->set_chan(ieee->dev, ieee->current_network.channel); - ieee->link_change(ieee->dev); - - notify_wx_assoc_event(ieee); - - ieee80211_start_send_beacons(ieee); - printk(KERN_WARNING "after sending beacon packet!\n"); - - if (ieee->data_hard_resume) - ieee->data_hard_resume(ieee->dev); - - netif_carrier_on(ieee->dev); - - up(&ieee->wx_sem); -} - -inline void ieee80211_start_ibss(struct ieee80211_device *ieee) -{ - queue_delayed_work(ieee->wq, &ieee->start_ibss_wq, 100); -} - -/* this is called only in user context, with wx_sem held */ -void ieee80211_start_bss(struct ieee80211_device *ieee) -{ - unsigned long flags; - /* Ref: 802.11d 11.1.3.3 - * STA shall not start a BSS unless properly formed Beacon frame - * including a Country IE. - */ - if (IS_DOT11D_ENABLE(ieee) && !IS_COUNTRY_IE_VALID(ieee)) { - if (!ieee->bGlobalDomain) - return; - } - /* check if we have already found the net we are interested in (if any). - * if not (we are disassociated and we are not - * in associating / authenticating phase) start the background scanning. - */ - ieee80211_softmac_check_all_nets(ieee); - - /* ensure no-one start an associating process (thus setting - * the ieee->state to ieee80211_ASSOCIATING) while we - * have just cheked it and we are going to enable scan. - * The ieee80211_new_net function is always called with - * lock held (from both ieee80211_softmac_check_all_nets and - * the rx path), so we cannot be in the middle of such function - */ - spin_lock_irqsave(&ieee->lock, flags); - - if (ieee->state == IEEE80211_NOLINK) { - ieee->actscanning = true; - ieee80211_rtl_start_scan(ieee); - } - spin_unlock_irqrestore(&ieee->lock, flags); -} - -/* called only in userspace context */ -void ieee80211_disassociate(struct ieee80211_device *ieee) -{ - netif_carrier_off(ieee->dev); - - if (ieee->softmac_features & IEEE_SOFTMAC_TX_QUEUE) - ieee80211_reset_queue(ieee); - - if (ieee->data_hard_stop) - ieee->data_hard_stop(ieee->dev); - - if (IS_DOT11D_ENABLE(ieee)) - Dot11d_Reset(ieee); - - ieee->link_change(ieee->dev); - if (ieee->state == IEEE80211_LINKED) - notify_wx_assoc_event(ieee); - ieee->state = IEEE80211_NOLINK; - -} -static void ieee80211_associate_retry_wq(struct work_struct *work) -{ - struct delayed_work *dwork = to_delayed_work(work); - struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, associate_retry_wq); - unsigned long flags; - down(&ieee->wx_sem); - if (!ieee->proto_started) - goto exit; - if (ieee->state != IEEE80211_ASSOCIATING_RETRY) - goto exit; - /* until we do not set the state to IEEE80211_NOLINK - * there are no possibility to have someone else trying - * to start an association procedure (we get here with - * ieee->state = IEEE80211_ASSOCIATING). - * When we set the state to IEEE80211_NOLINK it is possible - * that the RX path run an attempt to associate, but - * both ieee80211_softmac_check_all_nets and the - * RX path works with ieee->lock held so there are no - * problems. If we are still disassociated then start a scan. - * the lock here is necessary to ensure no one try to start - * an association procedure when we have just checked the - * state and we are going to start the scan. - */ - ieee->state = IEEE80211_NOLINK; - ieee->beinretry = true; - ieee80211_softmac_check_all_nets(ieee); - - spin_lock_irqsave(&ieee->lock, flags); - - if (ieee->state == IEEE80211_NOLINK) { - ieee->beinretry = false; - ieee->actscanning = true; - ieee80211_rtl_start_scan(ieee); - } - if (ieee->state == IEEE80211_NOLINK) - notify_wx_assoc_event(ieee); - spin_unlock_irqrestore(&ieee->lock, flags); - -exit: - up(&ieee->wx_sem); -} - -struct sk_buff *ieee80211_get_beacon_(struct ieee80211_device *ieee) -{ - u8 broadcast_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; - - struct sk_buff *skb = NULL; - struct ieee80211_probe_response *b; - - skb = ieee80211_probe_resp(ieee, broadcast_addr); - if (!skb) - return NULL; - - b = (struct ieee80211_probe_response *) skb->data; - b->header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_BEACON); - - return skb; -} - -struct sk_buff *ieee80211_get_beacon(struct ieee80211_device *ieee) -{ - struct sk_buff *skb; - struct ieee80211_probe_response *b; - - skb = ieee80211_get_beacon_(ieee); - if (!skb) - return NULL; - - b = (struct ieee80211_probe_response *) skb->data; - b->header.seq_ctrl = cpu_to_le16(ieee->seq_ctrl[0] << 4); - - if (ieee->seq_ctrl[0] == 0xFFF) - ieee->seq_ctrl[0] = 0; - else - ieee->seq_ctrl[0]++; - - return skb; -} - -void ieee80211_softmac_stop_protocol(struct ieee80211_device *ieee) -{ - ieee->sync_scan_hurryup = 1; - down(&ieee->wx_sem); - ieee80211_stop_protocol(ieee); - up(&ieee->wx_sem); -} - -void ieee80211_stop_protocol(struct ieee80211_device *ieee) -{ - if (!ieee->proto_started) - return; - - ieee->proto_started = 0; - - ieee80211_stop_send_beacons(ieee); - if ((ieee->iw_mode == IW_MODE_INFRA) && (ieee->state == IEEE80211_LINKED)) - SendDisassociation(ieee, NULL, WLAN_REASON_DISASSOC_STA_HAS_LEFT); - - del_timer_sync(&ieee->associate_timer); - cancel_delayed_work(&ieee->associate_retry_wq); - cancel_delayed_work(&ieee->start_ibss_wq); - ieee80211_stop_scan(ieee); - - ieee80211_disassociate(ieee); -} - -void ieee80211_softmac_start_protocol(struct ieee80211_device *ieee) -{ - ieee->sync_scan_hurryup = 0; - down(&ieee->wx_sem); - ieee80211_start_protocol(ieee); - up(&ieee->wx_sem); -} - -void ieee80211_start_protocol(struct ieee80211_device *ieee) -{ - short ch = 0; - int i = 0; - - if (ieee->proto_started) - return; - - ieee->proto_started = 1; - - if (ieee->current_network.channel == 0) { - do { - ch++; - if (ch > MAX_CHANNEL_NUMBER) - return; /* no channel found */ - - } while (!GET_DOT11D_INFO(ieee)->channel_map[ch]); - - ieee->current_network.channel = ch; - } - - if (ieee->current_network.beacon_interval == 0) - ieee->current_network.beacon_interval = 100; - ieee->set_chan(ieee->dev, ieee->current_network.channel); - - for (i = 0; i < 17; i++) { - ieee->last_rxseq_num[i] = -1; - ieee->last_rxfrag_num[i] = -1; - ieee->last_packet_time[i] = 0; - } - - ieee->init_wmmparam_flag = 0; /* reinitialize AC_xx_PARAM registers. */ - - /* if the user set the MAC of the ad-hoc cell and then - * switch to managed mode, shall we make sure that association - * attempts does not fail just because the user provide the essid - * and the nic is still checking for the AP MAC ?? - */ - switch (ieee->iw_mode) { - case IW_MODE_AUTO: - ieee->iw_mode = IW_MODE_INFRA; - /* not set break here intentionly */ - case IW_MODE_INFRA: - ieee80211_start_bss(ieee); - break; - - case IW_MODE_ADHOC: - ieee80211_start_ibss(ieee); - break; - - case IW_MODE_MASTER: - ieee80211_start_master_bss(ieee); - break; - - case IW_MODE_MONITOR: - ieee80211_start_monitor_mode(ieee); - break; - - default: - ieee->iw_mode = IW_MODE_INFRA; - ieee80211_start_bss(ieee); - break; - } -} - -#define DRV_NAME "Ieee80211" -void ieee80211_softmac_init(struct ieee80211_device *ieee) -{ - int i; - memset(&ieee->current_network, 0, sizeof(struct ieee80211_network)); - - ieee->state = IEEE80211_NOLINK; - ieee->sync_scan_hurryup = 0; - for (i = 0; i < 5; i++) - ieee->seq_ctrl[i] = 0; - - ieee->assoc_id = 0; - ieee->queue_stop = 0; - ieee->scanning = 0; - ieee->softmac_features = 0; /* so IEEE2100-like driver are happy */ - ieee->wap_set = 0; - ieee->ssid_set = 0; - ieee->proto_started = 0; - ieee->basic_rate = IEEE80211_DEFAULT_BASIC_RATE; - ieee->rate = 3; - ieee->ps = IEEE80211_PS_MBCAST|IEEE80211_PS_UNICAST; - ieee->sta_sleep = 0; - ieee->bInactivePs = false; - ieee->actscanning = false; - ieee->ListenInterval = 2; - ieee->NumRxDataInPeriod = 0; - ieee->NumRxBcnInPeriod = 0; - ieee->NumRxOkTotal = 0; - ieee->NumRxUnicast = 0; /* for keep alive */ - ieee->beinretry = false; - ieee->bHwRadioOff = false; - - init_mgmt_queue(ieee); - - ieee->tx_pending.txb = NULL; - - init_timer(&ieee->associate_timer); - ieee->associate_timer.data = (unsigned long)ieee; - ieee->associate_timer.function = ieee80211_associate_abort_cb; - - init_timer(&ieee->beacon_timer); - ieee->beacon_timer.data = (unsigned long) ieee; - ieee->beacon_timer.function = ieee80211_send_beacon_cb; - - ieee->wq = create_workqueue(DRV_NAME); - - INIT_DELAYED_WORK(&ieee->start_ibss_wq, (void *) ieee80211_start_ibss_wq); - INIT_WORK(&ieee->associate_complete_wq, (void *) ieee80211_associate_complete_wq); - INIT_WORK(&ieee->associate_procedure_wq, (void *) ieee80211_associate_procedure_wq); - INIT_DELAYED_WORK(&ieee->softmac_scan_wq, (void *) ieee80211_softmac_scan_wq); - INIT_DELAYED_WORK(&ieee->associate_retry_wq, (void *) ieee80211_associate_retry_wq); - INIT_WORK(&ieee->wx_sync_scan_wq, (void *) ieee80211_wx_sync_scan_wq); - - sema_init(&ieee->wx_sem, 1); - sema_init(&ieee->scan_sem, 1); - - spin_lock_init(&ieee->mgmt_tx_lock); - spin_lock_init(&ieee->beacon_lock); - - tasklet_init(&ieee->ps_task, - (void(*)(unsigned long)) ieee80211_sta_ps, - (unsigned long)ieee); - ieee->pDot11dInfo = kmalloc(sizeof(RT_DOT11D_INFO), GFP_ATOMIC); -} - -void ieee80211_softmac_free(struct ieee80211_device *ieee) -{ - down(&ieee->wx_sem); - - del_timer_sync(&ieee->associate_timer); - cancel_delayed_work(&ieee->associate_retry_wq); - - /* add for RF power on power of */ - cancel_delayed_work(&ieee->GPIOChangeRFWorkItem); - - destroy_workqueue(ieee->wq); - kfree(ieee->pDot11dInfo); - up(&ieee->wx_sem); -} - -/* Start of WPA code. This is stolen from the ipw2200 driver */ -static int ieee80211_wpa_enable(struct ieee80211_device *ieee, int value) -{ - /* This is called when wpa_supplicant loads and closes the driver - * interface. */ - printk("%s WPA\n", value ? "enabling" : "disabling"); - ieee->wpa_enabled = value; - return 0; -} - -static void ieee80211_wpa_assoc_frame(struct ieee80211_device *ieee, char *wpa_ie, - int wpa_ie_len) -{ - /* make sure WPA is enabled */ - ieee80211_wpa_enable(ieee, 1); - - ieee80211_disassociate(ieee); -} - -static int ieee80211_wpa_mlme(struct ieee80211_device *ieee, int command, - int reason) -{ - int ret = 0; - - switch (command) { - case IEEE_MLME_STA_DEAUTH: - /* silently ignore */ - break; - - case IEEE_MLME_STA_DISASSOC: - ieee80211_disassociate(ieee); - break; - - default: - printk("Unknown MLME request: %d\n", command); - ret = -EOPNOTSUPP; - } - - return ret; -} - -static int ieee80211_wpa_set_wpa_ie(struct ieee80211_device *ieee, - struct ieee_param *param, int plen) -{ - u8 *buf; - - if (param->u.wpa_ie.len > MAX_WPA_IE_LEN || - (param->u.wpa_ie.len && param->u.wpa_ie.data == NULL)) - return -EINVAL; - - if (param->u.wpa_ie.len) { - buf = kmemdup(param->u.wpa_ie.data, param->u.wpa_ie.len, - GFP_KERNEL); - if (buf == NULL) - return -ENOMEM; - - kfree(ieee->wpa_ie); - ieee->wpa_ie = buf; - ieee->wpa_ie_len = param->u.wpa_ie.len; - } else { - kfree(ieee->wpa_ie); - ieee->wpa_ie = NULL; - ieee->wpa_ie_len = 0; - } - - ieee80211_wpa_assoc_frame(ieee, ieee->wpa_ie, ieee->wpa_ie_len); - return 0; -} - -#define AUTH_ALG_OPEN_SYSTEM 0x1 -#define AUTH_ALG_SHARED_KEY 0x2 - -static int ieee80211_wpa_set_auth_algs(struct ieee80211_device *ieee, int value) -{ - struct ieee80211_security sec = { - .flags = SEC_AUTH_MODE, - }; - int ret = 0; - - if (value & AUTH_ALG_SHARED_KEY) { - sec.auth_mode = WLAN_AUTH_SHARED_KEY; - ieee->open_wep = 0; - } else { - sec.auth_mode = WLAN_AUTH_OPEN; - ieee->open_wep = 1; - } - - if (ieee->set_security) - ieee->set_security(ieee->dev, &sec); - else - ret = -EOPNOTSUPP; - - return ret; -} - -static int ieee80211_wpa_set_param(struct ieee80211_device *ieee, u8 name, - u32 value) -{ - int ret = 0; - unsigned long flags; - - switch (name) { - case IEEE_PARAM_WPA_ENABLED: - ret = ieee80211_wpa_enable(ieee, value); - break; - - case IEEE_PARAM_TKIP_COUNTERMEASURES: - ieee->tkip_countermeasures = value; - break; - - case IEEE_PARAM_DROP_UNENCRYPTED: { - /* HACK: - * - * wpa_supplicant calls set_wpa_enabled when the driver - * is loaded and unloaded, regardless of if WPA is being - * used. No other calls are made which can be used to - * determine if encryption will be used or not prior to - * association being expected. If encryption is not being - * used, drop_unencrypted is set to false, else true -- we - * can use this to determine if the CAP_PRIVACY_ON bit should - * be set. - */ - struct ieee80211_security sec = { - .flags = SEC_ENABLED, - .enabled = value, - }; - ieee->drop_unencrypted = value; - /* We only change SEC_LEVEL for open mode. Others - * are set by ipw_wpa_set_encryption. - */ - if (!value) { - sec.flags |= SEC_LEVEL; - sec.level = SEC_LEVEL_0; - } else { - sec.flags |= SEC_LEVEL; - sec.level = SEC_LEVEL_1; - } - if (ieee->set_security) - ieee->set_security(ieee->dev, &sec); - break; - } - - case IEEE_PARAM_PRIVACY_INVOKED: - ieee->privacy_invoked = value; - break; - case IEEE_PARAM_AUTH_ALGS: - ret = ieee80211_wpa_set_auth_algs(ieee, value); - break; - case IEEE_PARAM_IEEE_802_1X: - ieee->ieee802_1x = value; - break; - case IEEE_PARAM_WPAX_SELECT: - spin_lock_irqsave(&ieee->wpax_suitlist_lock, flags); - ieee->wpax_type_set = 1; - ieee->wpax_type_notify = value; - spin_unlock_irqrestore(&ieee->wpax_suitlist_lock, flags); - break; - default: - printk("Unknown WPA param: %d\n", name); - ret = -EOPNOTSUPP; - } - - return ret; -} - -/* implementation borrowed from hostap driver */ - -static int ieee80211_wpa_set_encryption(struct ieee80211_device *ieee, - struct ieee_param *param, int param_len) -{ - int ret = 0; - - struct ieee80211_crypto_ops *ops; - struct ieee80211_crypt_data **crypt; - - struct ieee80211_security sec = { - .flags = 0, - }; - - param->u.crypt.err = 0; - param->u.crypt.alg[IEEE_CRYPT_ALG_NAME_LEN - 1] = '\0'; - - if (param_len != - (int) ((char *) param->u.crypt.key - (char *) param) + - param->u.crypt.key_len) { - printk("Len mismatch %d, %d\n", param_len, - param->u.crypt.key_len); - return -EINVAL; - } - if (is_broadcast_ether_addr(param->sta_addr)) { - if (param->u.crypt.idx >= WEP_KEYS) - return -EINVAL; - crypt = &ieee->crypt[param->u.crypt.idx]; - } else { - return -EINVAL; - } - - if (strcmp(param->u.crypt.alg, "none") == 0) { - if (crypt) { - sec.enabled = 0; - /* FIXME FIXME */ - sec.level = SEC_LEVEL_0; - sec.flags |= SEC_ENABLED | SEC_LEVEL; - ieee80211_crypt_delayed_deinit(ieee, crypt); - } - goto done; - } - sec.enabled = 1; - /* FIXME FIXME */ - sec.flags |= SEC_ENABLED; - - /* IPW HW cannot build TKIP MIC, host decryption still needed. */ - if (!(ieee->host_encrypt || ieee->host_decrypt) && - strcmp(param->u.crypt.alg, "TKIP")) - goto skip_host_crypt; - - ops = ieee80211_get_crypto_ops(param->u.crypt.alg); - if (ops == NULL && strcmp(param->u.crypt.alg, "WEP") == 0) - ops = ieee80211_get_crypto_ops(param->u.crypt.alg); - else if (ops == NULL && strcmp(param->u.crypt.alg, "TKIP") == 0) - ops = ieee80211_get_crypto_ops(param->u.crypt.alg); - else if (ops == NULL && strcmp(param->u.crypt.alg, "CCMP") == 0) - ops = ieee80211_get_crypto_ops(param->u.crypt.alg); - if (ops == NULL) { - printk("unknown crypto alg '%s'\n", param->u.crypt.alg); - param->u.crypt.err = IEEE_CRYPT_ERR_UNKNOWN_ALG; - ret = -EINVAL; - goto done; - } - - if (*crypt == NULL || (*crypt)->ops != ops) { - struct ieee80211_crypt_data *new_crypt; - - ieee80211_crypt_delayed_deinit(ieee, crypt); - - new_crypt = kmalloc(sizeof(*new_crypt), GFP_KERNEL); - if (new_crypt == NULL) { - ret = -ENOMEM; - goto done; - } - memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data)); - new_crypt->ops = ops; - if (new_crypt->ops) - new_crypt->priv = - new_crypt->ops->init(param->u.crypt.idx); - - if (new_crypt->priv == NULL) { - kfree(new_crypt); - param->u.crypt.err = IEEE_CRYPT_ERR_CRYPT_INIT_FAILED; - ret = -EINVAL; - goto done; - } - - *crypt = new_crypt; - } - - if (param->u.crypt.key_len > 0 && (*crypt)->ops->set_key && - (*crypt)->ops->set_key(param->u.crypt.key, - param->u.crypt.key_len, param->u.crypt.seq, - (*crypt)->priv) < 0) { - printk("key setting failed\n"); - param->u.crypt.err = IEEE_CRYPT_ERR_KEY_SET_FAILED; - ret = -EINVAL; - goto done; - } - - skip_host_crypt: - if (param->u.crypt.set_tx) { - ieee->tx_keyidx = param->u.crypt.idx; - sec.active_key = param->u.crypt.idx; - sec.flags |= SEC_ACTIVE_KEY; - } else - sec.flags &= ~SEC_ACTIVE_KEY; - - if (param->u.crypt.alg != NULL) { - memcpy(sec.keys[param->u.crypt.idx], - param->u.crypt.key, - param->u.crypt.key_len); - sec.key_sizes[param->u.crypt.idx] = param->u.crypt.key_len; - sec.flags |= (1 << param->u.crypt.idx); - - if (strcmp(param->u.crypt.alg, "WEP") == 0) { - sec.flags |= SEC_LEVEL; - sec.level = SEC_LEVEL_1; - } else if (strcmp(param->u.crypt.alg, "TKIP") == 0) { - sec.flags |= SEC_LEVEL; - sec.level = SEC_LEVEL_2; - } else if (strcmp(param->u.crypt.alg, "CCMP") == 0) { - sec.flags |= SEC_LEVEL; - sec.level = SEC_LEVEL_3; - } - } - done: - if (ieee->set_security) - ieee->set_security(ieee->dev, &sec); - - /* Do not reset port if card is in Managed mode since resetting will - * generate new IEEE 802.11 authentication which may end up in looping - * with IEEE 802.1X. If your hardware requires a reset after WEP - * configuration (for example... Prism2), implement the reset_port in - * the callbacks structures used to initialize the 802.11 stack. */ - if (ieee->reset_on_keychange && - ieee->iw_mode != IW_MODE_INFRA && - ieee->reset_port && - ieee->reset_port(ieee->dev)) { - printk("reset_port failed\n"); - param->u.crypt.err = IEEE_CRYPT_ERR_CARD_CONF_FAILED; - return -EINVAL; - } - - return ret; -} - -int ieee80211_wpa_supplicant_ioctl(struct ieee80211_device *ieee, - struct iw_point *p) -{ - struct ieee_param *param; - int ret = 0; - - down(&ieee->wx_sem); - - if (p->length < sizeof(struct ieee_param) || !p->pointer) { - ret = -EINVAL; - goto out; - } - - param = memdup_user(p->pointer, p->length); - if (IS_ERR(param)) { - ret = PTR_ERR(param); - goto out; - } - - switch (param->cmd) { - case IEEE_CMD_SET_WPA_PARAM: - ret = ieee80211_wpa_set_param(ieee, param->u.wpa_param.name, - param->u.wpa_param.value); - break; - case IEEE_CMD_SET_WPA_IE: - ret = ieee80211_wpa_set_wpa_ie(ieee, param, p->length); - break; - case IEEE_CMD_SET_ENCRYPTION: - ret = ieee80211_wpa_set_encryption(ieee, param, p->length); - break; - case IEEE_CMD_MLME: - ret = ieee80211_wpa_mlme(ieee, param->u.mlme.command, - param->u.mlme.reason_code); - break; - default: - printk("Unknown WPA supplicant request: %d\n", param->cmd); - ret = -EOPNOTSUPP; - break; - } - - if (ret == 0 && copy_to_user(p->pointer, param, p->length)) - ret = -EFAULT; - - kfree(param); -out: - up(&ieee->wx_sem); - - return ret; -} - -void notify_wx_assoc_event(struct ieee80211_device *ieee) -{ - union iwreq_data wrqu; - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - if (ieee->state == IEEE80211_LINKED) - memcpy(wrqu.ap_addr.sa_data, ieee->current_network.bssid, ETH_ALEN); - else - memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN); - wireless_send_event(ieee->dev, SIOCGIWAP, &wrqu, NULL); -} diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c deleted file mode 100644 index 46f35644126..00000000000 --- a/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c +++ /dev/null @@ -1,567 +0,0 @@ -/* IEEE 802.11 SoftMAC layer - * Copyright (c) 2005 Andrea Merello - * - * Mostly extracted from the rtl8180-sa2400 driver for the - * in-kernel generic ieee802.11 stack. - * - * Some pieces of code might be stolen from ipw2100 driver - * copyright of who own it's copyright ;-) - * - * PS wx handler mostly stolen from hostap, copyright who - * own it's copyright ;-) - * - * released under the GPL - */ - - -#include - -#include "ieee80211.h" - -/* FIXME: add A freqs */ - -const long ieee80211_wlan_frequencies[] = { - 2412, 2417, 2422, 2427, - 2432, 2437, 2442, 2447, - 2452, 2457, 2462, 2467, - 2472, 2484 -}; - - -int ieee80211_wx_set_freq(struct ieee80211_device *ieee, - struct iw_request_info *a, union iwreq_data *wrqu, - char *b) -{ - int ret; - struct iw_freq *fwrq = &wrqu->freq; -// printk("in %s\n",__func__); - down(&ieee->wx_sem); - - if (ieee->iw_mode == IW_MODE_INFRA) { - ret = -EOPNOTSUPP; - goto out; - } - - /* if setting by freq convert to channel */ - if (fwrq->e == 1) { - if ((fwrq->m >= (int) 2.412e8 && - fwrq->m <= (int) 2.487e8)) { - int f = fwrq->m / 100000; - int c = 0; - - while ((c < 14) && (f != ieee80211_wlan_frequencies[c])) - c++; - - /* hack to fall through */ - fwrq->e = 0; - fwrq->m = c + 1; - } - } - - if (fwrq->e > 0 || fwrq->m > 14 || fwrq->m < 1) { - ret = -EOPNOTSUPP; - goto out; - - } else { /* Set the channel */ - - - ieee->current_network.channel = fwrq->m; - ieee->set_chan(ieee->dev, ieee->current_network.channel); - - if (ieee->iw_mode == IW_MODE_ADHOC || ieee->iw_mode == IW_MODE_MASTER) - if (ieee->state == IEEE80211_LINKED) { - ieee80211_stop_send_beacons(ieee); - ieee80211_start_send_beacons(ieee); - } - } - - ret = 0; -out: - up(&ieee->wx_sem); - return ret; -} - - -int ieee80211_wx_get_freq(struct ieee80211_device *ieee, - struct iw_request_info *a, union iwreq_data *wrqu, - char *b) -{ - struct iw_freq *fwrq = &wrqu->freq; - - if (ieee->current_network.channel == 0) - return -1; - - fwrq->m = ieee->current_network.channel; - fwrq->e = 0; - - return 0; -} - -int ieee80211_wx_get_wap(struct ieee80211_device *ieee, - struct iw_request_info *info, union iwreq_data *wrqu, - char *extra) -{ - unsigned long flags; - - wrqu->ap_addr.sa_family = ARPHRD_ETHER; - - if (ieee->iw_mode == IW_MODE_MONITOR) - return -1; - - /* We want avoid to give to the user inconsistent infos*/ - spin_lock_irqsave(&ieee->lock, flags); - - if (ieee->state != IEEE80211_LINKED && - ieee->state != IEEE80211_LINKED_SCANNING && - ieee->wap_set == 0) - - memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN); - else - memcpy(wrqu->ap_addr.sa_data, - ieee->current_network.bssid, ETH_ALEN); - - spin_unlock_irqrestore(&ieee->lock, flags); - - return 0; -} - - -int ieee80211_wx_set_wap(struct ieee80211_device *ieee, - struct iw_request_info *info, union iwreq_data *awrq, - char *extra) -{ - - int ret = 0; - unsigned long flags; - - short ifup = ieee->proto_started;//dev->flags & IFF_UP; - struct sockaddr *temp = (struct sockaddr *)awrq; - - //printk("=======Set WAP:"); - ieee->sync_scan_hurryup = 1; - - down(&ieee->wx_sem); - /* use ifconfig hw ether */ - if (ieee->iw_mode == IW_MODE_MASTER) { - ret = -1; - goto out; - } - - if (temp->sa_family != ARPHRD_ETHER) { - ret = -EINVAL; - goto out; - } - - if (ifup) - ieee80211_stop_protocol(ieee); - - /* just to avoid to give inconsistent infos in the - * get wx method. not really needed otherwise - */ - spin_lock_irqsave(&ieee->lock, flags); - - memcpy(ieee->current_network.bssid, temp->sa_data, ETH_ALEN); - ieee->wap_set = !is_zero_ether_addr(temp->sa_data); - //printk(" %x:%x:%x:%x:%x:%x\n", ieee->current_network.bssid[0],ieee->current_network.bssid[1],ieee->current_network.bssid[2],ieee->current_network.bssid[3],ieee->current_network.bssid[4],ieee->current_network.bssid[5]); - - spin_unlock_irqrestore(&ieee->lock, flags); - - if (ifup) - ieee80211_start_protocol(ieee); - -out: - up(&ieee->wx_sem); - return ret; -} - -int ieee80211_wx_get_essid(struct ieee80211_device *ieee, - struct iw_request_info *a, union iwreq_data *wrqu, - char *b) -{ - int len, ret = 0; - unsigned long flags; - - if (ieee->iw_mode == IW_MODE_MONITOR) - return -1; - - /* We want avoid to give to the user inconsistent infos*/ - spin_lock_irqsave(&ieee->lock, flags); - - if (ieee->current_network.ssid[0] == '\0' || - ieee->current_network.ssid_len == 0){ - ret = -1; - goto out; - } - - if (ieee->state != IEEE80211_LINKED && - ieee->state != IEEE80211_LINKED_SCANNING && - ieee->ssid_set == 0){ - ret = -1; - goto out; - } - len = ieee->current_network.ssid_len; - wrqu->essid.length = len; - strncpy(b, ieee->current_network.ssid, len); - wrqu->essid.flags = 1; - -out: - spin_unlock_irqrestore(&ieee->lock, flags); - - return ret; - -} - -int ieee80211_wx_set_rate(struct ieee80211_device *ieee, - struct iw_request_info *info, union iwreq_data *wrqu, - char *extra) -{ - - u32 target_rate = wrqu->bitrate.value; - - //added by lizhaoming for auto mode - if (target_rate == -1) - ieee->rate = 110; - else - ieee->rate = target_rate/100000; - - //FIXME: we might want to limit rate also in management protocols. - return 0; -} - - - -int ieee80211_wx_get_rate(struct ieee80211_device *ieee, - struct iw_request_info *info, union iwreq_data *wrqu, - char *extra) -{ - - wrqu->bitrate.value = ieee->rate * 100000; - - return 0; -} - -int ieee80211_wx_set_mode(struct ieee80211_device *ieee, - struct iw_request_info *a, union iwreq_data *wrqu, - char *b) -{ - - ieee->sync_scan_hurryup = 1; - - down(&ieee->wx_sem); - - if (wrqu->mode == ieee->iw_mode) - goto out; - - if (wrqu->mode == IW_MODE_MONITOR) - ieee->dev->type = ARPHRD_IEEE80211; - else - ieee->dev->type = ARPHRD_ETHER; - - if (!ieee->proto_started) { - ieee->iw_mode = wrqu->mode; - } else { - ieee80211_stop_protocol(ieee); - ieee->iw_mode = wrqu->mode; - ieee80211_start_protocol(ieee); - } - -out: - up(&ieee->wx_sem); - return 0; -} - - -void ieee80211_wx_sync_scan_wq(struct work_struct *work) -{ - struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, wx_sync_scan_wq); - short chan; - - chan = ieee->current_network.channel; - - if (ieee->data_hard_stop) - ieee->data_hard_stop(ieee->dev); - - ieee80211_stop_send_beacons(ieee); - - ieee->state = IEEE80211_LINKED_SCANNING; - ieee->link_change(ieee->dev); - - ieee80211_start_scan_syncro(ieee); - - ieee->set_chan(ieee->dev, chan); - - ieee->state = IEEE80211_LINKED; - ieee->link_change(ieee->dev); - - if (ieee->data_hard_resume) - ieee->data_hard_resume(ieee->dev); - - if (ieee->iw_mode == IW_MODE_ADHOC || ieee->iw_mode == IW_MODE_MASTER) - ieee80211_start_send_beacons(ieee); - - //YJ,add,080828, In prevent of lossing ping packet during scanning - //ieee80211_sta_ps_send_null_frame(ieee, false); - //YJ,add,080828,end - - up(&ieee->wx_sem); - -} - -int ieee80211_wx_set_scan(struct ieee80211_device *ieee, - struct iw_request_info *a, union iwreq_data *wrqu, - char *b) -{ - int ret = 0; - - down(&ieee->wx_sem); - - if (ieee->iw_mode == IW_MODE_MONITOR || !(ieee->proto_started)) { - ret = -1; - goto out; - } - //YJ,add,080828 - //In prevent of lossing ping packet during scanning - //ieee80211_sta_ps_send_null_frame(ieee, true); - //YJ,add,080828,end - - if (ieee->state == IEEE80211_LINKED) { - queue_work(ieee->wq, &ieee->wx_sync_scan_wq); - /* intentionally forget to up sem */ - return 0; - } - -out: - up(&ieee->wx_sem); - return ret; -} - -int ieee80211_wx_set_essid(struct ieee80211_device *ieee, - struct iw_request_info *a, union iwreq_data *wrqu, - char *extra) -{ - - int ret = 0, len; - short proto_started; - unsigned long flags; - - ieee->sync_scan_hurryup = 1; - - down(&ieee->wx_sem); - - proto_started = ieee->proto_started; - - if (wrqu->essid.length > IW_ESSID_MAX_SIZE) { - ret = -E2BIG; - goto out; - } - - if (ieee->iw_mode == IW_MODE_MONITOR) { - ret = -1; - goto out; - } - - if (proto_started) - ieee80211_stop_protocol(ieee); - - /* this is just to be sure that the GET wx callback - * has consistent infos. not needed otherwise - */ - spin_lock_irqsave(&ieee->lock, flags); - - if (wrqu->essid.flags && wrqu->essid.length) { -//YJ,modified,080819 - len = (wrqu->essid.length < IW_ESSID_MAX_SIZE) ? (wrqu->essid.length) : IW_ESSID_MAX_SIZE; - memset(ieee->current_network.ssid, 0, ieee->current_network.ssid_len); //YJ,add,080819 - strncpy(ieee->current_network.ssid, extra, len); - ieee->current_network.ssid_len = len; - ieee->ssid_set = 1; -//YJ,modified,080819,end - - //YJ,add,080819,for hidden ap - if (len == 0) { - memset(ieee->current_network.bssid, 0, ETH_ALEN); - ieee->current_network.capability = 0; - } - //YJ,add,080819,for hidden ap,end - } else { - ieee->ssid_set = 0; - ieee->current_network.ssid[0] = '\0'; - ieee->current_network.ssid_len = 0; - } - //printk("==========set essid %s!\n",ieee->current_network.ssid); - spin_unlock_irqrestore(&ieee->lock, flags); - - if (proto_started) - ieee80211_start_protocol(ieee); -out: - up(&ieee->wx_sem); - return ret; -} - -int ieee80211_wx_get_mode(struct ieee80211_device *ieee, - struct iw_request_info *a, union iwreq_data *wrqu, - char *b) -{ - - wrqu->mode = ieee->iw_mode; - return 0; -} - -int ieee80211_wx_set_rawtx(struct ieee80211_device *ieee, - struct iw_request_info *info, union iwreq_data *wrqu, - char *extra) -{ - - int *parms = (int *)extra; - int enable = (parms[0] > 0); - short prev = ieee->raw_tx; - - down(&ieee->wx_sem); - - if (enable) - ieee->raw_tx = 1; - else - ieee->raw_tx = 0; - - netdev_info(ieee->dev, "raw TX is %s\n", - ieee->raw_tx ? "enabled" : "disabled"); - - if (ieee->iw_mode == IW_MODE_MONITOR) { - if (prev == 0 && ieee->raw_tx) { - if (ieee->data_hard_resume) - ieee->data_hard_resume(ieee->dev); - - netif_carrier_on(ieee->dev); - } - - if (prev && ieee->raw_tx == 1) - netif_carrier_off(ieee->dev); - } - - up(&ieee->wx_sem); - - return 0; -} - -int ieee80211_wx_get_name(struct ieee80211_device *ieee, - struct iw_request_info *info, union iwreq_data *wrqu, - char *extra) -{ - strlcpy(wrqu->name, "802.11", IFNAMSIZ); - if (ieee->modulation & IEEE80211_CCK_MODULATION) { - strlcat(wrqu->name, "b", IFNAMSIZ); - if (ieee->modulation & IEEE80211_OFDM_MODULATION) - strlcat(wrqu->name, "/g", IFNAMSIZ); - } else if (ieee->modulation & IEEE80211_OFDM_MODULATION) - strlcat(wrqu->name, "g", IFNAMSIZ); - - if ((ieee->state == IEEE80211_LINKED) || - (ieee->state == IEEE80211_LINKED_SCANNING)) - strlcat(wrqu->name, " link", IFNAMSIZ); - else if (ieee->state != IEEE80211_NOLINK) - strlcat(wrqu->name, " .....", IFNAMSIZ); - - - return 0; -} - - -/* this is mostly stolen from hostap */ -int ieee80211_wx_set_power(struct ieee80211_device *ieee, - struct iw_request_info *info, union iwreq_data *wrqu, - char *extra) -{ - int ret = 0; - - if ((!ieee->sta_wake_up) || - (!ieee->ps_request_tx_ack) || - (!ieee->enter_sleep_state) || - (!ieee->ps_is_queue_empty)) { - - printk("ERROR. PS mode tried to be use but driver missed a callback\n\n"); - - return -1; - } - - down(&ieee->wx_sem); - - if (wrqu->power.disabled) { - ieee->ps = IEEE80211_PS_DISABLED; - - goto exit; - } - switch (wrqu->power.flags & IW_POWER_MODE) { - case IW_POWER_UNICAST_R: - ieee->ps = IEEE80211_PS_UNICAST; - - break; - case IW_POWER_ALL_R: - ieee->ps = IEEE80211_PS_UNICAST | IEEE80211_PS_MBCAST; - break; - - case IW_POWER_ON: - ieee->ps = IEEE80211_PS_DISABLED; - break; - - default: - ret = -EINVAL; - goto exit; - } - - if (wrqu->power.flags & IW_POWER_TIMEOUT) { - - ieee->ps_timeout = wrqu->power.value / 1000; - printk("Timeout %d\n", ieee->ps_timeout); - } - - if (wrqu->power.flags & IW_POWER_PERIOD) { - - ret = -EOPNOTSUPP; - goto exit; - //wrq->value / 1024; - - } -exit: - up(&ieee->wx_sem); - return ret; - -} - -/* this is stolen from hostap */ -int ieee80211_wx_get_power(struct ieee80211_device *ieee, - struct iw_request_info *info, union iwreq_data *wrqu, - char *extra) -{ - int ret = 0; - - down(&ieee->wx_sem); - - if (ieee->ps == IEEE80211_PS_DISABLED) { - wrqu->power.disabled = 1; - goto exit; - } - - wrqu->power.disabled = 0; - -// if ((wrqu->power.flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) { - wrqu->power.flags = IW_POWER_TIMEOUT; - wrqu->power.value = ieee->ps_timeout * 1000; -// } else { -// ret = -EOPNOTSUPP; -// goto exit; - //wrqu->power.flags = IW_POWER_PERIOD; - //wrqu->power.value = ieee->current_network.dtim_period * - // ieee->current_network.beacon_interval * 1024; -// } - - - if (ieee->ps & IEEE80211_PS_MBCAST) - wrqu->power.flags |= IW_POWER_ALL_R; - else - wrqu->power.flags |= IW_POWER_UNICAST_R; - -exit: - up(&ieee->wx_sem); - return ret; - -} diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c deleted file mode 100644 index 0dc5ae41427..00000000000 --- a/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c +++ /dev/null @@ -1,591 +0,0 @@ -/****************************************************************************** - - Copyright(c) 2003 - 2004 Intel Corporation. All rights reserved. - - This program is free software; you can redistribute it and/or modify it - under the terms of version 2 of the GNU General Public License as - published by the Free Software Foundation. - - This program is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - more details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., 59 - Temple Place - Suite 330, Boston, MA 02111-1307, USA. - - The full GNU General Public License is included in this distribution in the - file called LICENSE. - - Contact Information: - James P. Ketrenos - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -****************************************************************************** - - Few modifications for Realtek's Wi-Fi drivers by - Andrea Merello - - A special thanks goes to Realtek for their support ! - -******************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ieee80211.h" - - -/* - - -802.11 Data Frame - - -802.11 frame_contorl for data frames - 2 bytes - ,-----------------------------------------------------------------------------------------. -bits | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | a | b | c | d | e | - |----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|------| -val | 0 | 0 | 0 | 1 | x | 0 | 0 | 0 | 1 | 0 | x | x | x | x | x | - |----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|-----|------| -desc | ^-ver-^ | ^type-^ | ^-----subtype-----^ | to |from |more |retry| pwr |more |wep | - | | | x=0 data,x=1 data+ack | DS | DS |frag | | mgm |data | | - '-----------------------------------------------------------------------------------------' - /\ - | -802.11 Data Frame | - ,--------- 'ctrl' expands to >-----------' - | - ,--'---,-------------------------------------------------------------. -Bytes | 2 | 2 | 6 | 6 | 6 | 2 | 0..2312 | 4 | - |------|------|---------|---------|---------|------|---------|------| -Desc. | ctrl | dura | DA/RA | TA | SA | Sequ | Frame | fcs | - | | tion | (BSSID) | | | ence | data | | - `--------------------------------------------------| |------' -Total: 28 non-data bytes `----.----' - | - .- 'Frame data' expands to <---------------------------' - | - V - ,---------------------------------------------------. -Bytes | 1 | 1 | 1 | 3 | 2 | 0-2304 | - |------|------|---------|----------|------|---------| -Desc. | SNAP | SNAP | Control |Eth Tunnel| Type | IP | - | DSAP | SSAP | | | | Packet | - | 0xAA | 0xAA |0x03 (UI)|0x00-00-F8| | | - `-----------------------------------------| | -Total: 8 non-data bytes `----.----' - | - .- 'IP Packet' expands, if WEP enabled, to <--' - | - V - ,-----------------------. -Bytes | 4 | 0-2296 | 4 | - |-----|-----------|-----| -Desc. | IV | Encrypted | ICV | - | | IP Packet | | - `-----------------------' -Total: 8 non-data bytes - - -802.3 Ethernet Data Frame - - ,-----------------------------------------. -Bytes | 6 | 6 | 2 | Variable | 4 | - |-------|-------|------|-----------|------| -Desc. | Dest. | Source| Type | IP Packet | fcs | - | MAC | MAC | | | | - `-----------------------------------------' -Total: 18 non-data bytes - -In the event that fragmentation is required, the incoming payload is split into -N parts of size ieee->fts. The first fragment contains the SNAP header and the -remaining packets are just data. - -If encryption is enabled, each fragment payload size is reduced by enough space -to add the prefix and postfix (IV and ICV totalling 8 bytes in the case of WEP) -So if you have 1500 bytes of payload with ieee->fts set to 500 without -encryption it will take 3 frames. With WEP it will take 4 frames as the -payload of each frame is reduced to 492 bytes. - -* SKB visualization -* -* ,- skb->data -* | -* | ETHERNET HEADER ,-<-- PAYLOAD -* | | 14 bytes from skb->data -* | 2 bytes for Type --> ,T. | (sizeof ethhdr) -* | | | | -* |,-Dest.--. ,--Src.---. | | | -* | 6 bytes| | 6 bytes | | | | -* v | | | | | | -* 0 | v 1 | v | v 2 -* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 -* ^ | ^ | ^ | -* | | | | | | -* | | | | `T' <---- 2 bytes for Type -* | | | | -* | | '---SNAP--' <-------- 6 bytes for SNAP -* | | -* `-IV--' <-------------------- 4 bytes for IV (WEP) -* -* SNAP HEADER -* -*/ - -static u8 P802_1H_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0xf8 }; -static u8 RFC1042_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0x00 }; - -static inline int ieee80211_put_snap(u8 *data, u16 h_proto) -{ - struct ieee80211_snap_hdr *snap; - u8 *oui; - - snap = (struct ieee80211_snap_hdr *)data; - snap->dsap = 0xaa; - snap->ssap = 0xaa; - snap->ctrl = 0x03; - - if (h_proto == 0x8137 || h_proto == 0x80f3) - oui = P802_1H_OUI; - else - oui = RFC1042_OUI; - snap->oui[0] = oui[0]; - snap->oui[1] = oui[1]; - snap->oui[2] = oui[2]; - - *(u16 *)(data + SNAP_SIZE) = htons(h_proto); - - return SNAP_SIZE + sizeof(u16); -} - -int ieee80211_encrypt_fragment(struct ieee80211_device *ieee, - struct sk_buff *frag, int hdr_len) -{ - struct ieee80211_crypt_data* crypt = ieee->crypt[ieee->tx_keyidx]; - int res; - - /* - * added to care about null crypt condition, to solve that system hangs - * when shared keys error - */ - if (!crypt || !crypt->ops) - return -1; - -#ifdef CONFIG_IEEE80211_CRYPT_TKIP - struct ieee80211_hdr_4addr *header; - - if (ieee->tkip_countermeasures && - crypt && crypt->ops && strcmp(crypt->ops->name, "TKIP") == 0) { - header = (struct ieee80211_hdr_4addr *)frag->data; - if (net_ratelimit()) { - netdev_dbg(ieee->dev, "TKIP countermeasures: dropped " - "TX packet to %pM\n", header->addr1); - } - return -1; - } -#endif - /* - * To encrypt, frame format is: - * IV (4 bytes), clear payload (including SNAP), ICV (4 bytes) - * - * PR: FIXME: Copied from hostap. Check fragmentation/MSDU/MPDU - * encryption. - * - * Host-based IEEE 802.11 fragmentation for TX is not yet supported, so - * call both MSDU and MPDU encryption functions from here. - */ - atomic_inc(&crypt->refcnt); - res = 0; - if (crypt->ops->encrypt_msdu) - res = crypt->ops->encrypt_msdu(frag, hdr_len, crypt->priv); - if (res == 0 && crypt->ops->encrypt_mpdu) - res = crypt->ops->encrypt_mpdu(frag, hdr_len, crypt->priv); - - atomic_dec(&crypt->refcnt); - if (res < 0) { - netdev_info(ieee->dev, "Encryption failed: len=%d.\n", frag->len); - ieee->ieee_stats.tx_discards++; - return -1; - } - - return 0; -} - - -void ieee80211_txb_free(struct ieee80211_txb *txb) -{ - int i; - if (unlikely(!txb)) - return; - for (i = 0; i < txb->nr_frags; i++) - if (txb->fragments[i]) - dev_kfree_skb_any(txb->fragments[i]); - kfree(txb); -} - -static struct ieee80211_txb *ieee80211_alloc_txb(int nr_frags, int txb_size, - gfp_t gfp_mask) -{ - struct ieee80211_txb *txb; - int i; - txb = kmalloc( - sizeof(struct ieee80211_txb) + (sizeof(u8 *) * nr_frags), - gfp_mask); - if (!txb) - return NULL; - - memset(txb, 0, sizeof(struct ieee80211_txb)); - txb->nr_frags = nr_frags; - txb->frag_size = txb_size; - - for (i = 0; i < nr_frags; i++) { - txb->fragments[i] = dev_alloc_skb(txb_size); - if (unlikely(!txb->fragments[i])) { - i--; - break; - } - } - if (unlikely(i != nr_frags)) { - while (i >= 0) - dev_kfree_skb_any(txb->fragments[i--]); - kfree(txb); - return NULL; - } - return txb; -} - -/* - * Classify the to-be send data packet - * Need to acquire the sent queue index. - */ -static int ieee80211_classify(struct sk_buff *skb, - struct ieee80211_network *network) -{ - struct ether_header *eh = (struct ether_header *)skb->data; - unsigned int wme_UP = 0; - - if (!network->QoS_Enable) { - skb->priority = 0; - return(wme_UP); - } - - if (eh->ether_type == __constant_htons(ETHERTYPE_IP)) { - const struct iphdr *ih = (struct iphdr *)(skb->data + - sizeof(struct ether_header)); - wme_UP = (ih->tos >> 5)&0x07; - } else if (vlan_tx_tag_present(skb)) {/* vtag packet */ -#ifndef VLAN_PRI_SHIFT -#define VLAN_PRI_SHIFT 13 /* Shift to find VLAN user priority */ -#define VLAN_PRI_MASK 7 /* Mask for user priority bits in VLAN */ -#endif - u32 tag = vlan_tx_tag_get(skb); - wme_UP = (tag >> VLAN_PRI_SHIFT) & VLAN_PRI_MASK; - } else if (ETH_P_PAE == ntohs(((struct ethhdr *)skb->data)->h_proto)) { - wme_UP = 7; - } - - skb->priority = wme_UP; - return(wme_UP); -} - -/* SKBs are added to the ieee->tx_queue. */ -int ieee80211_rtl_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct ieee80211_device *ieee = netdev_priv(dev); - struct ieee80211_txb *txb = NULL; - struct ieee80211_hdr_3addrqos *frag_hdr; - int i, bytes_per_frag, nr_frags, bytes_last_frag, frag_size; - unsigned long flags; - struct net_device_stats *stats = &ieee->stats; - int ether_type, encrypt; - int bytes, fc, qos_ctl, hdr_len; - struct sk_buff *skb_frag; - struct ieee80211_hdr_3addrqos header = { /* Ensure zero initialized */ - .duration_id = 0, - .seq_ctl = 0, - .qos_ctl = 0 - }; - u8 dest[ETH_ALEN], src[ETH_ALEN]; - - struct ieee80211_crypt_data* crypt; - - spin_lock_irqsave(&ieee->lock, flags); - - /* - * If there is no driver handler to take the TXB, don't bother - * creating it... - */ - if ((!ieee->hard_start_xmit && - !(ieee->softmac_features & IEEE_SOFTMAC_TX_QUEUE)) || - ((!ieee->softmac_data_hard_start_xmit && - (ieee->softmac_features & IEEE_SOFTMAC_TX_QUEUE)))) { - netdev_warn(ieee->dev, "No xmit handler.\n"); - goto success; - } - - ieee80211_classify(skb,&ieee->current_network); - if (likely(ieee->raw_tx == 0)){ - - if (unlikely(skb->len < SNAP_SIZE + sizeof(u16))) { - netdev_warn(ieee->dev, "skb too small (%d).\n", skb->len); - goto success; - } - - ether_type = ntohs(((struct ethhdr *)skb->data)->h_proto); - - crypt = ieee->crypt[ieee->tx_keyidx]; - - encrypt = !(ether_type == ETH_P_PAE && ieee->ieee802_1x) && - ieee->host_encrypt && crypt && crypt->ops; - - if (!encrypt && ieee->ieee802_1x && - ieee->drop_unencrypted && ether_type != ETH_P_PAE) { - stats->tx_dropped++; - goto success; - } - - #ifdef CONFIG_IEEE80211_DEBUG - if (crypt && !encrypt && ether_type == ETH_P_PAE) { - struct eapol *eap = (struct eapol *)(skb->data + - sizeof(struct ethhdr) - SNAP_SIZE - sizeof(u16)); - IEEE80211_DEBUG_EAP("TX: IEEE 802.11 EAPOL frame: %s\n", - eap_get_type(eap->type)); - } - #endif - - /* Save source and destination addresses */ - memcpy(&dest, skb->data, ETH_ALEN); - memcpy(&src, skb->data+ETH_ALEN, ETH_ALEN); - - /* Advance the SKB to the start of the payload */ - skb_pull(skb, sizeof(struct ethhdr)); - - /* Determine total amount of storage required for TXB packets */ - bytes = skb->len + SNAP_SIZE + sizeof(u16); - - if (ieee->current_network.QoS_Enable) { - if (encrypt) - fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA | - IEEE80211_FCTL_WEP; - else - fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA; - - } else { - if (encrypt) - fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA | - IEEE80211_FCTL_WEP; - else - fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA; - } - - if (ieee->iw_mode == IW_MODE_INFRA) { - fc |= IEEE80211_FCTL_TODS; - /* To DS: Addr1 = BSSID, Addr2 = SA, Addr3 = DA */ - memcpy(&header.addr1, ieee->current_network.bssid, ETH_ALEN); - memcpy(&header.addr2, &src, ETH_ALEN); - memcpy(&header.addr3, &dest, ETH_ALEN); - } else if (ieee->iw_mode == IW_MODE_ADHOC) { - /* - * not From/To DS: Addr1 = DA, Addr2 = SA, - * Addr3 = BSSID - */ - memcpy(&header.addr1, dest, ETH_ALEN); - memcpy(&header.addr2, src, ETH_ALEN); - memcpy(&header.addr3, ieee->current_network.bssid, ETH_ALEN); - } - header.frame_ctl = cpu_to_le16(fc); - - /* - * Determine fragmentation size based on destination (multicast - * and broadcast are not fragmented) - */ - if (is_multicast_ether_addr(header.addr1)) { - frag_size = MAX_FRAG_THRESHOLD; - qos_ctl = QOS_CTL_NOTCONTAIN_ACK; - } else { - /* default:392 */ - frag_size = ieee->fts; - qos_ctl = 0; - } - - if (ieee->current_network.QoS_Enable) { - hdr_len = IEEE80211_3ADDR_LEN + 2; - /* skb->priority is set in the ieee80211_classify() */ - qos_ctl |= skb->priority; - header.qos_ctl = cpu_to_le16(qos_ctl); - } else { - hdr_len = IEEE80211_3ADDR_LEN; - } - - /* - * Determine amount of payload per fragment. Regardless of if - * this stack is providing the full 802.11 header, one will - * eventually be affixed to this fragment -- so we must account - * for it when determining the amount of payload space. - */ - bytes_per_frag = frag_size - hdr_len; - if (ieee->config & - (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS)) - bytes_per_frag -= IEEE80211_FCS_LEN; - - /* Each fragment may need to have room for encryption pre/postfix */ - if (encrypt) - bytes_per_frag -= crypt->ops->extra_prefix_len + - crypt->ops->extra_postfix_len; - - /* - * Number of fragments is the total bytes_per_frag / - * payload_per_fragment - */ - nr_frags = bytes / bytes_per_frag; - bytes_last_frag = bytes % bytes_per_frag; - if (bytes_last_frag) - nr_frags++; - else - bytes_last_frag = bytes_per_frag; - - /* - * When we allocate the TXB we allocate enough space for the - * reserve and full fragment bytes (bytes_per_frag doesn't - * include prefix, postfix, header, FCS, etc.) - */ - txb = ieee80211_alloc_txb(nr_frags, frag_size, GFP_ATOMIC); - if (unlikely(!txb)) { - netdev_warn(ieee->dev, "Could not allocate TXB\n"); - goto failed; - } - txb->encrypted = encrypt; - txb->payload_size = bytes; - - for (i = 0; i < nr_frags; i++) { - skb_frag = txb->fragments[i]; - skb_frag->priority = UP2AC(skb->priority); - if (encrypt) - skb_reserve(skb_frag, crypt->ops->extra_prefix_len); - - frag_hdr = (struct ieee80211_hdr_3addrqos *)skb_put( - skb_frag, hdr_len); - memcpy(frag_hdr, &header, hdr_len); - - /* - * If this is not the last fragment, then add the MOREFRAGS - * bit to the frame control - */ - if (i != nr_frags - 1) { - frag_hdr->frame_ctl = cpu_to_le16( - fc | IEEE80211_FCTL_MOREFRAGS); - bytes = bytes_per_frag; - - } else { - /* The last fragment takes the remaining length */ - bytes = bytes_last_frag; - } - if (ieee->current_network.QoS_Enable) { - /* - * add 1 only indicate to corresponding seq - * number control 2006/7/12 - */ - frag_hdr->seq_ctl = cpu_to_le16( - ieee->seq_ctrl[UP2AC(skb->priority)+1]<<4 | i); - } else { - frag_hdr->seq_ctl = cpu_to_le16( - ieee->seq_ctrl[0]<<4 | i); - } - - /* Put a SNAP header on the first fragment */ - if (i == 0) { - ieee80211_put_snap( - skb_put(skb_frag, SNAP_SIZE + sizeof(u16)), - ether_type); - bytes -= SNAP_SIZE + sizeof(u16); - } - - memcpy(skb_put(skb_frag, bytes), skb->data, bytes); - - /* Advance the SKB... */ - skb_pull(skb, bytes); - - /* - * Encryption routine will move the header forward in - * order to insert the IV between the header and the - * payload - */ - if (encrypt) - ieee80211_encrypt_fragment(ieee, skb_frag, hdr_len); - if (ieee->config & - (CFG_IEEE80211_COMPUTE_FCS | CFG_IEEE80211_RESERVE_FCS)) - skb_put(skb_frag, 4); - } - /* Advance sequence number in data frame. */ - if (ieee->current_network.QoS_Enable) { - if (ieee->seq_ctrl[UP2AC(skb->priority) + 1] == 0xFFF) - ieee->seq_ctrl[UP2AC(skb->priority) + 1] = 0; - else - ieee->seq_ctrl[UP2AC(skb->priority) + 1]++; - } else { - if (ieee->seq_ctrl[0] == 0xFFF) - ieee->seq_ctrl[0] = 0; - else - ieee->seq_ctrl[0]++; - } - } else { - if (unlikely(skb->len < sizeof(struct ieee80211_hdr_3addr))) { - netdev_warn(ieee->dev, "skb too small (%d).\n", skb->len); - goto success; - } - - txb = ieee80211_alloc_txb(1, skb->len, GFP_ATOMIC); - if (!txb) { - netdev_warn(ieee->dev, "Could not allocate TXB\n"); - goto failed; - } - - txb->encrypted = 0; - txb->payload_size = skb->len; - memcpy(skb_put(txb->fragments[0], skb->len), skb->data, skb->len); - } - - success: - spin_unlock_irqrestore(&ieee->lock, flags); - dev_kfree_skb_any(skb); - if (txb) { - if (ieee->softmac_features & IEEE_SOFTMAC_TX_QUEUE) { - ieee80211_softmac_xmit(txb, ieee); - } else { - if ((*ieee->hard_start_xmit)(txb, dev) == 0) { - stats->tx_packets++; - stats->tx_bytes += txb->payload_size; - return NETDEV_TX_OK; - } - ieee80211_txb_free(txb); - } - } - - return NETDEV_TX_OK; - - failed: - spin_unlock_irqrestore(&ieee->lock, flags); - netif_stop_queue(dev); - stats->tx_errors++; - return NETDEV_TX_BUSY; - -} diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_wx.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_wx.c deleted file mode 100644 index 07c3f715a6f..00000000000 --- a/drivers/staging/rtl8187se/ieee80211/ieee80211_wx.c +++ /dev/null @@ -1,713 +0,0 @@ -/* - * Copyright(c) 2004 Intel Corporation. All rights reserved. - * - * Portions of this file are based on the WEP enablement code provided by the - * Host AP project hostap-drivers v0.1.3 - * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen - * - * Copyright (c) 2002-2003, Jouni Malinen - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * The full GNU General Public License is included in this distribution in the - * file called LICENSE. - * - * Contact Information: - * James P. Ketrenos - * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - */ - -#include -#include -#include -#include -#include - -#include "ieee80211.h" -static const char *ieee80211_modes[] = { - "?", "a", "b", "ab", "g", "ag", "bg", "abg" -}; - -#define MAX_CUSTOM_LEN 64 -static inline char *rtl818x_translate_scan(struct ieee80211_device *ieee, - char *start, char *stop, - struct ieee80211_network *network, - struct iw_request_info *info) -{ - char custom[MAX_CUSTOM_LEN]; - char *p; - struct iw_event iwe; - int i, j; - u8 max_rate, rate; - - /* First entry *MUST* be the AP MAC address */ - iwe.cmd = SIOCGIWAP; - iwe.u.ap_addr.sa_family = ARPHRD_ETHER; - ether_addr_copy(iwe.u.ap_addr.sa_data, network->bssid); - start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_ADDR_LEN); - - /* Remaining entries will be displayed in the order we provide them */ - - /* Add the ESSID */ - iwe.cmd = SIOCGIWESSID; - iwe.u.data.flags = 1; - if (network->ssid_len == 0) { - iwe.u.data.length = sizeof(""); - start = iwe_stream_add_point(info, start, stop, &iwe, ""); - } else { - iwe.u.data.length = min_t(u8, network->ssid_len, 32); - start = iwe_stream_add_point(info, start, stop, &iwe, network->ssid); - } - /* Add the protocol name */ - iwe.cmd = SIOCGIWNAME; - snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11%s", ieee80211_modes[network->mode]); - start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_CHAR_LEN); - - /* Add mode */ - iwe.cmd = SIOCGIWMODE; - if (network->capability & - (WLAN_CAPABILITY_BSS | WLAN_CAPABILITY_IBSS)) { - if (network->capability & WLAN_CAPABILITY_BSS) - iwe.u.mode = IW_MODE_MASTER; - else - iwe.u.mode = IW_MODE_ADHOC; - - start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_UINT_LEN); - } - - /* Add frequency/channel */ - iwe.cmd = SIOCGIWFREQ; - iwe.u.freq.m = network->channel; - iwe.u.freq.e = 0; - iwe.u.freq.i = 0; - start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_FREQ_LEN); - - /* Add encryption capability */ - iwe.cmd = SIOCGIWENCODE; - if (network->capability & WLAN_CAPABILITY_PRIVACY) - iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; - else - iwe.u.data.flags = IW_ENCODE_DISABLED; - iwe.u.data.length = 0; - start = iwe_stream_add_point(info, start, stop, &iwe, network->ssid); - - /* Add basic and extended rates */ - max_rate = 0; - p = custom; - p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Rates (Mb/s): "); - for (i = 0, j = 0; i < network->rates_len; ) { - if (j < network->rates_ex_len && - ((network->rates_ex[j] & 0x7F) < - (network->rates[i] & 0x7F))) - rate = network->rates_ex[j++] & 0x7F; - else - rate = network->rates[i++] & 0x7F; - if (rate > max_rate) - max_rate = rate; - p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), - "%d%s ", rate >> 1, (rate & 1) ? ".5" : ""); - } - for (; j < network->rates_ex_len; j++) { - rate = network->rates_ex[j] & 0x7F; - p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), - "%d%s ", rate >> 1, (rate & 1) ? ".5" : ""); - if (rate > max_rate) - max_rate = rate; - } - - iwe.cmd = SIOCGIWRATE; - iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; - iwe.u.bitrate.value = max_rate * 500000; - start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_PARAM_LEN); - - iwe.cmd = IWEVCUSTOM; - iwe.u.data.length = p - custom; - if (iwe.u.data.length) - start = iwe_stream_add_point(info, start, stop, &iwe, custom); - - /* Add quality statistics */ - /* TODO: Fix these values... */ - if (network->stats.signal == 0 || network->stats.rssi == 0) - netdev_info(ieee->dev, "========>signal:%d, rssi:%d\n", - network->stats.signal, network->stats.rssi); - iwe.cmd = IWEVQUAL; - iwe.u.qual.qual = network->stats.signalstrength; - iwe.u.qual.level = network->stats.signal; - iwe.u.qual.noise = network->stats.noise; - iwe.u.qual.updated = network->stats.mask & IEEE80211_STATMASK_WEMASK; - if (!(network->stats.mask & IEEE80211_STATMASK_RSSI)) - iwe.u.qual.updated |= IW_QUAL_LEVEL_INVALID; - if (!(network->stats.mask & IEEE80211_STATMASK_NOISE)) - iwe.u.qual.updated |= IW_QUAL_NOISE_INVALID; - if (!(network->stats.mask & IEEE80211_STATMASK_SIGNAL)) - iwe.u.qual.updated |= IW_QUAL_QUAL_INVALID; - iwe.u.qual.updated = 7; - start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_QUAL_LEN); - - iwe.cmd = IWEVCUSTOM; - p = custom; - - iwe.u.data.length = p - custom; - if (iwe.u.data.length) - start = iwe_stream_add_point(info, start, stop, &iwe, custom); - - memset(&iwe, 0, sizeof(iwe)); - if (network->wpa_ie_len) { - char buf[MAX_WPA_IE_LEN]; - memcpy(buf, network->wpa_ie, network->wpa_ie_len); - iwe.cmd = IWEVGENIE; - iwe.u.data.length = network->wpa_ie_len; - start = iwe_stream_add_point(info, start, stop, &iwe, buf); - } - - memset(&iwe, 0, sizeof(iwe)); - if (network->rsn_ie_len) { - char buf[MAX_WPA_IE_LEN]; - memcpy(buf, network->rsn_ie, network->rsn_ie_len); - iwe.cmd = IWEVGENIE; - iwe.u.data.length = network->rsn_ie_len; - start = iwe_stream_add_point(info, start, stop, &iwe, buf); - } - - /* Add EXTRA: Age to display seconds since last beacon/probe response - * for given network. - */ - iwe.cmd = IWEVCUSTOM; - p = custom; - p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), - " Last beacon: %lums ago", (jiffies - network->last_scanned) / (HZ / 100)); - iwe.u.data.length = p - custom; - if (iwe.u.data.length) - start = iwe_stream_add_point(info, start, stop, &iwe, custom); - - return start; -} - -int ieee80211_wx_get_scan(struct ieee80211_device *ieee, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ieee80211_network *network; - unsigned long flags; - int err = 0; - char *ev = extra; - char *stop = ev + wrqu->data.length; - int i = 0; - - IEEE80211_DEBUG_WX("Getting scan\n"); - down(&ieee->wx_sem); - spin_lock_irqsave(&ieee->lock, flags); - - if (!ieee->bHwRadioOff) { - list_for_each_entry(network, &ieee->network_list, list) { - i++; - - if ((stop-ev) < 200) { - err = -E2BIG; - break; - } - if (ieee->scan_age == 0 || - time_after(network->last_scanned + ieee->scan_age, jiffies)) { - ev = rtl818x_translate_scan(ieee, ev, stop, network, info); - } else - IEEE80211_DEBUG_SCAN( - "Not showing network '%s (" - "%pM)' due to age (%lums).\n", - escape_essid(network->ssid, - network->ssid_len), - network->bssid, - (jiffies - network->last_scanned) / (HZ / 100)); - } - } - spin_unlock_irqrestore(&ieee->lock, flags); - up(&ieee->wx_sem); - wrqu->data.length = ev - extra; - wrqu->data.flags = 0; - IEEE80211_DEBUG_WX("exit: %d networks returned.\n", i); - - return err; -} - -int ieee80211_wx_set_encode(struct ieee80211_device *ieee, - struct iw_request_info *info, - union iwreq_data *wrqu, char *keybuf) -{ - struct iw_point *erq = &(wrqu->encoding); - struct net_device *dev = ieee->dev; - struct ieee80211_security sec = { - .flags = 0 - }; - int i, key, key_provided, len; - struct ieee80211_crypt_data **crypt; - - IEEE80211_DEBUG_WX("SET_ENCODE\n"); - - key = erq->flags & IW_ENCODE_INDEX; - if (key) { - if (key > WEP_KEYS) - return -EINVAL; - key--; - key_provided = 1; - } else { - key_provided = 0; - key = ieee->tx_keyidx; - } - - IEEE80211_DEBUG_WX("Key: %d [%s]\n", key, key_provided ? - "provided" : "default"); - - crypt = &ieee->crypt[key]; - - if (erq->flags & IW_ENCODE_DISABLED) { - if (key_provided && *crypt) { - IEEE80211_DEBUG_WX("Disabling encryption on key %d.\n", - key); - ieee80211_crypt_delayed_deinit(ieee, crypt); - } else - IEEE80211_DEBUG_WX("Disabling encryption.\n"); - - /* Check all the keys to see if any are still configured, - * and if no key index was provided, de-init them all. - */ - for (i = 0; i < WEP_KEYS; i++) { - if (ieee->crypt[i] != NULL) { - if (key_provided) - break; - ieee80211_crypt_delayed_deinit( - ieee, &ieee->crypt[i]); - } - } - - if (i == WEP_KEYS) { - sec.enabled = 0; - sec.level = SEC_LEVEL_0; - sec.flags |= SEC_ENABLED | SEC_LEVEL; - } - - goto done; - } - - sec.enabled = 1; - sec.flags |= SEC_ENABLED; - - if (*crypt != NULL && (*crypt)->ops != NULL && - strcmp((*crypt)->ops->name, "WEP") != 0) { - /* changing to use WEP; deinit previously used algorithm - * on this key. - */ - ieee80211_crypt_delayed_deinit(ieee, crypt); - } - - if (*crypt == NULL) { - struct ieee80211_crypt_data *new_crypt; - - /* take WEP into use */ - new_crypt = kzalloc(sizeof(struct ieee80211_crypt_data), - GFP_KERNEL); - if (new_crypt == NULL) - return -ENOMEM; - new_crypt->ops = ieee80211_get_crypto_ops("WEP"); - if (!new_crypt->ops) - new_crypt->ops = ieee80211_get_crypto_ops("WEP"); - - if (new_crypt->ops) - new_crypt->priv = new_crypt->ops->init(key); - - if (!new_crypt->ops || !new_crypt->priv) { - kfree(new_crypt); - new_crypt = NULL; - - netdev_warn(ieee->dev, - "could not initialize WEP: load module ieee80211_crypt_wep\n"); - return -EOPNOTSUPP; - } - *crypt = new_crypt; - } - - /* If a new key was provided, set it up */ - if (erq->length > 0) { - len = erq->length <= 5 ? 5 : 13; - memcpy(sec.keys[key], keybuf, erq->length); - if (len > erq->length) - memset(sec.keys[key] + erq->length, 0, - len - erq->length); - IEEE80211_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n", - key, escape_essid(sec.keys[key], len), - erq->length, len); - sec.key_sizes[key] = len; - (*crypt)->ops->set_key(sec.keys[key], len, NULL, - (*crypt)->priv); - sec.flags |= (1 << key); - /* This ensures a key will be activated if no key is - * explicitly set. - */ - if (key == sec.active_key) - sec.flags |= SEC_ACTIVE_KEY; - ieee->tx_keyidx = key; - } else { - len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN, - NULL, (*crypt)->priv); - if (len == 0) { - /* Set a default key of all 0 */ - IEEE80211_DEBUG_WX("Setting key %d to all zero.\n", - key); - memset(sec.keys[key], 0, 13); - (*crypt)->ops->set_key(sec.keys[key], 13, NULL, - (*crypt)->priv); - sec.key_sizes[key] = 13; - sec.flags |= (1 << key); - } - - /* No key data - just set the default TX key index */ - if (key_provided) { - IEEE80211_DEBUG_WX( - "Setting key %d to default Tx key.\n", key); - ieee->tx_keyidx = key; - sec.active_key = key; - sec.flags |= SEC_ACTIVE_KEY; - } - } - - done: - ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED); - sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY; - sec.flags |= SEC_AUTH_MODE; - IEEE80211_DEBUG_WX("Auth: %s\n", sec.auth_mode == WLAN_AUTH_OPEN ? - "OPEN" : "SHARED KEY"); - - /* For now we just support WEP, so only set that security level... - * TODO: When WPA is added this is one place that needs to change - */ - sec.flags |= SEC_LEVEL; - sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */ - - if (ieee->set_security) - ieee->set_security(dev, &sec); - - /* Do not reset port if card is in Managed mode since resetting will - * generate new IEEE 802.11 authentication which may end up in looping - * with IEEE 802.1X. If your hardware requires a reset after WEP - * configuration (for example... Prism2), implement the reset_port in - * the callbacks structures used to initialize the 802.11 stack. - */ - if (ieee->reset_on_keychange && - ieee->iw_mode != IW_MODE_INFRA && - ieee->reset_port && ieee->reset_port(dev)) { - netdev_dbg(ieee->dev, "reset_port failed\n"); - return -EINVAL; - } - return 0; -} - -int ieee80211_wx_get_encode(struct ieee80211_device *ieee, - struct iw_request_info *info, - union iwreq_data *wrqu, char *keybuf) -{ - struct iw_point *erq = &(wrqu->encoding); - int len, key; - struct ieee80211_crypt_data *crypt; - - IEEE80211_DEBUG_WX("GET_ENCODE\n"); - - if (ieee->iw_mode == IW_MODE_MONITOR) - return -1; - - key = erq->flags & IW_ENCODE_INDEX; - if (key) { - if (key > WEP_KEYS) - return -EINVAL; - key--; - } else - key = ieee->tx_keyidx; - - crypt = ieee->crypt[key]; - erq->flags = key + 1; - - if (crypt == NULL || crypt->ops == NULL) { - erq->length = 0; - erq->flags |= IW_ENCODE_DISABLED; - return 0; - } - - if (strcmp(crypt->ops->name, "WEP") != 0) { - /* only WEP is supported with wireless extensions, so just - * report that encryption is used. - */ - erq->length = 0; - erq->flags |= IW_ENCODE_ENABLED; - return 0; - } - - len = crypt->ops->get_key(keybuf, WEP_KEY_LEN, NULL, crypt->priv); - erq->length = (len >= 0 ? len : 0); - - erq->flags |= IW_ENCODE_ENABLED; - - if (ieee->open_wep) - erq->flags |= IW_ENCODE_OPEN; - else - erq->flags |= IW_ENCODE_RESTRICTED; - - return 0; -} - -int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct net_device *dev = ieee->dev; - struct iw_point *encoding = &wrqu->encoding; - struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; - int i, idx, ret = 0; - int group_key = 0; - const char *alg; - struct ieee80211_crypto_ops *ops; - struct ieee80211_crypt_data **crypt; - - struct ieee80211_security sec = { - .flags = 0, - }; - idx = encoding->flags & IW_ENCODE_INDEX; - if (idx) { - if (idx < 1 || idx > WEP_KEYS) - return -EINVAL; - idx--; - } else - idx = ieee->tx_keyidx; - - if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { - crypt = &ieee->crypt[idx]; - group_key = 1; - } else { - /* some Cisco APs use idx>0 for unicast in dynamic WEP */ - if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP) - return -EINVAL; - if (ieee->iw_mode == IW_MODE_INFRA) - crypt = &ieee->crypt[idx]; - else - return -EINVAL; - } - - sec.flags |= SEC_ENABLED; - if ((encoding->flags & IW_ENCODE_DISABLED) || - ext->alg == IW_ENCODE_ALG_NONE) { - if (*crypt) - ieee80211_crypt_delayed_deinit(ieee, crypt); - - for (i = 0; i < WEP_KEYS; i++) - if (ieee->crypt[i] != NULL) - break; - - if (i == WEP_KEYS) { - sec.enabled = 0; - sec.level = SEC_LEVEL_0; - sec.flags |= SEC_LEVEL; - } - goto done; - } - - sec.enabled = 1; - - switch (ext->alg) { - case IW_ENCODE_ALG_WEP: - alg = "WEP"; - break; - case IW_ENCODE_ALG_TKIP: - alg = "TKIP"; - break; - case IW_ENCODE_ALG_CCMP: - alg = "CCMP"; - break; - default: - IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n", - dev->name, ext->alg); - ret = -EINVAL; - goto done; - } - - ops = ieee80211_get_crypto_ops(alg); - if (ops == NULL) - ops = ieee80211_get_crypto_ops(alg); - if (ops == NULL) { - IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n", - dev->name, ext->alg); - netdev_err(ieee->dev, "========>unknown crypto alg %d\n", - ext->alg); - ret = -EINVAL; - goto done; - } - - if (*crypt == NULL || (*crypt)->ops != ops) { - struct ieee80211_crypt_data *new_crypt; - - ieee80211_crypt_delayed_deinit(ieee, crypt); - - new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL); - if (new_crypt == NULL) { - ret = -ENOMEM; - goto done; - } - new_crypt->ops = ops; - if (new_crypt->ops) - new_crypt->priv = new_crypt->ops->init(idx); - if (new_crypt->priv == NULL) { - kfree(new_crypt); - ret = -EINVAL; - goto done; - } - *crypt = new_crypt; - - } - - if (ext->key_len > 0 && (*crypt)->ops->set_key && - (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq, - (*crypt)->priv) < 0) { - IEEE80211_DEBUG_WX("%s: key setting failed\n", dev->name); - netdev_err(ieee->dev, "key setting failed\n"); - ret = -EINVAL; - goto done; - } -#if 1 - if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { - ieee->tx_keyidx = idx; - sec.active_key = idx; - sec.flags |= SEC_ACTIVE_KEY; - } - - if (ext->alg != IW_ENCODE_ALG_NONE) { - memcpy(sec.keys[idx], ext->key, ext->key_len); - sec.key_sizes[idx] = ext->key_len; - sec.flags |= (1 << idx); - if (ext->alg == IW_ENCODE_ALG_WEP) { - sec.flags |= SEC_LEVEL; - sec.level = SEC_LEVEL_1; - } else if (ext->alg == IW_ENCODE_ALG_TKIP) { - sec.flags |= SEC_LEVEL; - sec.level = SEC_LEVEL_2; - } else if (ext->alg == IW_ENCODE_ALG_CCMP) { - sec.flags |= SEC_LEVEL; - sec.level = SEC_LEVEL_3; - } - /* Don't set sec level for group keys. */ - if (group_key) - sec.flags &= ~SEC_LEVEL; - } -#endif -done: - if (ieee->set_security) - ieee->set_security(ieee->dev, &sec); - - if (ieee->reset_on_keychange && - ieee->iw_mode != IW_MODE_INFRA && - ieee->reset_port && ieee->reset_port(dev)) { - IEEE80211_DEBUG_WX("%s: reset_port failed\n", dev->name); - return -EINVAL; - } - - return ret; -} - -int ieee80211_wx_set_mlme(struct ieee80211_device *ieee, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_mlme *mlme = (struct iw_mlme *) extra; -#if 1 - switch (mlme->cmd) { - case IW_MLME_DEAUTH: - case IW_MLME_DISASSOC: - ieee80211_disassociate(ieee); - break; - default: - return -EOPNOTSUPP; - } -#endif - return 0; -} - -int ieee80211_wx_set_auth(struct ieee80211_device *ieee, - struct iw_request_info *info, - struct iw_param *data, char *extra) -{ - switch (data->flags & IW_AUTH_INDEX) { - case IW_AUTH_WPA_VERSION: - /* need to support wpa2 here */ - break; - case IW_AUTH_CIPHER_PAIRWISE: - case IW_AUTH_CIPHER_GROUP: - case IW_AUTH_KEY_MGMT: - /* Host AP driver does not use these parameters and allows - * wpa_supplicant to control them internally. - */ - break; - case IW_AUTH_TKIP_COUNTERMEASURES: - ieee->tkip_countermeasures = data->value; - break; - case IW_AUTH_DROP_UNENCRYPTED: - ieee->drop_unencrypted = data->value; - break; - - case IW_AUTH_80211_AUTH_ALG: - ieee->open_wep = (data->value&IW_AUTH_ALG_OPEN_SYSTEM) ? 1 : 0; - break; - -#if 1 - case IW_AUTH_WPA_ENABLED: - ieee->wpa_enabled = (data->value) ? 1 : 0; - break; - -#endif - case IW_AUTH_RX_UNENCRYPTED_EAPOL: - ieee->ieee802_1x = data->value; - break; - case IW_AUTH_PRIVACY_INVOKED: - ieee->privacy_invoked = data->value; - break; - default: - return -EOPNOTSUPP; - } - return 0; -} - -#if 1 -int ieee80211_wx_set_gen_ie(struct ieee80211_device *ieee, u8 *ie, size_t len) -{ - u8 *buf = NULL; - - if (len > MAX_WPA_IE_LEN || (len && ie == NULL)) { - netdev_err(ieee->dev, "return error out, len:%zu\n", len); - return -EINVAL; - } - - if (len) { - if (len != ie[1]+2) { - netdev_err(ieee->dev, "len:%zu, ie:%d\n", len, ie[1]); - return -EINVAL; - } - buf = kmemdup(ie, len, GFP_KERNEL); - if (buf == NULL) - return -ENOMEM; - kfree(ieee->wpa_ie); - ieee->wpa_ie = buf; - ieee->wpa_ie_len = len; - } else { - kfree(ieee->wpa_ie); - ieee->wpa_ie = NULL; - ieee->wpa_ie_len = 0; - } - - return 0; - -} -#endif diff --git a/drivers/staging/rtl8187se/r8180.h b/drivers/staging/rtl8187se/r8180.h deleted file mode 100644 index 9f931dba1d8..00000000000 --- a/drivers/staging/rtl8187se/r8180.h +++ /dev/null @@ -1,640 +0,0 @@ -/* - * This is part of rtl8180 OpenSource driver. - * Copyright (C) Andrea Merello 2004-2005 - * Released under the terms of GPL (General Public Licence) - * - * Parts of this driver are based on the GPL part of the official realtek driver - * - * Parts of this driver are based on the rtl8180 driver skeleton from Patric - * Schenke & Andres Salomon - * - * Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver - * - * We want to thanks the Authors of those projects and the Ndiswrapper project - * Authors. - */ - -#ifndef R8180H -#define R8180H - -#include - -#define RTL8180_MODULE_NAME "r8180" -#define DMESG(x, a...) printk(KERN_INFO RTL8180_MODULE_NAME ": " x "\n", ## a) -#define DMESGW(x, a...) printk(KERN_WARNING RTL8180_MODULE_NAME ": WW:" x "\n", ## a) -#define DMESGE(x, a...) printk(KERN_WARNING RTL8180_MODULE_NAME ": EE:" x "\n", ## a) - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* for rtnl_lock() */ -#include -#include -#include /* Necessary because we use the proc fs. */ -#include -#include "ieee80211/ieee80211.h" -#include - -#define EPROM_93c46 0 -#define EPROM_93c56 1 - -#define RTL_IOCTL_WPA_SUPPLICANT (SIOCIWFIRSTPRIV + 30) - -#define DEFAULT_FRAG_THRESHOLD 2342U -#define MIN_FRAG_THRESHOLD 256U -#define DEFAULT_RTS_THRESHOLD 2342U -#define MIN_RTS_THRESHOLD 0U -#define MAX_RTS_THRESHOLD 2342U -#define DEFAULT_BEACONINTERVAL 0x64U - -#define DEFAULT_RETRY_RTS 7 -#define DEFAULT_RETRY_DATA 7 - -#define BEACON_QUEUE 6 - -#define aSifsTime 10 - -#define sCrcLng 4 -#define sAckCtsLng 112 /* bits in ACK and CTS frames. */ -/* +by amy 080312. */ -#define RATE_ADAPTIVE_TIMER_PERIOD 300 - -enum wireless_mode { - WIRELESS_MODE_UNKNOWN = 0x00, - WIRELESS_MODE_A = 0x01, - WIRELESS_MODE_B = 0x02, - WIRELESS_MODE_G = 0x04, - WIRELESS_MODE_AUTO = 0x08, -}; - -struct chnl_access_setting { - u16 sifs_timer; - u16 difs_timer; - u16 slot_time_timer; - u16 eifs_timer; - u16 cwmin_index; - u16 cwmax_index; -}; - -enum nic_t { - NIC_8185 = 1, - NIC_8185B -}; - -typedef u32 AC_CODING; -#define AC0_BE 0 /* ACI: 0x00 */ /* Best Effort. */ -#define AC1_BK 1 /* ACI: 0x01 */ /* Background. */ -#define AC2_VI 2 /* ACI: 0x10 */ /* Video. */ -#define AC3_VO 3 /* ACI: 0x11 */ /* Voice. */ -#define AC_MAX 4 /* Max: define total number; Should not to be used as a real - * enum. - */ - -/* - * ECWmin/ECWmax field. - * Ref: WMM spec 2.2.2: WME Parameter Element, p.13. - */ -typedef union _ECW { - u8 charData; - struct { - u8 ECWmin:4; - u8 ECWmax:4; - } f; /* Field */ -} ECW, *PECW; - -/* - * ACI/AIFSN Field. Ref: WMM spec 2.2.2: WME Parameter Element, p.12. - */ -typedef union _ACI_AIFSN { - u8 charData; - - struct { - u8 AIFSN:4; - u8 ACM:1; - u8 ACI:2; - u8 Reserved:1; - } f; /* Field */ -} ACI_AIFSN, *PACI_AIFSN; - -/* - * AC Parameters Record Format. - * Ref: WMM spec 2.2.2: WME Parameter Element, p.12. - */ -typedef union _AC_PARAM { - u32 longData; - u8 charData[4]; - - struct { - ACI_AIFSN AciAifsn; - ECW Ecw; - u16 TXOPLimit; - } f; /* Field */ -} AC_PARAM, *PAC_PARAM; - -struct buffer { - struct buffer *next; - u32 *buf; - dma_addr_t dma; -}; - -/* YJ,modified,080828. */ -struct stats { - unsigned long txrdu; - unsigned long rxrdu; - unsigned long rxnolast; - unsigned long rxnodata; - unsigned long rxnopointer; - unsigned long txnperr; - unsigned long txresumed; - unsigned long rxerr; - unsigned long rxoverflow; - unsigned long rxint; - unsigned long txbkpokint; - unsigned long txbepoking; - unsigned long txbkperr; - unsigned long txbeperr; - unsigned long txnpokint; - unsigned long txhpokint; - unsigned long txhperr; - unsigned long ints; - unsigned long shints; - unsigned long txoverflow; - unsigned long rxdmafail; - unsigned long txbeacon; - unsigned long txbeaconerr; - unsigned long txlpokint; - unsigned long txlperr; - unsigned long txretry; /* retry number tony 20060601 */ - unsigned long rxcrcerrmin; /* crc error (0-500) */ - unsigned long rxcrcerrmid; /* crc error (500-1000) */ - unsigned long rxcrcerrmax; /* crc error (>1000) */ - unsigned long rxicverr; /* ICV error */ -}; - -#define MAX_LD_SLOT_NUM 10 -#define KEEP_ALIVE_INTERVAL 20 /* in seconds. */ -#define CHECK_FOR_HANG_PERIOD 2 /* be equal to watchdog check time. */ -#define DEFAULT_KEEP_ALIVE_LEVEL 1 -#define DEFAULT_SLOT_NUM 2 -#define POWER_PROFILE_AC 0 -#define POWER_PROFILE_BATTERY 1 - -struct link_detect_t { - u32 rx_frame_num[MAX_LD_SLOT_NUM]; /* number of Rx Frame. - * CheckForHang_period to determine - * link status. - */ - u16 slot_num; /* number of CheckForHang period to determine link status, - * default is 2. - */ - u16 slot_index; - u32 num_tx_ok_in_period; /* number of packet transmitted during - * CheckForHang. - */ - u32 num_rx_ok_in_period; /* number of packet received during - * CheckForHang. - */ - u8 idle_count; /* (KEEP_ALIVE_INTERVAL / CHECK_FOR_HANG_PERIOD) */ - u32 last_num_tx_unicast; - u32 last_num_rx_unicast; - - bool b_busy_traffic; /* when it is set to 1, UI cann't scan at will. */ -}; - -/* YJ,modified,080828,end */ - -/* by amy for led - * ========================================================================== - * LED customization. - * ========================================================================== - */ -enum led_strategy_8185 { - SW_LED_MODE0, - SW_LED_MODE1, - HW_LED, /* HW control 2 LEDs, LED0 and LED1 (there are 4 different - * control modes). */ -}; - -enum rt_rf_power_state { - RF_ON, - RF_SLEEP, - RF_OFF -}; - -enum _ReasonCode { - unspec_reason = 0x1, - auth_not_valid = 0x2, - deauth_lv_ss = 0x3, - inactivity = 0x4, - ap_overload = 0x5, - class2_err = 0x6, - class3_err = 0x7, - disas_lv_ss = 0x8, - asoc_not_auth = 0x9, - - /* ----MIC_CHECK */ - mic_failure = 0xe, - /* ----END MIC_CHECK */ - - /* Reason code defined in 802.11i D10.0 p.28. */ - invalid_IE = 0x0d, - four_way_tmout = 0x0f, - two_way_tmout = 0x10, - IE_dismatch = 0x11, - invalid_Gcipher = 0x12, - invalid_Pcipher = 0x13, - invalid_AKMP = 0x14, - unsup_RSNIEver = 0x15, - invalid_RSNIE = 0x16, - auth_802_1x_fail = 0x17, - ciper_reject = 0x18, - - /* Reason code defined in 7.3.1.7, 802.1e D13.0, p.42. Added by Annie, - * 2005-11-15. - */ - QoS_unspec = 0x20, /* 32 */ - QAP_bandwidth = 0x21, /* 33 */ - poor_condition = 0x22, /* 34 */ - no_facility = 0x23, /* 35 */ - /* Where is 36??? */ - req_declined = 0x25, /* 37 */ - invalid_param = 0x26, /* 38 */ - req_not_honored = 0x27, /* 39 */ - TS_not_created = 0x2F, /* 47 */ - DL_not_allowed = 0x30, /* 48 */ - dest_not_exist = 0x31, /* 49 */ - dest_not_QSTA = 0x32, /* 50 */ -}; - -enum rt_ps_mode { - ACTIVE, /* Active/Continuous access. */ - MAX_PS, /* Max power save mode. */ - FAST_PS /* Fast power save mode. */ -}; - -/* by amy for power save. */ -struct r8180_priv { - struct pci_dev *pdev; - - short epromtype; - int irq; - struct ieee80211_device *ieee80211; - - short plcp_preamble_mode; /* 0:auto 1:short 2:long */ - - spinlock_t irq_th_lock; - spinlock_t tx_lock; - spinlock_t ps_lock; - spinlock_t rf_ps_lock; - - u16 irq_mask; - short irq_enabled; - struct net_device *dev; - short chan; - short sens; - short max_sens; - u8 chtxpwr[15]; /* channels from 1 to 14, 0 not used. */ - u8 chtxpwr_ofdm[15]; /* channels from 1 to 14, 0 not used. */ - u8 channel_plan; /* it's the channel plan index. */ - short up; - short crcmon; /* if 1 allow bad crc frame reception in monitor mode. */ - - struct timer_list scan_timer; - spinlock_t scan_lock; - u8 active_probe; - struct semaphore wx_sem; - short hw_wep; - - short digphy; - short antb; - short diversity; - u32 key0[4]; - short (*rf_set_sens)(struct net_device *dev, short sens); - void (*rf_set_chan)(struct net_device *dev, short ch); - void (*rf_close)(struct net_device *dev); - void (*rf_init)(struct net_device *dev); - void (*rf_sleep)(struct net_device *dev); - void (*rf_wakeup)(struct net_device *dev); - /* short rate; */ - short promisc; - /* stats */ - struct stats stats; - struct link_detect_t link_detect; /* YJ,add,080828 */ - struct iw_statistics wstats; - - /* RX stuff. */ - u32 *rxring; - u32 *rxringtail; - dma_addr_t rxringdma; - struct buffer *rxbuffer; - struct buffer *rxbufferhead; - int rxringcount; - u16 rxbuffersize; - - struct sk_buff *rx_skb; - - short rx_skb_complete; - - u32 rx_prevlen; - - u32 *txmapring; - u32 *txbkpring; - u32 *txbepring; - u32 *txvipring; - u32 *txvopring; - u32 *txhpring; - dma_addr_t txmapringdma; - dma_addr_t txbkpringdma; - dma_addr_t txbepringdma; - dma_addr_t txvipringdma; - dma_addr_t txvopringdma; - dma_addr_t txhpringdma; - u32 *txmapringtail; - u32 *txbkpringtail; - u32 *txbepringtail; - u32 *txvipringtail; - u32 *txvopringtail; - u32 *txhpringtail; - u32 *txmapringhead; - u32 *txbkpringhead; - u32 *txbepringhead; - u32 *txvipringhead; - u32 *txvopringhead; - u32 *txhpringhead; - struct buffer *txmapbufs; - struct buffer *txbkpbufs; - struct buffer *txbepbufs; - struct buffer *txvipbufs; - struct buffer *txvopbufs; - struct buffer *txhpbufs; - struct buffer *txmapbufstail; - struct buffer *txbkpbufstail; - struct buffer *txbepbufstail; - struct buffer *txvipbufstail; - struct buffer *txvopbufstail; - struct buffer *txhpbufstail; - - int txringcount; - int txbuffsize; - struct tasklet_struct irq_rx_tasklet; - u8 dma_poll_mask; - - /* adhoc/master mode stuff. */ - u32 *txbeaconringtail; - dma_addr_t txbeaconringdma; - u32 *txbeaconring; - int txbeaconcount; - struct buffer *txbeaconbufs; - struct buffer *txbeaconbufstail; - - u8 retry_data; - u8 retry_rts; - u16 rts; - - /* by amy for led. */ - enum led_strategy_8185 led_strategy; - /* by amy for led. */ - - /* by amy for power save. */ - struct timer_list watch_dog_timer; - bool bInactivePs; - bool bSwRfProcessing; - enum rt_rf_power_state eInactivePowerState; - enum rt_rf_power_state eRFPowerState; - u32 RfOffReason; - bool RFChangeInProgress; - bool SetRFPowerStateInProgress; - u8 RFProgType; - bool bLeisurePs; - enum rt_ps_mode dot11PowerSaveMode; - u8 TxPollingTimes; - - bool bApBufOurFrame; /* TRUE if AP buffer our unicast data , we will - * keep eAwake until receive data or timeout. - */ - u8 WaitBufDataBcnCount; - u8 WaitBufDataTimeOut; - - /* by amy for power save. */ - /* by amy for antenna. */ - u8 EEPROMSwAntennaDiversity; - bool EEPROMDefaultAntenna1; - u8 RegSwAntennaDiversityMechanism; - bool bSwAntennaDiverity; - u8 RegDefaultAntenna; - bool bDefaultAntenna1; - u8 SignalStrength; - long Stats_SignalStrength; - long LastSignalStrengthInPercent; /* In percentage, used for smoothing, - * e.g. Moving Average. - */ - u8 SignalQuality; /* in 0-100 index. */ - long Stats_SignalQuality; - long RecvSignalPower; /* in dBm. */ - long Stats_RecvSignalPower; - u8 LastRxPktAntenna; /* +by amy 080312 Antenna which received the lasted - * packet. 0: Aux, 1:Main. Added by Roger, - * 2008.01.25. - */ - u32 AdRxOkCnt; - long AdRxSignalStrength; - u8 CurrAntennaIndex; /* Index to current Antenna (both Tx and Rx). */ - u8 AdTickCount; /* Times of SwAntennaDiversityTimer happened. */ - u8 AdCheckPeriod; /* # of period SwAntennaDiversityTimer to check Rx - * signal strength for SW Antenna Diversity. - */ - u8 AdMinCheckPeriod; /* Min value of AdCheckPeriod. */ - u8 AdMaxCheckPeriod; /* Max value of AdCheckPeriod. */ - long AdRxSsThreshold; /* Signal strength threshold to switch antenna. */ - long AdMaxRxSsThreshold; /* Max value of AdRxSsThreshold. */ - bool bAdSwitchedChecking; /* TRUE if we shall shall check Rx signal - * strength for last time switching antenna. - */ - long AdRxSsBeforeSwitched; /* Rx signal strength before we switched - * antenna. - */ - struct timer_list SwAntennaDiversityTimer; - /* by amy for antenna {by amy 080312 */ - - /* Crystal calibration. Added by Roger, 2007.12.11. */ - - bool bXtalCalibration; /* Crystal calibration.*/ - u8 XtalCal_Xin; /* Crystal calibration for Xin. 0~7.5pF */ - u8 XtalCal_Xout; /* Crystal calibration for Xout. 0~7.5pF */ - - /* Tx power tracking with thermal meter indication. - * Added by Roger, 2007.12.11. - */ - - bool bTxPowerTrack; /* Tx Power tracking. */ - u8 ThermalMeter; /* Thermal meter reference indication. */ - - /* Dynamic Initial Gain Adjustment Mechanism. Added by Bruce, - * 2007-02-14. - */ - bool bDigMechanism; /* TRUE if DIG is enabled, FALSE ow. */ - bool bRegHighPowerMechanism; /* For High Power Mechanism. 061010, - * by rcnjko. - */ - u32 FalseAlarmRegValue; - u8 RegDigOfdmFaUpTh; /* Upper threshold of OFDM false alarm, which is - * used in DIG. - */ - u8 DIG_NumberFallbackVote; - u8 DIG_NumberUpgradeVote; - /* For HW antenna diversity, added by Roger, 2008.01.30. */ - u32 AdMainAntennaRxOkCnt; /* Main antenna Rx OK count. */ - u32 AdAuxAntennaRxOkCnt; /* Aux antenna Rx OK count. */ - bool bHWAdSwitched; /* TRUE if we has switched default antenna by HW - * evaluation. - */ - /* RF High Power upper/lower threshold. */ - u8 RegHiPwrUpperTh; - u8 RegHiPwrLowerTh; - /* RF RSSI High Power upper/lower Threshold. */ - u8 RegRSSIHiPwrUpperTh; - u8 RegRSSIHiPwrLowerTh; - /* Current CCK RSSI value to determine CCK high power, asked by SD3 DZ, - * by Bruce, 2007-04-12. - */ - u8 CurCCKRSSI; - bool bCurCCKPkt; - /* High Power Mechanism. Added by amy, 080312. */ - bool bToUpdateTxPwr; - long UndecoratedSmoothedSS; - long UndecoratedSmoothedRxPower; - u8 RSSI; - char RxPower; - u8 InitialGain; - /* For adjust Dig Threshold during Legacy/Leisure Power Save Mode. */ - u32 DozePeriodInPast2Sec; - /* Don't access BB/RF under disable PLL situation. */ - u8 InitialGainBackUp; - u8 RegBModeGainStage; - /* by amy for rate adaptive */ - struct timer_list rateadapter_timer; - u32 RateAdaptivePeriod; - bool bEnhanceTxPwr; - bool bUpdateARFR; - int ForcedDataRate; /* Force Data Rate. 0: Auto, 0x02: 1M ~ 0x6C: 54M.) - */ - u32 NumTxUnicast; /* YJ,add,080828,for keep alive. */ - u8 keepAliveLevel; /*YJ,add,080828,for KeepAlive. */ - unsigned long NumTxOkTotal; - u16 LastRetryCnt; - u16 LastRetryRate; - unsigned long LastTxokCnt; - unsigned long LastRxokCnt; - u16 CurrRetryCnt; - unsigned long LastTxOKBytes; - unsigned long NumTxOkBytesTotal; - u8 LastFailTxRate; - long LastFailTxRateSS; - u8 FailTxRateCount; - u32 LastTxThroughput; - /* for up rate. */ - unsigned short bTryuping; - u8 CurrTxRate; /* the rate before up. */ - u16 CurrRetryRate; - u16 TryupingCount; - u8 TryDownCountLowData; - u8 TryupingCountNoData; - - u8 CurrentOperaRate; - struct work_struct reset_wq; - struct work_struct watch_dog_wq; - short ack_tx_to_ieee; - - u8 dma_poll_stop_mask; - - u16 ShortRetryLimit; - u16 LongRetryLimit; - u16 EarlyRxThreshold; - u32 TransmitConfig; - u32 ReceiveConfig; - u32 IntrMask; - - struct chnl_access_setting ChannelAccessSetting; -}; - -#define MANAGE_PRIORITY 0 -#define BK_PRIORITY 1 -#define BE_PRIORITY 2 -#define VI_PRIORITY 3 -#define VO_PRIORITY 4 -#define HI_PRIORITY 5 -#define BEACON_PRIORITY 6 - -#define LOW_PRIORITY VI_PRIORITY -#define NORM_PRIORITY VO_PRIORITY -/* AC2Queue mapping. */ -#define AC2Q(_ac) (((_ac) == WME_AC_VO) ? VO_PRIORITY : \ - ((_ac) == WME_AC_VI) ? VI_PRIORITY : \ - ((_ac) == WME_AC_BK) ? BK_PRIORITY : \ - BE_PRIORITY) - -short rtl8180_tx(struct net_device *dev, u8 *skbuf, int len, int priority, - bool morefrag, short fragdesc, int rate); - -u8 read_nic_byte(struct net_device *dev, int x); -u32 read_nic_dword(struct net_device *dev, int x); -u16 read_nic_word(struct net_device *dev, int x); -void write_nic_byte(struct net_device *dev, int x, u8 y); -void write_nic_word(struct net_device *dev, int x, u16 y); -void write_nic_dword(struct net_device *dev, int x, u32 y); -void force_pci_posting(struct net_device *dev); - -void rtl8180_rtx_disable(struct net_device *); -void rtl8180_set_anaparam(struct net_device *dev, u32 a); -void rtl8185_set_anaparam2(struct net_device *dev, u32 a); -void rtl8180_set_hw_wep(struct net_device *dev); -void rtl8180_no_hw_wep(struct net_device *dev); -void rtl8180_update_msr(struct net_device *dev); -void rtl8180_beacon_tx_disable(struct net_device *dev); -void rtl8180_beacon_rx_disable(struct net_device *dev); -int rtl8180_down(struct net_device *dev); -int rtl8180_up(struct net_device *dev); -void rtl8180_commit(struct net_device *dev); -void rtl8180_set_chan(struct net_device *dev, short ch); -void write_phy(struct net_device *dev, u8 adr, u8 data); -void write_phy_cck(struct net_device *dev, u8 adr, u32 data); -void write_phy_ofdm(struct net_device *dev, u8 adr, u32 data); -void rtl8185_tx_antenna(struct net_device *dev, u8 ant); -void rtl8185_rf_pins_enable(struct net_device *dev); -void IPSEnter(struct net_device *dev); -void IPSLeave(struct net_device *dev); -int get_curr_tx_free_desc(struct net_device *dev, int priority); -void UpdateInitialGain(struct net_device *dev); -bool SetAntennaConfig87SE(struct net_device *dev, u8 DefaultAnt, - bool bAntDiversity); - -void rtl8185b_adapter_start(struct net_device *dev); -void rtl8185b_rx_enable(struct net_device *dev); -void rtl8185b_tx_enable(struct net_device *dev); -void rtl8180_reset(struct net_device *dev); -void rtl8185b_irq_enable(struct net_device *dev); -void fix_rx_fifo(struct net_device *dev); -void fix_tx_fifo(struct net_device *dev); -void rtl8225z2_SetTXPowerLevel(struct net_device *dev, short ch); -void rtl8180_rate_adapter(struct work_struct *work); -bool MgntActSet_RF_State(struct net_device *dev, enum rt_rf_power_state StateToSet, - u32 ChangeSource); - -#endif - -/* fun with the built-in ieee80211 stack... */ -extern int ieee80211_crypto_init(void); -extern void ieee80211_crypto_deinit(void); -extern int ieee80211_crypto_tkip_init(void); -extern void ieee80211_crypto_tkip_exit(void); -extern int ieee80211_crypto_ccmp_init(void); -extern void ieee80211_crypto_ccmp_exit(void); -extern int ieee80211_crypto_wep_init(void); -extern void ieee80211_crypto_wep_exit(void); diff --git a/drivers/staging/rtl8187se/r8180_93cx6.h b/drivers/staging/rtl8187se/r8180_93cx6.h deleted file mode 100644 index b52b5b0610a..00000000000 --- a/drivers/staging/rtl8187se/r8180_93cx6.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - This is part of rtl8180 OpenSource driver - Copyright (C) Andrea Merello 2004-2005 - Released under the terms of GPL (General Public Licence) - - Parts of this driver are based on the GPL part of the official realtek driver - Parts of this driver are based on the rtl8180 driver skeleton from Patric Schenke & Andres Salomon - Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver - - We want to tanks the Authors of such projects and the Ndiswrapper project Authors. -*/ - -/*This files contains card eeprom (93c46 or 93c56) programming routines*/ -/*memory is addressed by WORDS*/ - -#include "r8180.h" -#include "r8180_hw.h" - -#define EPROM_DELAY 10 - -#define EPROM_ANAPARAM_ADDRLWORD 0xd -#define EPROM_ANAPARAM_ADDRHWORD 0xe - -#define RFCHIPID 0x6 -#define RFCHIPID_INTERSIL 1 -#define RFCHIPID_RFMD 2 -#define RFCHIPID_PHILIPS 3 -#define RFCHIPID_MAXIM 4 -#define RFCHIPID_GCT 5 -#define RFCHIPID_RTL8225 9 -#define RF_ZEBRA2 11 -#define EPROM_TXPW_BASE 0x05 -#define RF_ZEBRA4 12 -#define RFCHIPID_RTL8255 0xa -#define RF_PARAM 0x19 -#define RF_PARAM_DIGPHY_SHIFT 0 -#define RF_PARAM_ANTBDEFAULT_SHIFT 1 -#define RF_PARAM_CARRIERSENSE_SHIFT 2 -#define RF_PARAM_CARRIERSENSE_MASK (3<<2) -#define ENERGY_TRESHOLD 0x17 -#define EPROM_VERSION 0x1E -#define MAC_ADR 0x7 - -#define CIS 0x18 - -#define EPROM_TXPW_OFDM_CH1_2 0x20 - -#define EPROM_TXPW_CH1_2 0x30 - -#define RTL818X_EEPROM_CMD_READ (1 << 0) -#define RTL818X_EEPROM_CMD_WRITE (1 << 1) -#define RTL818X_EEPROM_CMD_CK (1 << 2) -#define RTL818X_EEPROM_CMD_CS (1 << 3) - diff --git a/drivers/staging/rtl8187se/r8180_core.c b/drivers/staging/rtl8187se/r8180_core.c deleted file mode 100644 index a6022d4e757..00000000000 --- a/drivers/staging/rtl8187se/r8180_core.c +++ /dev/null @@ -1,3775 +0,0 @@ -/* - * This is part of rtl818x pci OpenSource driver - v 0.1 - * Copyright (C) Andrea Merello 2004-2005 - * Released under the terms of GPL (General Public License) - * - * Parts of this driver are based on the GPL part of the official - * Realtek driver. - * - * Parts of this driver are based on the rtl8180 driver skeleton - * from Patric Schenke & Andres Salomon. - * - * Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver. - * - * Parts of BB/RF code are derived from David Young rtl8180 netbsd driver. - * - * RSSI calc function from 'The Deuce' - * - * Some ideas borrowed from the 8139too.c driver included in linux kernel. - * - * We (I?) want to thanks the Authors of those projecs and also the - * Ndiswrapper's project Authors. - * - * A big big thanks goes also to Realtek corp. for their help in my attempt to - * add RTL8185 and RTL8225 support, and to David Young also. - * - * Power management interface routines. - * Written by Mariusz Matuszek. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#undef RX_DONT_PASS_UL -#undef DUMMY_RX - -#include -#include -#include -#include -#include -#include - -#include "r8180_hw.h" -#include "r8180.h" -#include "r8180_rtl8225.h" /* RTL8225 Radio frontend */ -#include "r8180_93cx6.h" /* Card EEPROM */ -#include "r8180_wx.h" -#include "r8180_dm.h" - -#include "ieee80211/dot11d.h" - -static struct pci_device_id rtl8180_pci_id_tbl[] = { - { - .vendor = PCI_VENDOR_ID_REALTEK, - .device = 0x8199, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = 0, - }, - { - .vendor = 0, - .device = 0, - .subvendor = 0, - .subdevice = 0, - .driver_data = 0, - } -}; - -static char ifname[IFNAMSIZ] = "wlan%d"; -static int hwwep; - -MODULE_LICENSE("GPL"); -MODULE_DEVICE_TABLE(pci, rtl8180_pci_id_tbl); -MODULE_AUTHOR("Andrea Merello "); -MODULE_DESCRIPTION("Linux driver for Realtek RTL8187SE WiFi cards"); - -module_param_string(ifname, ifname, sizeof(ifname), S_IRUGO|S_IWUSR); -module_param(hwwep, int, S_IRUGO|S_IWUSR); - -MODULE_PARM_DESC(hwwep, " Try to use hardware WEP support. Still broken and not available on all cards"); - -static int rtl8180_pci_probe(struct pci_dev *pdev, - const struct pci_device_id *id); - -static void rtl8180_pci_remove(struct pci_dev *pdev); - -static void rtl8180_shutdown(struct pci_dev *pdev) -{ - struct net_device *dev = pci_get_drvdata(pdev); - if (dev->netdev_ops->ndo_stop) - dev->netdev_ops->ndo_stop(dev); - pci_disable_device(pdev); -} - -static int rtl8180_suspend(struct pci_dev *pdev, pm_message_t state) -{ - struct net_device *dev = pci_get_drvdata(pdev); - - if (!netif_running(dev)) - goto out_pci_suspend; - - if (dev->netdev_ops->ndo_stop) - dev->netdev_ops->ndo_stop(dev); - - netif_device_detach(dev); - -out_pci_suspend: - pci_save_state(pdev); - pci_disable_device(pdev); - pci_set_power_state(pdev, pci_choose_state(pdev, state)); - return 0; -} - -static int rtl8180_resume(struct pci_dev *pdev) -{ - struct net_device *dev = pci_get_drvdata(pdev); - int err; - u32 val; - - pci_set_power_state(pdev, PCI_D0); - - err = pci_enable_device(pdev); - if (err) { - dev_err(&pdev->dev, "pci_enable_device failed on resume\n"); - - return err; - } - - pci_restore_state(pdev); - - /* - * Suspend/Resume resets the PCI configuration space, so we have to - * re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries - * from interfering with C3 CPU state. pci_restore_state won't help - * here since it only restores the first 64 bytes pci config header. - */ - pci_read_config_dword(pdev, 0x40, &val); - if ((val & 0x0000ff00) != 0) - pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); - - if (!netif_running(dev)) - goto out; - - if (dev->netdev_ops->ndo_open) - dev->netdev_ops->ndo_open(dev); - - netif_device_attach(dev); -out: - return 0; -} - -static struct pci_driver rtl8180_pci_driver = { - .name = RTL8180_MODULE_NAME, - .id_table = rtl8180_pci_id_tbl, - .probe = rtl8180_pci_probe, - .remove = rtl8180_pci_remove, - .suspend = rtl8180_suspend, - .resume = rtl8180_resume, - .shutdown = rtl8180_shutdown, -}; - -u8 read_nic_byte(struct net_device *dev, int x) -{ - return 0xff&readb((u8 __iomem *)dev->mem_start + x); -} - -u32 read_nic_dword(struct net_device *dev, int x) -{ - return readl((u8 __iomem *)dev->mem_start + x); -} - -u16 read_nic_word(struct net_device *dev, int x) -{ - return readw((u8 __iomem *)dev->mem_start + x); -} - -void write_nic_byte(struct net_device *dev, int x, u8 y) -{ - writeb(y, (u8 __iomem *)dev->mem_start + x); - udelay(20); -} - -void write_nic_dword(struct net_device *dev, int x, u32 y) -{ - writel(y, (u8 __iomem *)dev->mem_start + x); - udelay(20); -} - -void write_nic_word(struct net_device *dev, int x, u16 y) -{ - writew(y, (u8 __iomem *)dev->mem_start + x); - udelay(20); -} - -inline void force_pci_posting(struct net_device *dev) -{ - read_nic_byte(dev, EPROM_CMD); - mb(); -} - -static irqreturn_t rtl8180_interrupt(int irq, void *netdev); -void set_nic_rxring(struct net_device *dev); -void set_nic_txring(struct net_device *dev); -static struct net_device_stats *rtl8180_stats(struct net_device *dev); -void rtl8180_commit(struct net_device *dev); -void rtl8180_start_tx_beacon(struct net_device *dev); - -static struct proc_dir_entry *rtl8180_proc; - -static int proc_get_registers(struct seq_file *m, void *v) -{ - struct net_device *dev = m->private; - int i, n, max = 0xff; - - /* This dump the current register page */ - for (n = 0; n <= max;) { - seq_printf(m, "\nD: %2x > ", n); - - for (i = 0; i < 16 && n <= max; i++, n++) - seq_printf(m, "%2x ", read_nic_byte(dev, n)); - } - seq_putc(m, '\n'); - return 0; -} - -int get_curr_tx_free_desc(struct net_device *dev, int priority); - -static int proc_get_stats_hw(struct seq_file *m, void *v) -{ - return 0; -} - -static int proc_get_stats_rx(struct seq_file *m, void *v) -{ - struct net_device *dev = m->private; - struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); - - seq_printf(m, - "RX OK: %lu\n" - "RX Retry: %lu\n" - "RX CRC Error(0-500): %lu\n" - "RX CRC Error(500-1000): %lu\n" - "RX CRC Error(>1000): %lu\n" - "RX ICV Error: %lu\n", - priv->stats.rxint, - priv->stats.rxerr, - priv->stats.rxcrcerrmin, - priv->stats.rxcrcerrmid, - priv->stats.rxcrcerrmax, - priv->stats.rxicverr - ); - - return 0; -} - -static int proc_get_stats_tx(struct seq_file *m, void *v) -{ - struct net_device *dev = m->private; - struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); - unsigned long totalOK; - - totalOK = priv->stats.txnpokint + priv->stats.txhpokint + - priv->stats.txlpokint; - - seq_printf(m, - "TX OK: %lu\n" - "TX Error: %lu\n" - "TX Retry: %lu\n" - "TX beacon OK: %lu\n" - "TX beacon error: %lu\n", - totalOK, - priv->stats.txnperr+priv->stats.txhperr+priv->stats.txlperr, - priv->stats.txretry, - priv->stats.txbeacon, - priv->stats.txbeaconerr - ); - - return 0; -} - -static void rtl8180_proc_module_init(void) -{ - DMESG("Initializing proc filesystem"); - rtl8180_proc = proc_mkdir(RTL8180_MODULE_NAME, init_net.proc_net); -} - -static void rtl8180_proc_module_remove(void) -{ - remove_proc_entry(RTL8180_MODULE_NAME, init_net.proc_net); -} - -static void rtl8180_proc_remove_one(struct net_device *dev) -{ - remove_proc_subtree(dev->name, rtl8180_proc); -} - -/* - * seq_file wrappers for procfile show routines. - */ -static int rtl8180_proc_open(struct inode *inode, struct file *file) -{ - struct net_device *dev = proc_get_parent_data(inode); - int (*show)(struct seq_file *, void *) = PDE_DATA(inode); - - return single_open(file, show, dev); -} - -static const struct file_operations rtl8180_proc_fops = { - .open = rtl8180_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -/* - * Table of proc files we need to create. - */ -struct rtl8180_proc_file { - char name[12]; - int (*show)(struct seq_file *, void *); -}; - -static const struct rtl8180_proc_file rtl8180_proc_files[] = { - { "stats-hw", &proc_get_stats_hw }, - { "stats-rx", &proc_get_stats_rx }, - { "stats-tx", &proc_get_stats_tx }, - { "registers", &proc_get_registers }, - { "" } -}; - -static void rtl8180_proc_init_one(struct net_device *dev) -{ - const struct rtl8180_proc_file *f; - struct proc_dir_entry *dir; - - dir = proc_mkdir_data(dev->name, 0, rtl8180_proc, dev); - if (!dir) { - DMESGE("Unable to initialize /proc/net/r8180/%s\n", dev->name); - return; - } - - for (f = rtl8180_proc_files; f->name[0]; f++) { - if (!proc_create_data(f->name, S_IFREG | S_IRUGO, dir, - &rtl8180_proc_fops, f->show)) { - DMESGE("Unable to initialize /proc/net/r8180/%s/%s\n", - dev->name, f->name); - return; - } - } -} - -/* - * FIXME: check if we can use some standard already-existent - * data type+functions in kernel. - */ - -static short buffer_add(struct buffer **buffer, u32 *buf, dma_addr_t dma, - struct buffer **bufferhead) -{ - struct buffer *tmp; - - if (!*buffer) { - - *buffer = kmalloc(sizeof(struct buffer), GFP_KERNEL); - - if (*buffer == NULL) { - DMESGE("Failed to kmalloc head of TX/RX struct"); - return -1; - } - (*buffer)->next = *buffer; - (*buffer)->buf = buf; - (*buffer)->dma = dma; - if (bufferhead != NULL) - (*bufferhead) = (*buffer); - return 0; - } - tmp = *buffer; - - while (tmp->next != (*buffer)) - tmp = tmp->next; - tmp->next = kmalloc(sizeof(struct buffer), GFP_KERNEL); - if (tmp->next == NULL) { - DMESGE("Failed to kmalloc TX/RX struct"); - return -1; - } - tmp->next->buf = buf; - tmp->next->dma = dma; - tmp->next->next = *buffer; - - return 0; -} - -static void buffer_free(struct net_device *dev, struct buffer **buffer, int len, - short consistent) -{ - - struct buffer *tmp, *next; - struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); - struct pci_dev *pdev = priv->pdev; - - if (!*buffer) - return; - - tmp = *buffer; - - do { - next = tmp->next; - if (consistent) { - pci_free_consistent(pdev, len, - tmp->buf, tmp->dma); - } else { - pci_unmap_single(pdev, tmp->dma, - len, PCI_DMA_FROMDEVICE); - kfree(tmp->buf); - } - kfree(tmp); - tmp = next; - } while (next != *buffer); - - *buffer = NULL; -} - -int get_curr_tx_free_desc(struct net_device *dev, int priority) -{ - struct r8180_priv *priv = ieee80211_priv(dev); - u32 *tail; - u32 *head; - int ret; - - switch (priority) { - case MANAGE_PRIORITY: - head = priv->txmapringhead; - tail = priv->txmapringtail; - break; - case BK_PRIORITY: - head = priv->txbkpringhead; - tail = priv->txbkpringtail; - break; - case BE_PRIORITY: - head = priv->txbepringhead; - tail = priv->txbepringtail; - break; - case VI_PRIORITY: - head = priv->txvipringhead; - tail = priv->txvipringtail; - break; - case VO_PRIORITY: - head = priv->txvopringhead; - tail = priv->txvopringtail; - break; - case HI_PRIORITY: - head = priv->txhpringhead; - tail = priv->txhpringtail; - break; - default: - return -1; - } - - if (head <= tail) - ret = priv->txringcount - (tail - head)/8; - else - ret = (head - tail)/8; - - if (ret > priv->txringcount) - DMESG("BUG"); - - return ret; -} - -static short check_nic_enought_desc(struct net_device *dev, int priority) -{ - struct r8180_priv *priv = ieee80211_priv(dev); - struct ieee80211_device *ieee = netdev_priv(dev); - int requiredbyte; - int required; - - requiredbyte = priv->ieee80211->fts + - sizeof(struct ieee80211_header_data); - - if (ieee->current_network.QoS_Enable) - requiredbyte += 2; - - required = requiredbyte / (priv->txbuffsize-4); - - if (requiredbyte % priv->txbuffsize) - required++; - - /* for now we keep two free descriptor as a safety boundary - * between the tail and the head - */ - - return required + 2 < get_curr_tx_free_desc(dev, priority); -} - -void fix_tx_fifo(struct net_device *dev) -{ - struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); - u32 *tmp; - int i; - - for (tmp = priv->txmapring, i = 0; - i < priv->txringcount; - tmp += 8, i++) { - *tmp = *tmp & ~(1<<31); - } - - for (tmp = priv->txbkpring, i = 0; - i < priv->txringcount; - tmp += 8, i++) { - *tmp = *tmp & ~(1<<31); - } - - for (tmp = priv->txbepring, i = 0; - i < priv->txringcount; - tmp += 8, i++) { - *tmp = *tmp & ~(1<<31); - } - for (tmp = priv->txvipring, i = 0; - i < priv->txringcount; - tmp += 8, i++) { - *tmp = *tmp & ~(1<<31); - } - - for (tmp = priv->txvopring, i = 0; - i < priv->txringcount; - tmp += 8, i++) { - *tmp = *tmp & ~(1<<31); - } - - for (tmp = priv->txhpring, i = 0; - i < priv->txringcount; - tmp += 8, i++) { - *tmp = *tmp & ~(1<<31); - } - - for (tmp = priv->txbeaconring, i = 0; - i < priv->txbeaconcount; - tmp += 8, i++) { - *tmp = *tmp & ~(1<<31); - } - - priv->txmapringtail = priv->txmapring; - priv->txmapringhead = priv->txmapring; - priv->txmapbufstail = priv->txmapbufs; - - priv->txbkpringtail = priv->txbkpring; - priv->txbkpringhead = priv->txbkpring; - priv->txbkpbufstail = priv->txbkpbufs; - - priv->txbepringtail = priv->txbepring; - priv->txbepringhead = priv->txbepring; - priv->txbepbufstail = priv->txbepbufs; - - priv->txvipringtail = priv->txvipring; - priv->txvipringhead = priv->txvipring; - priv->txvipbufstail = priv->txvipbufs; - - priv->txvopringtail = priv->txvopring; - priv->txvopringhead = priv->txvopring; - priv->txvopbufstail = priv->txvopbufs; - - priv->txhpringtail = priv->txhpring; - priv->txhpringhead = priv->txhpring; - priv->txhpbufstail = priv->txhpbufs; - - priv->txbeaconringtail = priv->txbeaconring; - priv->txbeaconbufstail = priv->txbeaconbufs; - set_nic_txring(dev); - - ieee80211_reset_queue(priv->ieee80211); - priv->ack_tx_to_ieee = 0; -} - -void fix_rx_fifo(struct net_device *dev) -{ - struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); - u32 *tmp; - struct buffer *rxbuf; - u8 rx_desc_size; - - rx_desc_size = 8; /* 4*8 = 32 bytes */ - - for (tmp = priv->rxring, rxbuf = priv->rxbufferhead; - (tmp < (priv->rxring)+(priv->rxringcount)*rx_desc_size); - tmp += rx_desc_size, rxbuf = rxbuf->next) { - *(tmp+2) = rxbuf->dma; - *tmp = *tmp & ~0xfff; - *tmp = *tmp | priv->rxbuffersize; - *tmp |= (1<<31); - } - - priv->rxringtail = priv->rxring; - priv->rxbuffer = priv->rxbufferhead; - priv->rx_skb_complete = 1; - set_nic_rxring(dev); -} - -static void rtl8180_irq_disable(struct net_device *dev) -{ - struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); - - write_nic_dword(dev, IMR, 0); - force_pci_posting(dev); - priv->irq_enabled = 0; -} - -void rtl8180_set_mode(struct net_device *dev, int mode) -{ - u8 ecmd; - - ecmd = read_nic_byte(dev, EPROM_CMD); - ecmd = ecmd & ~EPROM_CMD_OPERATING_MODE_MASK; - ecmd = ecmd | (mode<ieee80211->state == IEEE80211_LINKED) { - if (priv->ieee80211->iw_mode == IW_MODE_ADHOC) - msr |= (MSR_LINK_ADHOC<ieee80211->iw_mode == IW_MODE_MASTER) - msr |= (MSR_LINK_MASTER<ieee80211->iw_mode == IW_MODE_INFRA) - msr |= (MSR_LINK_MANAGED< 14) || (ch < 1)) { - netdev_err(dev, "In %s: Invalid channel %d\n", __func__, ch); - return; - } - - priv->chan = ch; - priv->rf_set_chan(dev, priv->chan); -} - -void set_nic_txring(struct net_device *dev) -{ - struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); - - write_nic_dword(dev, TX_MANAGEPRIORITY_RING_ADDR, priv->txmapringdma); - write_nic_dword(dev, TX_BKPRIORITY_RING_ADDR, priv->txbkpringdma); - write_nic_dword(dev, TX_BEPRIORITY_RING_ADDR, priv->txbepringdma); - write_nic_dword(dev, TX_VIPRIORITY_RING_ADDR, priv->txvipringdma); - write_nic_dword(dev, TX_VOPRIORITY_RING_ADDR, priv->txvopringdma); - write_nic_dword(dev, TX_HIGHPRIORITY_RING_ADDR, priv->txhpringdma); - write_nic_dword(dev, TX_BEACON_RING_ADDR, priv->txbeaconringdma); -} - -void rtl8180_beacon_tx_enable(struct net_device *dev) -{ - struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); - - rtl8180_set_mode(dev, EPROM_CMD_CONFIG); - priv->dma_poll_stop_mask &= ~(TPPOLLSTOP_BQ); - write_nic_byte(dev, TPPollStop, priv->dma_poll_mask); - rtl8180_set_mode(dev, EPROM_CMD_NORMAL); -} - -void rtl8180_beacon_tx_disable(struct net_device *dev) -{ - struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); - - rtl8180_set_mode(dev, EPROM_CMD_CONFIG); - priv->dma_poll_stop_mask |= TPPOLLSTOP_BQ; - write_nic_byte(dev, TPPollStop, priv->dma_poll_stop_mask); - rtl8180_set_mode(dev, EPROM_CMD_NORMAL); - -} - -void rtl8180_rtx_disable(struct net_device *dev) -{ - u8 cmd; - struct r8180_priv *priv = ieee80211_priv(dev); - - cmd = read_nic_byte(dev, CMD); - write_nic_byte(dev, CMD, cmd & - ~((1<rx_skb_complete) - dev_kfree_skb_any(priv->rx_skb); -} - -static short alloc_tx_desc_ring(struct net_device *dev, int bufsize, int count, - int addr) -{ - int i; - u32 *desc; - u32 *tmp; - dma_addr_t dma_desc, dma_tmp; - struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); - struct pci_dev *pdev = priv->pdev; - void *buf; - - if ((bufsize & 0xfff) != bufsize) { - DMESGE("TX buffer allocation too large"); - return 0; - } - desc = (u32 *)pci_alloc_consistent(pdev, - sizeof(u32)*8*count+256, &dma_desc); - if (desc == NULL) - return -1; - - if (dma_desc & 0xff) - /* - * descriptor's buffer must be 256 byte aligned - * we shouldn't be here, since we set DMA mask ! - */ - WARN(1, "DMA buffer is not aligned\n"); - - tmp = desc; - - for (i = 0; i < count; i++) { - buf = (void *)pci_alloc_consistent(pdev, bufsize, &dma_tmp); - if (buf == NULL) - return -ENOMEM; - - switch (addr) { - case TX_MANAGEPRIORITY_RING_ADDR: - if (-1 == buffer_add(&priv->txmapbufs, - buf, dma_tmp, NULL)) { - DMESGE("Unable to allocate mem for buffer NP"); - return -ENOMEM; - } - break; - case TX_BKPRIORITY_RING_ADDR: - if (-1 == buffer_add(&priv->txbkpbufs, - buf, dma_tmp, NULL)) { - DMESGE("Unable to allocate mem for buffer LP"); - return -ENOMEM; - } - break; - case TX_BEPRIORITY_RING_ADDR: - if (-1 == buffer_add(&priv->txbepbufs, - buf, dma_tmp, NULL)) { - DMESGE("Unable to allocate mem for buffer NP"); - return -ENOMEM; - } - break; - case TX_VIPRIORITY_RING_ADDR: - if (-1 == buffer_add(&priv->txvipbufs, - buf, dma_tmp, NULL)) { - DMESGE("Unable to allocate mem for buffer LP"); - return -ENOMEM; - } - break; - case TX_VOPRIORITY_RING_ADDR: - if (-1 == buffer_add(&priv->txvopbufs, - buf, dma_tmp, NULL)) { - DMESGE("Unable to allocate mem for buffer NP"); - return -ENOMEM; - } - break; - case TX_HIGHPRIORITY_RING_ADDR: - if (-1 == buffer_add(&priv->txhpbufs, - buf, dma_tmp, NULL)) { - DMESGE("Unable to allocate mem for buffer HP"); - return -ENOMEM; - } - break; - case TX_BEACON_RING_ADDR: - if (-1 == buffer_add(&priv->txbeaconbufs, - buf, dma_tmp, NULL)) { - DMESGE("Unable to allocate mem for buffer BP"); - return -ENOMEM; - } - break; - } - *tmp = *tmp & ~(1<<31); /* descriptor empty, owned by the drv */ - *(tmp+2) = (u32)dma_tmp; - *(tmp+3) = bufsize; - - if (i+1 < count) - *(tmp+4) = (u32)dma_desc+((i+1)*8*4); - else - *(tmp+4) = (u32)dma_desc; - - tmp = tmp+8; - } - - switch (addr) { - case TX_MANAGEPRIORITY_RING_ADDR: - priv->txmapringdma = dma_desc; - priv->txmapring = desc; - break; - case TX_BKPRIORITY_RING_ADDR: - priv->txbkpringdma = dma_desc; - priv->txbkpring = desc; - break; - case TX_BEPRIORITY_RING_ADDR: - priv->txbepringdma = dma_desc; - priv->txbepring = desc; - break; - case TX_VIPRIORITY_RING_ADDR: - priv->txvipringdma = dma_desc; - priv->txvipring = desc; - break; - case TX_VOPRIORITY_RING_ADDR: - priv->txvopringdma = dma_desc; - priv->txvopring = desc; - break; - case TX_HIGHPRIORITY_RING_ADDR: - priv->txhpringdma = dma_desc; - priv->txhpring = desc; - break; - case TX_BEACON_RING_ADDR: - priv->txbeaconringdma = dma_desc; - priv->txbeaconring = desc; - break; - - } - - return 0; -} - -static void free_tx_desc_rings(struct net_device *dev) -{ - struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); - struct pci_dev *pdev = priv->pdev; - int count = priv->txringcount; - - pci_free_consistent(pdev, sizeof(u32)*8*count+256, - priv->txmapring, priv->txmapringdma); - buffer_free(dev, &(priv->txmapbufs), priv->txbuffsize, 1); - - pci_free_consistent(pdev, sizeof(u32)*8*count+256, - priv->txbkpring, priv->txbkpringdma); - buffer_free(dev, &(priv->txbkpbufs), priv->txbuffsize, 1); - - pci_free_consistent(pdev, sizeof(u32)*8*count+256, - priv->txbepring, priv->txbepringdma); - buffer_free(dev, &(priv->txbepbufs), priv->txbuffsize, 1); - - pci_free_consistent(pdev, sizeof(u32)*8*count+256, - priv->txvipring, priv->txvipringdma); - buffer_free(dev, &(priv->txvipbufs), priv->txbuffsize, 1); - - pci_free_consistent(pdev, sizeof(u32)*8*count+256, - priv->txvopring, priv->txvopringdma); - buffer_free(dev, &(priv->txvopbufs), priv->txbuffsize, 1); - - pci_free_consistent(pdev, sizeof(u32)*8*count+256, - priv->txhpring, priv->txhpringdma); - buffer_free(dev, &(priv->txhpbufs), priv->txbuffsize, 1); - - count = priv->txbeaconcount; - pci_free_consistent(pdev, sizeof(u32)*8*count+256, - priv->txbeaconring, priv->txbeaconringdma); - buffer_free(dev, &(priv->txbeaconbufs), priv->txbuffsize, 1); -} - -static void free_rx_desc_ring(struct net_device *dev) -{ - struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); - struct pci_dev *pdev = priv->pdev; - int count = priv->rxringcount; - - pci_free_consistent(pdev, sizeof(u32)*8*count+256, - priv->rxring, priv->rxringdma); - - buffer_free(dev, &(priv->rxbuffer), priv->rxbuffersize, 0); -} - -static short alloc_rx_desc_ring(struct net_device *dev, u16 bufsize, int count) -{ - int i; - u32 *desc; - u32 *tmp; - dma_addr_t dma_desc, dma_tmp; - struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); - struct pci_dev *pdev = priv->pdev; - void *buf; - u8 rx_desc_size; - - rx_desc_size = 8; /* 4*8 = 32 bytes */ - - if ((bufsize & 0xfff) != bufsize) { - DMESGE("RX buffer allocation too large"); - return -1; - } - - desc = (u32 *)pci_alloc_consistent(pdev, - sizeof(u32) * rx_desc_size * count + 256, &dma_desc); - - if (dma_desc & 0xff) - /* - * descriptor's buffer must be 256 byte aligned - * should never happen since we specify the DMA mask - */ - WARN(1, "DMA buffer is not aligned\n"); - - priv->rxring = desc; - priv->rxringdma = dma_desc; - tmp = desc; - - for (i = 0; i < count; i++) { - buf = kmalloc(bufsize * sizeof(u8), GFP_ATOMIC); - if (buf == NULL) { - DMESGE("Failed to kmalloc RX buffer"); - return -1; - } - - dma_tmp = pci_map_single(pdev, buf, bufsize * sizeof(u8), - PCI_DMA_FROMDEVICE); - if (pci_dma_mapping_error(pdev, dma_tmp)) - return -1; - if (-1 == buffer_add(&(priv->rxbuffer), buf, dma_tmp, - &(priv->rxbufferhead))) { - DMESGE("Unable to allocate mem RX buf"); - return -1; - } - *tmp = 0; /* zero pads the header of the descriptor */ - *tmp = *tmp | (bufsize&0xfff); - *(tmp+2) = (u32)dma_tmp; - *tmp = *tmp | (1<<31); /* descriptor void, owned by the NIC */ - - tmp = tmp+rx_desc_size; - } - - /* this is the last descriptor */ - *(tmp - rx_desc_size) = *(tmp - rx_desc_size) | (1 << 30); - - return 0; -} - - -void set_nic_rxring(struct net_device *dev) -{ - u8 pgreg; - struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); - - pgreg = read_nic_byte(dev, PGSELECT); - write_nic_byte(dev, PGSELECT, pgreg & ~(1<rxringdma); -} - -void rtl8180_reset(struct net_device *dev) -{ - u8 cr; - - rtl8180_irq_disable(dev); - - cr = read_nic_byte(dev, CMD); - cr = cr & 2; - cr = cr | (1< 12) - return 10; - return rtl_rate[rate]; -} - -inline u8 rtl8180_IsWirelessBMode(u16 rate) -{ - if (((rate <= 110) && (rate != 60) && (rate != 90)) || (rate == 220)) - return 1; - else - return 0; -} - -u16 N_DBPSOfRate(u16 DataRate); - -static u16 ComputeTxTime(u16 FrameLength, u16 DataRate, u8 bManagementFrame, - u8 bShortPreamble) -{ - u16 FrameTime; - u16 N_DBPS; - u16 Ceiling; - - if (rtl8180_IsWirelessBMode(DataRate)) { - if (bManagementFrame || !bShortPreamble || DataRate == 10) - /* long preamble */ - FrameTime = (u16)(144+48+(FrameLength*8/(DataRate/10))); - else - /* short preamble */ - FrameTime = (u16)(72+24+(FrameLength*8/(DataRate/10))); - - if ((FrameLength*8 % (DataRate/10)) != 0) /* get the ceilling */ - FrameTime++; - } else { /* 802.11g DSSS-OFDM PLCP length field calculation. */ - N_DBPS = N_DBPSOfRate(DataRate); - Ceiling = (16 + 8*FrameLength + 6) / N_DBPS - + (((16 + 8*FrameLength + 6) % N_DBPS) ? 1 : 0); - FrameTime = (u16)(16 + 4 + 4*Ceiling + 6); - } - return FrameTime; -} - -u16 N_DBPSOfRate(u16 DataRate) -{ - u16 N_DBPS = 24; - - switch (DataRate) { - case 60: - N_DBPS = 24; - break; - case 90: - N_DBPS = 36; - break; - case 120: - N_DBPS = 48; - break; - case 180: - N_DBPS = 72; - break; - case 240: - N_DBPS = 96; - break; - case 360: - N_DBPS = 144; - break; - case 480: - N_DBPS = 192; - break; - case 540: - N_DBPS = 216; - break; - default: - break; - } - - return N_DBPS; -} - -/* - * For Netgear case, they want good-looking signal strength. - */ -static long NetgearSignalStrengthTranslate(long LastSS, long CurrSS) -{ - long RetSS; - - /* Step 1. Scale mapping. */ - if (CurrSS >= 71 && CurrSS <= 100) - RetSS = 90 + ((CurrSS - 70) / 3); - else if (CurrSS >= 41 && CurrSS <= 70) - RetSS = 78 + ((CurrSS - 40) / 3); - else if (CurrSS >= 31 && CurrSS <= 40) - RetSS = 66 + (CurrSS - 30); - else if (CurrSS >= 21 && CurrSS <= 30) - RetSS = 54 + (CurrSS - 20); - else if (CurrSS >= 5 && CurrSS <= 20) - RetSS = 42 + (((CurrSS - 5) * 2) / 3); - else if (CurrSS == 4) - RetSS = 36; - else if (CurrSS == 3) - RetSS = 27; - else if (CurrSS == 2) - RetSS = 18; - else if (CurrSS == 1) - RetSS = 9; - else - RetSS = CurrSS; - - /* Step 2. Smoothing. */ - if (LastSS > 0) - RetSS = ((LastSS * 5) + (RetSS) + 5) / 6; - - return RetSS; -} - -/* - * Translate 0-100 signal strength index into dBm. - */ -static long TranslateToDbm8185(u8 SignalStrengthIndex) -{ - long SignalPower; - - /* Translate to dBm (x=0.5y-95). */ - SignalPower = (long)((SignalStrengthIndex + 1) >> 1); - SignalPower -= 95; - - return SignalPower; -} - -/* - * Perform signal smoothing for dynamic mechanism. - * This is different with PerformSignalSmoothing8185 in smoothing formula. - * No dramatic adjustment is applied because dynamic mechanism need some - * degree of correctness. Ported from 8187B. - */ -static void PerformUndecoratedSignalSmoothing8185(struct r8180_priv *priv, - bool bCckRate) -{ - long smoothedSS; - long smoothedRx; - - /* Determine the current packet is CCK rate. */ - priv->bCurCCKPkt = bCckRate; - - smoothedSS = priv->SignalStrength * 10; - - if (priv->UndecoratedSmoothedSS >= 0) - smoothedSS = ((priv->UndecoratedSmoothedSS * 5) + - smoothedSS) / 6; - - priv->UndecoratedSmoothedSS = smoothedSS; - - smoothedRx = ((priv->UndecoratedSmoothedRxPower * 50) + - (priv->RxPower * 11)) / 60; - - priv->UndecoratedSmoothedRxPower = smoothedRx; - - if (bCckRate) - priv->CurCCKRSSI = priv->RSSI; - else - priv->CurCCKRSSI = 0; -} - - -/* - * This is rough RX isr handling routine - */ -static void rtl8180_rx(struct net_device *dev) -{ - struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); - struct sk_buff *tmp_skb; - short first, last; - u32 len; - int lastlen; - unsigned char quality, signal; - u8 rate; - u32 *tmp, *tmp2; - u8 rx_desc_size; - u8 padding; - char rxpower = 0; - u32 RXAGC = 0; - long RxAGC_dBm = 0; - u8 LNA = 0, BB = 0; - u8 LNA_gain[4] = {02, 17, 29, 39}; - u8 Antenna = 0; - struct ieee80211_hdr_4addr *hdr; - u16 fc, type; - u8 bHwError = 0, bCRC = 0, bICV = 0; - bool bCckRate = false; - u8 RSSI = 0; - long SignalStrengthIndex = 0; - struct ieee80211_rx_stats stats = { - .signal = 0, - .noise = -98, - .rate = 0, - .freq = IEEE80211_24GHZ_BAND, - }; - - stats.nic_type = NIC_8185B; - rx_desc_size = 8; - - if ((*(priv->rxringtail)) & (1<<31)) { - /* we have got an RX int, but the descriptor. we are pointing - * is empty. - */ - - priv->stats.rxnodata++; - priv->ieee80211->stats.rx_errors++; - - tmp2 = NULL; - tmp = priv->rxringtail; - do { - if (tmp == priv->rxring) - tmp = priv->rxring + (priv->rxringcount - 1) * - rx_desc_size; - else - tmp -= rx_desc_size; - - if (!(*tmp & (1<<31))) - tmp2 = tmp; - } while (tmp != priv->rxring); - - if (tmp2) - priv->rxringtail = tmp2; - } - - /* while there are filled descriptors */ - while (!(*(priv->rxringtail) & (1<<31))) { - if (*(priv->rxringtail) & (1<<26)) - DMESGW("RX buffer overflow"); - if (*(priv->rxringtail) & (1<<12)) - priv->stats.rxicverr++; - - if (*(priv->rxringtail) & (1<<27)) { - priv->stats.rxdmafail++; - goto drop; - } - - pci_dma_sync_single_for_cpu(priv->pdev, - priv->rxbuffer->dma, - priv->rxbuffersize * sizeof(u8), - PCI_DMA_FROMDEVICE); - - first = *(priv->rxringtail) & (1<<29) ? 1 : 0; - if (first) - priv->rx_prevlen = 0; - - last = *(priv->rxringtail) & (1<<28) ? 1 : 0; - if (last) { - lastlen = ((*priv->rxringtail) & 0xfff); - - /* if the last descriptor (that should tell us the total - * packet len) tell us something less than the - * descriptors len we had until now, then there is some - * problem.. - * workaround to prevent kernel panic - */ - if (lastlen < priv->rx_prevlen) - len = 0; - else - len = lastlen-priv->rx_prevlen; - - if (*(priv->rxringtail) & (1<<13)) { - if ((*(priv->rxringtail) & 0xfff) < 500) - priv->stats.rxcrcerrmin++; - else if ((*(priv->rxringtail) & 0x0fff) > 1000) - priv->stats.rxcrcerrmax++; - else - priv->stats.rxcrcerrmid++; - - } - - } else { - len = priv->rxbuffersize; - } - - if (first && last) { - padding = ((*(priv->rxringtail+3))&(0x04000000))>>26; - } else if (first) { - padding = ((*(priv->rxringtail+3))&(0x04000000))>>26; - if (padding) - len -= 2; - } else { - padding = 0; - } - padding = 0; - priv->rx_prevlen += len; - - if (priv->rx_prevlen > MAX_FRAG_THRESHOLD + 100) { - /* HW is probably passing several buggy frames without - * FD or LD flag set. - * Throw this garbage away to prevent skb memory - * exhausting - */ - if (!priv->rx_skb_complete) - dev_kfree_skb_any(priv->rx_skb); - priv->rx_skb_complete = 1; - } - - signal = (unsigned char)((*(priv->rxringtail + 3) & - 0x00ff0000) >> 16); - signal = (signal & 0xfe) >> 1; - - quality = (unsigned char)((*(priv->rxringtail+3)) & (0xff)); - - stats.mac_time[0] = *(priv->rxringtail+1); - stats.mac_time[1] = *(priv->rxringtail+2); - - rxpower = ((char)((*(priv->rxringtail + 4) & - 0x00ff0000) >> 16)) / 2 - 42; - - RSSI = ((u8)((*(priv->rxringtail + 3) & - 0x0000ff00) >> 8)) & 0x7f; - - rate = ((*(priv->rxringtail)) & - ((1<<23)|(1<<22)|(1<<21)|(1<<20)))>>20; - - stats.rate = rtl8180_rate2rate(rate); - Antenna = (*(priv->rxringtail + 3) & 0x00008000) == 0 ? 0 : 1; - if (!rtl8180_IsWirelessBMode(stats.rate)) { /* OFDM rate. */ - RxAGC_dBm = rxpower+1; /* bias */ - } else { /* CCK rate. */ - RxAGC_dBm = signal; /* bit 0 discard */ - - LNA = (u8) (RxAGC_dBm & 0x60) >> 5; /* bit 6~ bit 5 */ - BB = (u8) (RxAGC_dBm & 0x1F); /* bit 4 ~ bit 0 */ - - /* Pin_11b=-(LNA_gain+BB_gain) (dBm) */ - RxAGC_dBm = -(LNA_gain[LNA] + (BB * 2)); - - RxAGC_dBm += 4; /* bias */ - } - - if (RxAGC_dBm & 0x80) /* absolute value */ - RXAGC = ~(RxAGC_dBm)+1; - bCckRate = rtl8180_IsWirelessBMode(stats.rate); - /* Translate RXAGC into 1-100. */ - if (!rtl8180_IsWirelessBMode(stats.rate)) { /* OFDM rate. */ - if (RXAGC > 90) - RXAGC = 90; - else if (RXAGC < 25) - RXAGC = 25; - RXAGC = (90-RXAGC)*100/65; - } else { /* CCK rate. */ - if (RXAGC > 95) - RXAGC = 95; - else if (RXAGC < 30) - RXAGC = 30; - RXAGC = (95-RXAGC)*100/65; - } - priv->SignalStrength = (u8)RXAGC; - priv->RecvSignalPower = RxAGC_dBm; - priv->RxPower = rxpower; - priv->RSSI = RSSI; - /* SQ translation formula is provided by SD3 DZ. 2006.06.27 */ - if (quality >= 127) - /* 0 causes epc to show signal zero, walk around now */ - quality = 1; - else if (quality < 27) - quality = 100; - else - quality = 127 - quality; - priv->SignalQuality = quality; - - stats.signal = (u8) quality; - - stats.signalstrength = RXAGC; - if (stats.signalstrength > 100) - stats.signalstrength = 100; - stats.signalstrength = (stats.signalstrength * 70) / 100 + 30; - stats.rssi = priv->wstats.qual.qual = priv->SignalQuality; - stats.noise = priv->wstats.qual.noise = - 100 - priv->wstats.qual.qual; - bHwError = (((*(priv->rxringtail)) & (0x00000fff)) == 4080) | - (((*(priv->rxringtail)) & (0x04000000)) != 0) | - (((*(priv->rxringtail)) & (0x08000000)) != 0) | - (((~(*(priv->rxringtail))) & (0x10000000)) != 0) | - (((~(*(priv->rxringtail))) & (0x20000000)) != 0); - bCRC = ((*(priv->rxringtail)) & (0x00002000)) >> 13; - bICV = ((*(priv->rxringtail)) & (0x00001000)) >> 12; - hdr = (struct ieee80211_hdr_4addr *)priv->rxbuffer->buf; - fc = le16_to_cpu(hdr->frame_ctl); - type = WLAN_FC_GET_TYPE(fc); - - if (IEEE80211_FTYPE_CTL != type && - !bHwError && !bCRC && !bICV && - eqMacAddr(priv->ieee80211->current_network.bssid, - fc & IEEE80211_FCTL_TODS ? hdr->addr1 : - fc & IEEE80211_FCTL_FROMDS ? hdr->addr2 : - hdr->addr3)) { - - /* Perform signal smoothing for dynamic - * mechanism on demand. This is different - * with PerformSignalSmoothing8185 in smoothing - * fomula. No dramatic adjustion is apply - * because dynamic mechanism need some degree - * of correctness. */ - PerformUndecoratedSignalSmoothing8185(priv, bCckRate); - - /* For good-looking singal strength. */ - SignalStrengthIndex = NetgearSignalStrengthTranslate( - priv->LastSignalStrengthInPercent, - priv->SignalStrength); - - priv->LastSignalStrengthInPercent = SignalStrengthIndex; - priv->Stats_SignalStrength = - TranslateToDbm8185((u8)SignalStrengthIndex); - - /* - * We need more correct power of received packets and - * the "SignalStrength" of RxStats is beautified, so we - * record the correct power here. - */ - - priv->Stats_SignalQuality = (long)( - priv->Stats_SignalQuality * 5 + - (long)priv->SignalQuality + 5) / 6; - - priv->Stats_RecvSignalPower = (long)( - priv->Stats_RecvSignalPower * 5 + - priv->RecvSignalPower - 1) / 6; - - /* - * Figure out which antenna received the last packet. - * 0: aux, 1: main - */ - priv->LastRxPktAntenna = Antenna ? 1 : 0; - SwAntennaDiversityRxOk8185(dev, priv->SignalStrength); - } - - if (first) { - if (!priv->rx_skb_complete) { - /* seems that HW sometimes fails to receive and - * doesn't provide the last descriptor. - */ - dev_kfree_skb_any(priv->rx_skb); - priv->stats.rxnolast++; - } - priv->rx_skb = dev_alloc_skb(len+2); - if (!priv->rx_skb) - goto drop; - - priv->rx_skb_complete = 0; - priv->rx_skb->dev = dev; - } else { - /* if we are here we should have already RXed the first - * frame. - * If we get here and the skb is not allocated then - * we have just throw out garbage (skb not allocated) - * and we are still rxing garbage.... - */ - if (!priv->rx_skb_complete) { - - tmp_skb = dev_alloc_skb( - priv->rx_skb->len + len + 2); - - if (!tmp_skb) - goto drop; - - tmp_skb->dev = dev; - - memcpy(skb_put(tmp_skb, priv->rx_skb->len), - priv->rx_skb->data, - priv->rx_skb->len); - - dev_kfree_skb_any(priv->rx_skb); - - priv->rx_skb = tmp_skb; - } - } - - if (!priv->rx_skb_complete) { - memcpy(skb_put(priv->rx_skb, len), ((unsigned char *) - priv->rxbuffer->buf) + (padding ? 2 : 0), len); - } - - if (last && !priv->rx_skb_complete) { - if (priv->rx_skb->len > 4) - skb_trim(priv->rx_skb, priv->rx_skb->len-4); - if (!ieee80211_rtl_rx(priv->ieee80211, - priv->rx_skb, &stats)) - dev_kfree_skb_any(priv->rx_skb); - priv->rx_skb_complete = 1; - } - - pci_dma_sync_single_for_device(priv->pdev, - priv->rxbuffer->dma, - priv->rxbuffersize * sizeof(u8), - PCI_DMA_FROMDEVICE); - -drop: /* this is used when we have not enough mem */ - /* restore the descriptor */ - *(priv->rxringtail+2) = priv->rxbuffer->dma; - *(priv->rxringtail) = *(priv->rxringtail) & ~0xfff; - *(priv->rxringtail) = - *(priv->rxringtail) | priv->rxbuffersize; - - *(priv->rxringtail) = - *(priv->rxringtail) | (1<<31); - - priv->rxringtail += rx_desc_size; - if (priv->rxringtail >= - (priv->rxring)+(priv->rxringcount)*rx_desc_size) - priv->rxringtail = priv->rxring; - - priv->rxbuffer = (priv->rxbuffer->next); - } -} - - -static void rtl8180_dma_kick(struct net_device *dev, int priority) -{ - struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); - - rtl8180_set_mode(dev, EPROM_CMD_CONFIG); - write_nic_byte(dev, TX_DMA_POLLING, - (1 << (priority + 1)) | priv->dma_poll_mask); - rtl8180_set_mode(dev, EPROM_CMD_NORMAL); - - force_pci_posting(dev); -} - -static void rtl8180_data_hard_stop(struct net_device *dev) -{ - struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); - - rtl8180_set_mode(dev, EPROM_CMD_CONFIG); - priv->dma_poll_stop_mask |= TPPOLLSTOP_AC_VIQ; - write_nic_byte(dev, TPPollStop, priv->dma_poll_stop_mask); - rtl8180_set_mode(dev, EPROM_CMD_NORMAL); -} - -static void rtl8180_data_hard_resume(struct net_device *dev) -{ - struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); - - rtl8180_set_mode(dev, EPROM_CMD_CONFIG); - priv->dma_poll_stop_mask &= ~(TPPOLLSTOP_AC_VIQ); - write_nic_byte(dev, TPPollStop, priv->dma_poll_stop_mask); - rtl8180_set_mode(dev, EPROM_CMD_NORMAL); -} - -/* - * This function TX data frames when the ieee80211 stack requires this. - * It checks also if we need to stop the ieee tx queue, eventually do it - */ -static void rtl8180_hard_data_xmit(struct sk_buff *skb, struct net_device *dev, - int rate) -{ - struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); - int mode; - struct ieee80211_hdr_3addr *h = (struct ieee80211_hdr_3addr *)skb->data; - bool morefrag = le16_to_cpu(h->frame_control) & IEEE80211_FCTL_MOREFRAGS; - unsigned long flags; - int priority; - - mode = priv->ieee80211->iw_mode; - - rate = ieeerate2rtlrate(rate); - /* - * This function doesn't require lock because we make sure it's called - * with the tx_lock already acquired. - * This come from the kernel's hard_xmit callback (through the ieee - * stack, or from the try_wake_queue (again through the ieee stack. - */ - priority = AC2Q(skb->priority); - spin_lock_irqsave(&priv->tx_lock, flags); - - if (priv->ieee80211->bHwRadioOff) { - spin_unlock_irqrestore(&priv->tx_lock, flags); - - return; - } - - if (!check_nic_enought_desc(dev, priority)) { - DMESGW("Error: no descriptor left by previous TX (avail %d) ", - get_curr_tx_free_desc(dev, priority)); - ieee80211_rtl_stop_queue(priv->ieee80211); - } - rtl8180_tx(dev, skb->data, skb->len, priority, morefrag, 0, rate); - if (!check_nic_enought_desc(dev, priority)) - ieee80211_rtl_stop_queue(priv->ieee80211); - - spin_unlock_irqrestore(&priv->tx_lock, flags); -} - -/* - * This is a rough attempt to TX a frame - * This is called by the ieee 80211 stack to TX management frames. - * If the ring is full packets are dropped (for data frame the queue - * is stopped before this can happen). For this reason it is better - * if the descriptors are larger than the largest management frame - * we intend to TX: i'm unsure what the HW does if it will not find - * the last fragment of a frame because it has been dropped... - * Since queues for Management and Data frames are different we - * might use a different lock than tx_lock (for example mgmt_tx_lock) - */ -/* these function may loop if invoked with 0 descriptors or 0 len buffer */ -static int rtl8180_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); - unsigned long flags; - int priority; - - priority = MANAGE_PRIORITY; - - spin_lock_irqsave(&priv->tx_lock, flags); - - if (priv->ieee80211->bHwRadioOff) { - spin_unlock_irqrestore(&priv->tx_lock, flags); - dev_kfree_skb_any(skb); - return NETDEV_TX_OK; - } - - rtl8180_tx(dev, skb->data, skb->len, priority, - 0, 0, ieeerate2rtlrate(priv->ieee80211->basic_rate)); - - priv->ieee80211->stats.tx_bytes += skb->len; - priv->ieee80211->stats.tx_packets++; - spin_unlock_irqrestore(&priv->tx_lock, flags); - - dev_kfree_skb_any(skb); - return NETDEV_TX_OK; -} - -static void rtl8180_prepare_beacon(struct net_device *dev) -{ - struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); - struct sk_buff *skb; - - u16 word = read_nic_word(dev, BcnItv); - word &= ~BcnItv_BcnItv; /* clear Bcn_Itv */ - - /* word |= 0x64; */ - word |= cpu_to_le16(priv->ieee80211->current_network.beacon_interval); - - write_nic_word(dev, BcnItv, word); - - skb = ieee80211_get_beacon(priv->ieee80211); - if (skb) { - rtl8180_tx(dev, skb->data, skb->len, BEACON_PRIORITY, - 0, 0, ieeerate2rtlrate(priv->ieee80211->basic_rate)); - dev_kfree_skb_any(skb); - } -} - -/* - * This function do the real dirty work: it enqueues a TX command descriptor in - * the ring buffer, copyes the frame in a TX buffer and kicks the NIC to ensure - * it does the DMA transfer. - */ -short rtl8180_tx(struct net_device *dev, u8 *txbuf, int len, int priority, - bool morefrag, short descfrag, int rate) -{ - struct r8180_priv *priv = ieee80211_priv(dev); - u32 *tail, *temp_tail; - u32 *begin; - u32 *buf; - int i; - int remain; - int buflen; - int count; - struct buffer *buflist; - struct ieee80211_hdr_3addr *frag_hdr = - (struct ieee80211_hdr_3addr *)txbuf; - u8 dest[ETH_ALEN]; - u8 bUseShortPreamble = 0; - u8 bCTSEnable = 0; - u8 bRTSEnable = 0; - u16 Duration = 0; - u16 RtsDur = 0; - u16 ThisFrameTime = 0; - u16 TxDescDuration = 0; - bool ownbit_flag = false; - - switch (priority) { - case MANAGE_PRIORITY: - tail = priv->txmapringtail; - begin = priv->txmapring; - buflist = priv->txmapbufstail; - count = priv->txringcount; - break; - case BK_PRIORITY: - tail = priv->txbkpringtail; - begin = priv->txbkpring; - buflist = priv->txbkpbufstail; - count = priv->txringcount; - break; - case BE_PRIORITY: - tail = priv->txbepringtail; - begin = priv->txbepring; - buflist = priv->txbepbufstail; - count = priv->txringcount; - break; - case VI_PRIORITY: - tail = priv->txvipringtail; - begin = priv->txvipring; - buflist = priv->txvipbufstail; - count = priv->txringcount; - break; - case VO_PRIORITY: - tail = priv->txvopringtail; - begin = priv->txvopring; - buflist = priv->txvopbufstail; - count = priv->txringcount; - break; - case HI_PRIORITY: - tail = priv->txhpringtail; - begin = priv->txhpring; - buflist = priv->txhpbufstail; - count = priv->txringcount; - break; - case BEACON_PRIORITY: - tail = priv->txbeaconringtail; - begin = priv->txbeaconring; - buflist = priv->txbeaconbufstail; - count = priv->txbeaconcount; - break; - default: - return -1; - break; - } - - memcpy(&dest, frag_hdr->addr1, ETH_ALEN); - if (is_multicast_ether_addr(dest)) { - Duration = 0; - RtsDur = 0; - bRTSEnable = 0; - bCTSEnable = 0; - - ThisFrameTime = ComputeTxTime(len + sCrcLng, - rtl8180_rate2rate(rate), 0, bUseShortPreamble); - TxDescDuration = ThisFrameTime; - } else { /* Unicast packet */ - u16 AckTime; - - /* for Keep alive */ - priv->NumTxUnicast++; - - /* Figure out ACK rate according to BSS basic rate - * and Tx rate. - * AckCTSLng = 14 use 1M bps send - */ - AckTime = ComputeTxTime(14, 10, 0, 0); - - if (((len + sCrcLng) > priv->rts) && priv->rts) { /* RTS/CTS. */ - u16 RtsTime, CtsTime; - bRTSEnable = 1; - bCTSEnable = 0; - - /* Rate and time required for RTS. */ - RtsTime = ComputeTxTime(sAckCtsLng / 8, - priv->ieee80211->basic_rate, 0, 0); - - /* Rate and time required for CTS. - * AckCTSLng = 14 use 1M bps send - */ - CtsTime = ComputeTxTime(14, 10, 0, 0); - - /* Figure out time required to transmit this frame. */ - ThisFrameTime = ComputeTxTime(len + sCrcLng, - rtl8180_rate2rate(rate), 0, - bUseShortPreamble); - - /* RTS-CTS-ThisFrame-ACK. */ - RtsDur = CtsTime + ThisFrameTime + - AckTime + 3 * aSifsTime; - - TxDescDuration = RtsTime + RtsDur; - } else { /* Normal case. */ - bCTSEnable = 0; - bRTSEnable = 0; - RtsDur = 0; - - ThisFrameTime = ComputeTxTime(len + sCrcLng, - rtl8180_rate2rate(rate), 0, bUseShortPreamble); - TxDescDuration = ThisFrameTime + aSifsTime + AckTime; - } - - if (!(le16_to_cpu(frag_hdr->frame_control) & IEEE80211_FCTL_MOREFRAGS)) { - /* ThisFrame-ACK. */ - Duration = aSifsTime + AckTime; - } else { /* One or more fragments remained. */ - u16 NextFragTime; - - /* pretend following packet length = current packet */ - NextFragTime = ComputeTxTime(len + sCrcLng, - rtl8180_rate2rate(rate), 0, bUseShortPreamble); - - /* ThisFrag-ACk-NextFrag-ACK. */ - Duration = NextFragTime + 3 * aSifsTime + 2 * AckTime; - } - - } /* End of Unicast packet */ - - frag_hdr->duration_id = Duration; - - buflen = priv->txbuffsize; - remain = len; - temp_tail = tail; - - while (remain != 0) { - mb(); - if (!buflist) { - DMESGE("TX buffer error, cannot TX frames. pri %d.", - priority); - return -1; - } - buf = buflist->buf; - - if ((*tail & (1 << 31)) && (priority != BEACON_PRIORITY)) { - DMESGW("No more TX desc, returning %x of %x", - remain, len); - priv->stats.txrdu++; - return remain; - } - - *tail = 0; /* zeroes header */ - *(tail+1) = 0; - *(tail+3) = 0; - *(tail+5) = 0; - *(tail+6) = 0; - *(tail+7) = 0; - - /* FIXME: should be triggered by HW encryption parameters.*/ - *tail |= (1<<15); /* no encrypt */ - - if (remain == len && !descfrag) { - ownbit_flag = false; - *tail = *tail | (1 << 29); /* first segment of packet */ - *tail = *tail | (len); - } else { - ownbit_flag = true; - } - - for (i = 0; i < buflen && remain > 0; i++, remain--) { - /* copy data into descriptor pointed DMAble buffer */ - ((u8 *)buf)[i] = txbuf[i]; - - if (remain == 4 && i+4 >= buflen) - break; - /* ensure the last desc has at least 4 bytes payload */ - } - txbuf = txbuf + i; - *(tail+3) = *(tail+3) & ~0xfff; - *(tail+3) = *(tail+3) | i; /* buffer length */ - - if (bCTSEnable) - *tail |= (1<<18); - - if (bRTSEnable) { /* rts enable */ - /* RTS RATE */ - *tail |= (ieeerate2rtlrate( - priv->ieee80211->basic_rate) << 19); - - *tail |= (1<<23); /* rts enable */ - *(tail+1) |= (RtsDur&0xffff); /* RTS Duration */ - } - *(tail+3) |= ((TxDescDuration&0xffff)<<16); /* DURATION */ - - *(tail + 5) |= (11 << 8); /* retry lim; */ - - *tail = *tail | ((rate&0xf) << 24); - - if (morefrag) - *tail = (*tail) | (1<<17); /* more fragment */ - if (!remain) - *tail = (*tail) | (1<<28); /* last segment of frame */ - - *(tail+5) = *(tail+5)|(2<<27); - *(tail+7) = *(tail+7)|(1<<4); - - wmb(); - if (ownbit_flag) - /* descriptor ready to be txed */ - *tail |= (1 << 31); - - if ((tail - begin)/8 == count-1) - tail = begin; - else - tail = tail+8; - - buflist = buflist->next; - - mb(); - - switch (priority) { - case MANAGE_PRIORITY: - priv->txmapringtail = tail; - priv->txmapbufstail = buflist; - break; - case BK_PRIORITY: - priv->txbkpringtail = tail; - priv->txbkpbufstail = buflist; - break; - case BE_PRIORITY: - priv->txbepringtail = tail; - priv->txbepbufstail = buflist; - break; - case VI_PRIORITY: - priv->txvipringtail = tail; - priv->txvipbufstail = buflist; - break; - case VO_PRIORITY: - priv->txvopringtail = tail; - priv->txvopbufstail = buflist; - break; - case HI_PRIORITY: - priv->txhpringtail = tail; - priv->txhpbufstail = buflist; - break; - case BEACON_PRIORITY: - /* - * The HW seems to be happy with the 1st - * descriptor filled and the 2nd empty... - * So always update descriptor 1 and never - * touch 2nd - */ - break; - } - } - *temp_tail = *temp_tail | (1<<31); /* descriptor ready to be txed */ - rtl8180_dma_kick(dev, priority); - - return 0; -} - -void rtl8180_irq_rx_tasklet(struct r8180_priv *priv); - -static void rtl8180_link_change(struct net_device *dev) -{ - struct r8180_priv *priv = ieee80211_priv(dev); - u16 beacon_interval; - struct ieee80211_network *net = &priv->ieee80211->current_network; - - rtl8180_update_msr(dev); - - rtl8180_set_mode(dev, EPROM_CMD_CONFIG); - - write_nic_dword(dev, BSSID, ((u32 *)net->bssid)[0]); - write_nic_word(dev, BSSID+4, ((u16 *)net->bssid)[2]); - - beacon_interval = read_nic_word(dev, BEACON_INTERVAL); - beacon_interval &= ~BEACON_INTERVAL_MASK; - beacon_interval |= net->beacon_interval; - write_nic_word(dev, BEACON_INTERVAL, beacon_interval); - - rtl8180_set_mode(dev, EPROM_CMD_NORMAL); - - rtl8180_set_chan(dev, priv->chan); -} - -static void rtl8180_rq_tx_ack(struct net_device *dev) -{ - - struct r8180_priv *priv = ieee80211_priv(dev); - - write_nic_byte(dev, CONFIG4, - read_nic_byte(dev, CONFIG4) | CONFIG4_PWRMGT); - priv->ack_tx_to_ieee = 1; -} - -static short rtl8180_is_tx_queue_empty(struct net_device *dev) -{ - - struct r8180_priv *priv = ieee80211_priv(dev); - u32 *d; - - for (d = priv->txmapring; - d < priv->txmapring + priv->txringcount; d += 8) - if (*d & (1<<31)) - return 0; - - for (d = priv->txbkpring; - d < priv->txbkpring + priv->txringcount; d += 8) - if (*d & (1<<31)) - return 0; - - for (d = priv->txbepring; - d < priv->txbepring + priv->txringcount; d += 8) - if (*d & (1<<31)) - return 0; - - for (d = priv->txvipring; - d < priv->txvipring + priv->txringcount; d += 8) - if (*d & (1<<31)) - return 0; - - for (d = priv->txvopring; - d < priv->txvopring + priv->txringcount; d += 8) - if (*d & (1<<31)) - return 0; - - for (d = priv->txhpring; - d < priv->txhpring + priv->txringcount; d += 8) - if (*d & (1<<31)) - return 0; - return 1; -} - -static void rtl8180_hw_wakeup(struct net_device *dev) -{ - unsigned long flags; - struct r8180_priv *priv = ieee80211_priv(dev); - - spin_lock_irqsave(&priv->ps_lock, flags); - write_nic_byte(dev, CONFIG4, - read_nic_byte(dev, CONFIG4) & ~CONFIG4_PWRMGT); - if (priv->rf_wakeup) - priv->rf_wakeup(dev); - spin_unlock_irqrestore(&priv->ps_lock, flags); -} - -static void rtl8180_hw_sleep_down(struct net_device *dev) -{ - unsigned long flags; - struct r8180_priv *priv = ieee80211_priv(dev); - - spin_lock_irqsave(&priv->ps_lock, flags); - if (priv->rf_sleep) - priv->rf_sleep(dev); - spin_unlock_irqrestore(&priv->ps_lock, flags); -} - -static void rtl8180_hw_sleep(struct net_device *dev, u32 th, u32 tl) -{ - struct r8180_priv *priv = ieee80211_priv(dev); - u32 rb = jiffies; - unsigned long flags; - - spin_lock_irqsave(&priv->ps_lock, flags); - - /* - * Writing HW register with 0 equals to disable - * the timer, that is not really what we want - */ - tl -= MSECS(4+16+7); - - /* - * If the interval in which we are requested to sleep is too - * short then give up and remain awake - */ - if (((tl >= rb) && (tl-rb) <= MSECS(MIN_SLEEP_TIME)) - || ((rb > tl) && (rb-tl) < MSECS(MIN_SLEEP_TIME))) { - spin_unlock_irqrestore(&priv->ps_lock, flags); - netdev_warn(dev, "too short to sleep\n"); - return; - } - - { - u32 tmp = (tl > rb) ? (tl-rb) : (rb-tl); - - priv->DozePeriodInPast2Sec += jiffies_to_msecs(tmp); - /* as tl may be less than rb */ - queue_delayed_work(priv->ieee80211->wq, - &priv->ieee80211->hw_wakeup_wq, tmp); - } - /* - * If we suspect the TimerInt is gone beyond tl - * while setting it, then give up - */ - - if (((tl > rb) && ((tl-rb) > MSECS(MAX_SLEEP_TIME))) || - ((tl < rb) && ((rb-tl) > MSECS(MAX_SLEEP_TIME)))) { - spin_unlock_irqrestore(&priv->ps_lock, flags); - return; - } - - queue_work(priv->ieee80211->wq, (void *)&priv->ieee80211->hw_sleep_wq); - spin_unlock_irqrestore(&priv->ps_lock, flags); -} - -static void rtl8180_wmm_single_param_update(struct net_device *dev, - u8 mode, AC_CODING eACI, PAC_PARAM param) -{ - u8 u1bAIFS; - u32 u4bAcParam; - - /* Retrieve parameters to update. */ - /* Mode G/A: slotTimeTimer = 9; Mode B: 20 */ - u1bAIFS = param->f.AciAifsn.f.AIFSN * ((mode & IEEE_G) == IEEE_G ? - 9 : 20) + aSifsTime; - u4bAcParam = (((u32)param->f.TXOPLimit << AC_PARAM_TXOP_LIMIT_OFFSET) | - ((u32)param->f.Ecw.f.ECWmax << AC_PARAM_ECW_MAX_OFFSET) | - ((u32)param->f.Ecw.f.ECWmin << AC_PARAM_ECW_MIN_OFFSET) | - ((u32)u1bAIFS << AC_PARAM_AIFS_OFFSET)); - - switch (eACI) { - case AC1_BK: - write_nic_dword(dev, AC_BK_PARAM, u4bAcParam); - return; - case AC0_BE: - write_nic_dword(dev, AC_BE_PARAM, u4bAcParam); - return; - case AC2_VI: - write_nic_dword(dev, AC_VI_PARAM, u4bAcParam); - return; - case AC3_VO: - write_nic_dword(dev, AC_VO_PARAM, u4bAcParam); - return; - default: - pr_warn("SetHwReg8185(): invalid ACI: %d!\n", eACI); - return; - } -} - -static void rtl8180_wmm_param_update(struct work_struct *work) -{ - struct ieee80211_device *ieee = container_of(work, - struct ieee80211_device, wmm_param_update_wq); - struct net_device *dev = ieee->dev; - u8 *ac_param = (u8 *)(ieee->current_network.wmm_param); - u8 mode = ieee->current_network.mode; - AC_CODING eACI; - AC_PARAM AcParam; - - if (!ieee->current_network.QoS_Enable) { - /* legacy ac_xx_param update */ - AcParam.longData = 0; - AcParam.f.AciAifsn.f.AIFSN = 2; /* Follow 802.11 DIFS. */ - AcParam.f.AciAifsn.f.ACM = 0; - AcParam.f.Ecw.f.ECWmin = 3; /* Follow 802.11 CWmin. */ - AcParam.f.Ecw.f.ECWmax = 7; /* Follow 802.11 CWmax. */ - AcParam.f.TXOPLimit = 0; - - for (eACI = 0; eACI < AC_MAX; eACI++) { - AcParam.f.AciAifsn.f.ACI = (u8)eACI; - - rtl8180_wmm_single_param_update(dev, mode, eACI, - (PAC_PARAM)&AcParam); - } - return; - } - - for (eACI = 0; eACI < AC_MAX; eACI++) { - rtl8180_wmm_single_param_update(dev, mode, - ((PAC_PARAM)ac_param)->f.AciAifsn.f.ACI, - (PAC_PARAM)ac_param); - - ac_param += sizeof(AC_PARAM); - } -} - -void rtl8180_restart_wq(struct work_struct *work); -void rtl8180_watch_dog_wq(struct work_struct *work); -void rtl8180_hw_wakeup_wq(struct work_struct *work); -void rtl8180_hw_sleep_wq(struct work_struct *work); -void rtl8180_sw_antenna_wq(struct work_struct *work); -void rtl8180_watch_dog(struct net_device *dev); - -static void watch_dog_adaptive(unsigned long data) -{ - struct r8180_priv *priv = ieee80211_priv((struct net_device *)data); - - if (!priv->up) { - DMESG("<----watch_dog_adaptive():driver is not up!\n"); - return; - } - - /* Tx High Power Mechanism. */ - if (CheckHighPower((struct net_device *)data)) - queue_work(priv->ieee80211->wq, - (void *)&priv->ieee80211->tx_pw_wq); - - /* Tx Power Tracking on 87SE. */ - if (CheckTxPwrTracking((struct net_device *)data)) - TxPwrTracking87SE((struct net_device *)data); - - /* Perform DIG immediately. */ - if (CheckDig((struct net_device *)data)) - queue_work(priv->ieee80211->wq, - (void *)&priv->ieee80211->hw_dig_wq); - - rtl8180_watch_dog((struct net_device *)data); - - queue_work(priv->ieee80211->wq, - (void *)&priv->ieee80211->GPIOChangeRFWorkItem); - - priv->watch_dog_timer.expires = jiffies + - MSECS(IEEE80211_WATCH_DOG_TIME); - - add_timer(&priv->watch_dog_timer); -} - -static struct rtl8187se_channel_list channel_plan_list[] = { - /* FCC */ - {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 36, 40, - 44, 48, 52, 56, 60, 64}, 19}, - - /* IC */ - {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 11}, - - /* ETSI */ - {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 36, 40, - 44, 48, 52, 56, 60, 64}, 21}, - - /* Spain. Change to ETSI. */ - {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 36, 40, - 44, 48, 52, 56, 60, 64}, 21}, - - /* France. Change to ETSI. */ - {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 36, 40, - 44, 48, 52, 56, 60, 64}, 21}, - - /* MKK */ - {{14, 36, 40, 44, 48, 52, 56, 60, 64}, 9}, - - /* MKK1 */ - {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 36, - 40, 44, 48, 52, 56, 60, 64}, 22}, - - /* Israel. */ - {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 36, 40, - 44, 48, 52, 56, 60, 64}, 21}, - - /* For 11a , TELEC */ - {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 34, 38, 42, 46}, 17}, - - /* For Global Domain. 1-11 active, 12-14 passive. */ - {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}, 14}, - - /* world wide 13: ch1~ch11 active, ch12~13 passive */ - {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, 13} -}; - -static void rtl8180_set_channel_map(u8 channel_plan, - struct ieee80211_device *ieee) -{ - int i; - - ieee->MinPassiveChnlNum = MAX_CHANNEL_NUMBER+1; - ieee->IbssStartChnl = 0; - - switch (channel_plan) { - case COUNTRY_CODE_FCC: - case COUNTRY_CODE_IC: - case COUNTRY_CODE_ETSI: - case COUNTRY_CODE_SPAIN: - case COUNTRY_CODE_FRANCE: - case COUNTRY_CODE_MKK: - case COUNTRY_CODE_MKK1: - case COUNTRY_CODE_ISRAEL: - case COUNTRY_CODE_TELEC: - { - Dot11d_Init(ieee); - ieee->bGlobalDomain = false; - if (channel_plan_list[channel_plan].len != 0) { - /* Clear old channel map */ - memset(GET_DOT11D_INFO(ieee)->channel_map, 0, sizeof(GET_DOT11D_INFO(ieee)->channel_map)); - /* Set new channel map */ - for (i = 0; i < channel_plan_list[channel_plan].len; i++) { - if (channel_plan_list[channel_plan].channel[i] <= 14) - GET_DOT11D_INFO(ieee)->channel_map[channel_plan_list[channel_plan].channel[i]] = 1; - } - } - break; - } - case COUNTRY_CODE_GLOBAL_DOMAIN: - { - GET_DOT11D_INFO(ieee)->bEnabled = false; - Dot11d_Reset(ieee); - ieee->bGlobalDomain = true; - break; - } - case COUNTRY_CODE_WORLD_WIDE_13_INDEX: - { - ieee->MinPassiveChnlNum = 12; - ieee->IbssStartChnl = 10; - break; - } - default: - { - Dot11d_Init(ieee); - ieee->bGlobalDomain = false; - memset(GET_DOT11D_INFO(ieee)->channel_map, 0, sizeof(GET_DOT11D_INFO(ieee)->channel_map)); - for (i = 1; i <= 14; i++) - GET_DOT11D_INFO(ieee)->channel_map[i] = 1; - break; - } - } -} - -void GPIOChangeRFWorkItemCallBack(struct work_struct *work); - -static void rtl8180_statistics_init(struct stats *pstats) -{ - memset(pstats, 0, sizeof(struct stats)); -} - -static void rtl8180_link_detect_init(struct link_detect_t *plink_detect) -{ - memset(plink_detect, 0, sizeof(struct link_detect_t)); - plink_detect->slot_num = DEFAULT_SLOT_NUM; -} - -static void rtl8187se_eeprom_register_read(struct eeprom_93cx6 *eeprom) -{ - struct net_device *dev = eeprom->data; - u8 reg = read_nic_byte(dev, EPROM_CMD); - - eeprom->reg_data_in = reg & RTL818X_EEPROM_CMD_WRITE; - eeprom->reg_data_out = reg & RTL818X_EEPROM_CMD_READ; - eeprom->reg_data_clock = reg & RTL818X_EEPROM_CMD_CK; - eeprom->reg_chip_select = reg & RTL818X_EEPROM_CMD_CS; -} - -static void rtl8187se_eeprom_register_write(struct eeprom_93cx6 *eeprom) -{ - struct net_device *dev = eeprom->data; - u8 reg = 2 << 6; - - if (eeprom->reg_data_in) - reg |= RTL818X_EEPROM_CMD_WRITE; - if (eeprom->reg_data_out) - reg |= RTL818X_EEPROM_CMD_READ; - if (eeprom->reg_data_clock) - reg |= RTL818X_EEPROM_CMD_CK; - if (eeprom->reg_chip_select) - reg |= RTL818X_EEPROM_CMD_CS; - - write_nic_byte(dev, EPROM_CMD, reg); - read_nic_byte(dev, EPROM_CMD); - udelay(10); -} - -static short rtl8180_init(struct net_device *dev) -{ - struct r8180_priv *priv = ieee80211_priv(dev); - u16 word; - u16 usValue; - u16 tmpu16; - int i, j; - struct eeprom_93cx6 eeprom; - u16 eeprom_val; - - eeprom.data = dev; - eeprom.register_read = rtl8187se_eeprom_register_read; - eeprom.register_write = rtl8187se_eeprom_register_write; - eeprom.width = PCI_EEPROM_WIDTH_93C46; - - eeprom_93cx6_read(&eeprom, EEPROM_COUNTRY_CODE>>1, &eeprom_val); - priv->channel_plan = eeprom_val & 0xFF; - if (priv->channel_plan > COUNTRY_CODE_GLOBAL_DOMAIN) { - netdev_err(dev, "rtl8180_init: Invalid channel plan! Set to default.\n"); - priv->channel_plan = 0; - } - - DMESG("Channel plan is %d\n", priv->channel_plan); - rtl8180_set_channel_map(priv->channel_plan, priv->ieee80211); - - /* FIXME: these constants are placed in a bad pleace. */ - priv->txbuffsize = 2048; /* 1024; */ - priv->txringcount = 32; /* 32; */ - priv->rxbuffersize = 2048; /* 1024; */ - priv->rxringcount = 64; /* 32; */ - priv->txbeaconcount = 2; - priv->rx_skb_complete = 1; - - priv->RFChangeInProgress = false; - priv->SetRFPowerStateInProgress = false; - priv->RFProgType = 0; - - priv->irq_enabled = 0; - - rtl8180_statistics_init(&priv->stats); - rtl8180_link_detect_init(&priv->link_detect); - - priv->ack_tx_to_ieee = 0; - priv->ieee80211->current_network.beacon_interval = - DEFAULT_BEACONINTERVAL; - priv->ieee80211->iw_mode = IW_MODE_INFRA; - priv->ieee80211->softmac_features = IEEE_SOFTMAC_SCAN | - IEEE_SOFTMAC_ASSOCIATE | IEEE_SOFTMAC_PROBERQ | - IEEE_SOFTMAC_PROBERS | IEEE_SOFTMAC_TX_QUEUE; - priv->ieee80211->active_scan = 1; - priv->ieee80211->rate = 110; /* 11 mbps */ - priv->ieee80211->modulation = IEEE80211_CCK_MODULATION; - priv->ieee80211->host_encrypt = 1; - priv->ieee80211->host_decrypt = 1; - priv->ieee80211->sta_wake_up = rtl8180_hw_wakeup; - priv->ieee80211->ps_request_tx_ack = rtl8180_rq_tx_ack; - priv->ieee80211->enter_sleep_state = rtl8180_hw_sleep; - priv->ieee80211->ps_is_queue_empty = rtl8180_is_tx_queue_empty; - - priv->hw_wep = hwwep; - priv->dev = dev; - priv->retry_rts = DEFAULT_RETRY_RTS; - priv->retry_data = DEFAULT_RETRY_DATA; - priv->RFChangeInProgress = false; - priv->SetRFPowerStateInProgress = false; - priv->RFProgType = 0; - priv->bInactivePs = true; /* false; */ - priv->ieee80211->bInactivePs = priv->bInactivePs; - priv->bSwRfProcessing = false; - priv->eRFPowerState = RF_OFF; - priv->RfOffReason = 0; - priv->led_strategy = SW_LED_MODE0; - priv->TxPollingTimes = 0; - priv->bLeisurePs = true; - priv->dot11PowerSaveMode = ACTIVE; - priv->AdMinCheckPeriod = 5; - priv->AdMaxCheckPeriod = 10; - priv->AdMaxRxSsThreshold = 30; /* 60->30 */ - priv->AdRxSsThreshold = 20; /* 50->20 */ - priv->AdCheckPeriod = priv->AdMinCheckPeriod; - priv->AdTickCount = 0; - priv->AdRxSignalStrength = -1; - priv->RegSwAntennaDiversityMechanism = 0; - priv->RegDefaultAntenna = 0; - priv->SignalStrength = 0; - priv->AdRxOkCnt = 0; - priv->CurrAntennaIndex = 0; - priv->AdRxSsBeforeSwitched = 0; - init_timer(&priv->SwAntennaDiversityTimer); - priv->SwAntennaDiversityTimer.data = (unsigned long)dev; - priv->SwAntennaDiversityTimer.function = - (void *)SwAntennaDiversityTimerCallback; - priv->bDigMechanism = true; - priv->InitialGain = 6; - priv->bXtalCalibration = false; - priv->XtalCal_Xin = 0; - priv->XtalCal_Xout = 0; - priv->bTxPowerTrack = false; - priv->ThermalMeter = 0; - priv->FalseAlarmRegValue = 0; - priv->RegDigOfdmFaUpTh = 0xc; /* Upper threshold of OFDM false alarm, - which is used in DIG. */ - priv->DIG_NumberFallbackVote = 0; - priv->DIG_NumberUpgradeVote = 0; - priv->LastSignalStrengthInPercent = 0; - priv->Stats_SignalStrength = 0; - priv->LastRxPktAntenna = 0; - priv->SignalQuality = 0; /* in 0-100 index. */ - priv->Stats_SignalQuality = 0; - priv->RecvSignalPower = 0; /* in dBm. */ - priv->Stats_RecvSignalPower = 0; - priv->AdMainAntennaRxOkCnt = 0; - priv->AdAuxAntennaRxOkCnt = 0; - priv->bHWAdSwitched = false; - priv->bRegHighPowerMechanism = true; - priv->RegHiPwrUpperTh = 77; - priv->RegHiPwrLowerTh = 75; - priv->RegRSSIHiPwrUpperTh = 70; - priv->RegRSSIHiPwrLowerTh = 20; - priv->bCurCCKPkt = false; - priv->UndecoratedSmoothedSS = -1; - priv->bToUpdateTxPwr = false; - priv->CurCCKRSSI = 0; - priv->RxPower = 0; - priv->RSSI = 0; - priv->NumTxOkTotal = 0; - priv->NumTxUnicast = 0; - priv->keepAliveLevel = DEFAULT_KEEP_ALIVE_LEVEL; - priv->CurrRetryCnt = 0; - priv->LastRetryCnt = 0; - priv->LastTxokCnt = 0; - priv->LastRxokCnt = 0; - priv->LastRetryRate = 0; - priv->bTryuping = 0; - priv->CurrTxRate = 0; - priv->CurrRetryRate = 0; - priv->TryupingCount = 0; - priv->TryupingCountNoData = 0; - priv->TryDownCountLowData = 0; - priv->LastTxOKBytes = 0; - priv->LastFailTxRate = 0; - priv->LastFailTxRateSS = 0; - priv->FailTxRateCount = 0; - priv->LastTxThroughput = 0; - priv->NumTxOkBytesTotal = 0; - priv->ForcedDataRate = 0; - priv->RegBModeGainStage = 1; - - priv->promisc = (dev->flags & IFF_PROMISC) ? 1 : 0; - spin_lock_init(&priv->irq_th_lock); - spin_lock_init(&priv->tx_lock); - spin_lock_init(&priv->ps_lock); - spin_lock_init(&priv->rf_ps_lock); - sema_init(&priv->wx_sem, 1); - INIT_WORK(&priv->reset_wq, (void *)rtl8180_restart_wq); - INIT_DELAYED_WORK(&priv->ieee80211->hw_wakeup_wq, - (void *)rtl8180_hw_wakeup_wq); - INIT_DELAYED_WORK(&priv->ieee80211->hw_sleep_wq, - (void *)rtl8180_hw_sleep_wq); - INIT_WORK(&priv->ieee80211->wmm_param_update_wq, - (void *)rtl8180_wmm_param_update); - INIT_DELAYED_WORK(&priv->ieee80211->rate_adapter_wq, - (void *)rtl8180_rate_adapter); - INIT_DELAYED_WORK(&priv->ieee80211->hw_dig_wq, - (void *)rtl8180_hw_dig_wq); - INIT_DELAYED_WORK(&priv->ieee80211->tx_pw_wq, - (void *)rtl8180_tx_pw_wq); - INIT_DELAYED_WORK(&priv->ieee80211->GPIOChangeRFWorkItem, - (void *) GPIOChangeRFWorkItemCallBack); - tasklet_init(&priv->irq_rx_tasklet, - (void(*)(unsigned long)) rtl8180_irq_rx_tasklet, - (unsigned long)priv); - - init_timer(&priv->watch_dog_timer); - priv->watch_dog_timer.data = (unsigned long)dev; - priv->watch_dog_timer.function = watch_dog_adaptive; - - init_timer(&priv->rateadapter_timer); - priv->rateadapter_timer.data = (unsigned long)dev; - priv->rateadapter_timer.function = timer_rate_adaptive; - priv->RateAdaptivePeriod = RATE_ADAPTIVE_TIMER_PERIOD; - priv->bEnhanceTxPwr = false; - - priv->ieee80211->softmac_hard_start_xmit = rtl8180_hard_start_xmit; - priv->ieee80211->set_chan = rtl8180_set_chan; - priv->ieee80211->link_change = rtl8180_link_change; - priv->ieee80211->softmac_data_hard_start_xmit = rtl8180_hard_data_xmit; - priv->ieee80211->data_hard_stop = rtl8180_data_hard_stop; - priv->ieee80211->data_hard_resume = rtl8180_data_hard_resume; - - priv->ieee80211->init_wmmparam_flag = 0; - - priv->ieee80211->start_send_beacons = rtl8180_start_tx_beacon; - priv->ieee80211->stop_send_beacons = rtl8180_beacon_tx_disable; - priv->ieee80211->fts = DEFAULT_FRAG_THRESHOLD; - - priv->ShortRetryLimit = 7; - priv->LongRetryLimit = 7; - priv->EarlyRxThreshold = 7; - - priv->TransmitConfig = (1<ShortRetryLimit<LongRetryLimit<ReceiveConfig = RCR_AMF | RCR_ADF | RCR_ACF | - RCR_AB | RCR_AM | RCR_APM | - (7<EarlyRxThreshold<EarlyRxThreshold == 7 ? - RCR_ONLYERLPKT : 0); - - priv->IntrMask = IMR_TMGDOK | IMR_TBDER | - IMR_THPDER | IMR_THPDOK | - IMR_TVODER | IMR_TVODOK | - IMR_TVIDER | IMR_TVIDOK | - IMR_TBEDER | IMR_TBEDOK | - IMR_TBKDER | IMR_TBKDOK | - IMR_RDU | - IMR_RER | IMR_ROK | - IMR_RQoSOK; - - priv->InitialGain = 6; - - DMESG("MAC controller is a RTL8187SE b/g"); - - priv->ieee80211->modulation |= IEEE80211_OFDM_MODULATION; - priv->ieee80211->short_slot = 1; - - eeprom_93cx6_read(&eeprom, EEPROM_SW_REVD_OFFSET, &usValue); - DMESG("usValue is %#hx\n", usValue); - /* 3Read AntennaDiversity */ - - /* SW Antenna Diversity. */ - priv->EEPROMSwAntennaDiversity = (usValue & EEPROM_SW_AD_MASK) == - EEPROM_SW_AD_ENABLE; - - /* Default Antenna to use. */ - priv->EEPROMDefaultAntenna1 = (usValue & EEPROM_DEF_ANT_MASK) == - EEPROM_DEF_ANT_1; - - if (priv->RegSwAntennaDiversityMechanism == 0) /* Auto */ - /* 0: default from EEPROM. */ - priv->bSwAntennaDiverity = priv->EEPROMSwAntennaDiversity; - else - /* 1:disable antenna diversity, 2: enable antenna diversity. */ - priv->bSwAntennaDiverity = - priv->RegSwAntennaDiversityMechanism == 2; - - if (priv->RegDefaultAntenna == 0) - /* 0: default from EEPROM. */ - priv->bDefaultAntenna1 = priv->EEPROMDefaultAntenna1; - else - /* 1: main, 2: aux. */ - priv->bDefaultAntenna1 = priv->RegDefaultAntenna == 2; - - priv->plcp_preamble_mode = 2; - /* the eeprom type is stored in RCR register bit #6 */ - if (RCR_9356SEL & read_nic_dword(dev, RCR)) - priv->epromtype = EPROM_93c56; - else - priv->epromtype = EPROM_93c46; - - eeprom_93cx6_multiread(&eeprom, 0x7, (__le16 *) - dev->dev_addr, 3); - - for (i = 1, j = 0; i < 14; i += 2, j++) { - eeprom_93cx6_read(&eeprom, EPROM_TXPW_CH1_2 + j, &word); - priv->chtxpwr[i] = word & 0xff; - priv->chtxpwr[i+1] = (word & 0xff00)>>8; - } - for (i = 1, j = 0; i < 14; i += 2, j++) { - eeprom_93cx6_read(&eeprom, EPROM_TXPW_OFDM_CH1_2 + j, &word); - priv->chtxpwr_ofdm[i] = word & 0xff; - priv->chtxpwr_ofdm[i+1] = (word & 0xff00) >> 8; - } - - /* 3Read crystal calibration and thermal meter indication on 87SE. */ - eeprom_93cx6_read(&eeprom, EEPROM_RSV>>1, &tmpu16); - - /* Crystal calibration for Xin and Xout resp. */ - priv->XtalCal_Xout = tmpu16 & EEPROM_XTAL_CAL_XOUT_MASK; - priv->XtalCal_Xin = (tmpu16 & EEPROM_XTAL_CAL_XIN_MASK) >> 4; - if ((tmpu16 & EEPROM_XTAL_CAL_ENABLE) >> 12) - priv->bXtalCalibration = true; - - /* Thermal meter reference indication. */ - priv->ThermalMeter = (u8)((tmpu16 & EEPROM_THERMAL_METER_MASK) >> 8); - if ((tmpu16 & EEPROM_THERMAL_METER_ENABLE) >> 13) - priv->bTxPowerTrack = true; - - priv->rf_sleep = rtl8225z4_rf_sleep; - priv->rf_wakeup = rtl8225z4_rf_wakeup; - DMESGW("**PLEASE** REPORT SUCCESSFUL/UNSUCCESSFUL TO Realtek!"); - - priv->rf_close = rtl8225z2_rf_close; - priv->rf_init = rtl8225z2_rf_init; - priv->rf_set_chan = rtl8225z2_rf_set_chan; - priv->rf_set_sens = NULL; - - if (0 != alloc_rx_desc_ring(dev, priv->rxbuffersize, priv->rxringcount)) - return -ENOMEM; - - if (0 != alloc_tx_desc_ring(dev, priv->txbuffsize, priv->txringcount, - TX_MANAGEPRIORITY_RING_ADDR)) - return -ENOMEM; - - if (0 != alloc_tx_desc_ring(dev, priv->txbuffsize, priv->txringcount, - TX_BKPRIORITY_RING_ADDR)) - return -ENOMEM; - - if (0 != alloc_tx_desc_ring(dev, priv->txbuffsize, priv->txringcount, - TX_BEPRIORITY_RING_ADDR)) - return -ENOMEM; - - if (0 != alloc_tx_desc_ring(dev, priv->txbuffsize, priv->txringcount, - TX_VIPRIORITY_RING_ADDR)) - return -ENOMEM; - - if (0 != alloc_tx_desc_ring(dev, priv->txbuffsize, priv->txringcount, - TX_VOPRIORITY_RING_ADDR)) - return -ENOMEM; - - if (0 != alloc_tx_desc_ring(dev, priv->txbuffsize, priv->txringcount, - TX_HIGHPRIORITY_RING_ADDR)) - return -ENOMEM; - - if (0 != alloc_tx_desc_ring(dev, priv->txbuffsize, priv->txbeaconcount, - TX_BEACON_RING_ADDR)) - return -ENOMEM; - - if (request_irq(dev->irq, rtl8180_interrupt, - IRQF_SHARED, dev->name, dev)) { - DMESGE("Error allocating IRQ %d", dev->irq); - return -1; - } else { - priv->irq = dev->irq; - DMESG("IRQ %d", dev->irq); - } - - return 0; -} - -void rtl8180_no_hw_wep(struct net_device *dev) -{ -} - -void rtl8180_set_hw_wep(struct net_device *dev) -{ - struct r8180_priv *priv = ieee80211_priv(dev); - u8 pgreg; - u8 security; - u32 key0_word4; - - pgreg = read_nic_byte(dev, PGSELECT); - write_nic_byte(dev, PGSELECT, pgreg & ~(1<key0[3] & 0xff; - write_nic_dword(dev, KEY0, (priv->key0[0])); - write_nic_dword(dev, KEY0+4, (priv->key0[1])); - write_nic_dword(dev, KEY0+4+4, (priv->key0[2])); - write_nic_dword(dev, KEY0+4+4+4, (key0_word4)); - - security = read_nic_byte(dev, SECURITY); - security |= (1<> 24)); - write_nic_byte(dev, 0x7e, ((phyw & 0x00ff0000) >> 16)); - write_nic_byte(dev, 0x7d, ((phyw & 0x0000ff00) >> 8)); - write_nic_byte(dev, 0x7c, ((phyw & 0x000000ff))); -} - -inline void write_phy_ofdm(struct net_device *dev, u8 adr, u32 data) -{ - data = data & 0xff; - rtl8185_write_phy(dev, adr, data); -} - -void write_phy_cck(struct net_device *dev, u8 adr, u32 data) -{ - data = data & 0xff; - rtl8185_write_phy(dev, adr, data | 0x10000); -} - -/* - * This configures registers for beacon tx and enables it via - * rtl8180_beacon_tx_enable(). rtl8180_beacon_tx_disable() might - * be used to stop beacon transmission - */ -void rtl8180_start_tx_beacon(struct net_device *dev) -{ - u16 word; - - DMESG("Enabling beacon TX"); - rtl8180_prepare_beacon(dev); - rtl8180_irq_disable(dev); - rtl8180_beacon_tx_enable(dev); - - word = read_nic_word(dev, AtimWnd) & ~AtimWnd_AtimWnd; - write_nic_word(dev, AtimWnd, word); /* word |= */ - - word = read_nic_word(dev, BintrItv); - word &= ~BintrItv_BintrItv; - word |= 1000; /* priv->ieee80211->current_network.beacon_interval * - * ((priv->txbeaconcount > 1)?(priv->txbeaconcount-1):1); - * FIXME: check if correct ^^ worked with 0x3e8; - */ - write_nic_word(dev, BintrItv, word); - - rtl8180_set_mode(dev, EPROM_CMD_NORMAL); - - rtl8185b_irq_enable(dev); -} - -static struct net_device_stats *rtl8180_stats(struct net_device *dev) -{ - struct r8180_priv *priv = ieee80211_priv(dev); - - return &priv->ieee80211->stats; -} - -/* - * Change current and default preamble mode. - */ -static bool MgntActSet_802_11_PowerSaveMode(struct r8180_priv *priv, - enum rt_ps_mode rtPsMode) -{ - /* Currently, we do not change power save mode on IBSS mode. */ - if (priv->ieee80211->iw_mode == IW_MODE_ADHOC) - return false; - - priv->ieee80211->ps = rtPsMode; - - return true; -} - -static void LeisurePSEnter(struct r8180_priv *priv) -{ - if (priv->bLeisurePs) - if (priv->ieee80211->ps == IEEE80211_PS_DISABLED) - /* IEEE80211_PS_ENABLE */ - MgntActSet_802_11_PowerSaveMode(priv, - IEEE80211_PS_MBCAST | IEEE80211_PS_UNICAST); -} - -static void LeisurePSLeave(struct r8180_priv *priv) -{ - if (priv->bLeisurePs) - if (priv->ieee80211->ps != IEEE80211_PS_DISABLED) - MgntActSet_802_11_PowerSaveMode( - priv, IEEE80211_PS_DISABLED); -} - -void rtl8180_hw_wakeup_wq(struct work_struct *work) -{ - struct delayed_work *dwork = to_delayed_work(work); - struct ieee80211_device *ieee = container_of( - dwork, struct ieee80211_device, hw_wakeup_wq); - struct net_device *dev = ieee->dev; - - rtl8180_hw_wakeup(dev); -} - -void rtl8180_hw_sleep_wq(struct work_struct *work) -{ - struct delayed_work *dwork = to_delayed_work(work); - struct ieee80211_device *ieee = container_of( - dwork, struct ieee80211_device, hw_sleep_wq); - struct net_device *dev = ieee->dev; - - rtl8180_hw_sleep_down(dev); -} - -static void MgntLinkKeepAlive(struct r8180_priv *priv) -{ - if (priv->keepAliveLevel == 0) - return; - - if (priv->ieee80211->state == IEEE80211_LINKED) { - /* - * Keep-Alive. - */ - - if ((priv->keepAliveLevel == 2) || - (priv->link_detect.last_num_tx_unicast == - priv->NumTxUnicast && - priv->link_detect.last_num_rx_unicast == - priv->ieee80211->NumRxUnicast) - ) { - priv->link_detect.idle_count++; - - /* - * Send a Keep-Alive packet packet to AP if we had - * been idle for a while. - */ - if (priv->link_detect.idle_count >= - KEEP_ALIVE_INTERVAL / - CHECK_FOR_HANG_PERIOD - 1) { - priv->link_detect.idle_count = 0; - ieee80211_sta_ps_send_null_frame( - priv->ieee80211, false); - } - } else { - priv->link_detect.idle_count = 0; - } - priv->link_detect.last_num_tx_unicast = priv->NumTxUnicast; - priv->link_detect.last_num_rx_unicast = - priv->ieee80211->NumRxUnicast; - } -} - -void rtl8180_watch_dog(struct net_device *dev) -{ - struct r8180_priv *priv = ieee80211_priv(dev); - bool bEnterPS = false; - bool bBusyTraffic = false; - u32 TotalRxNum = 0; - u16 SlotIndex = 0; - u16 i = 0; - if (priv->ieee80211->actscanning == false) { - if ((priv->ieee80211->iw_mode != IW_MODE_ADHOC) && - (priv->ieee80211->state == IEEE80211_NOLINK) && - (priv->ieee80211->beinretry == false) && - (priv->eRFPowerState == RF_ON)) - IPSEnter(dev); - } - if ((priv->ieee80211->state == IEEE80211_LINKED) && - (priv->ieee80211->iw_mode == IW_MODE_INFRA)) { - SlotIndex = (priv->link_detect.slot_index++) % - priv->link_detect.slot_num; - - priv->link_detect.rx_frame_num[SlotIndex] = - priv->ieee80211->NumRxDataInPeriod + - priv->ieee80211->NumRxBcnInPeriod; - - for (i = 0; i < priv->link_detect.slot_num; i++) - TotalRxNum += priv->link_detect.rx_frame_num[i]; - - if (TotalRxNum == 0) { - priv->ieee80211->state = IEEE80211_ASSOCIATING; - queue_work(priv->ieee80211->wq, - &priv->ieee80211->associate_procedure_wq); - } - } - - MgntLinkKeepAlive(priv); - - LeisurePSLeave(priv); - - if (priv->ieee80211->state == IEEE80211_LINKED) { - priv->link_detect.num_rx_ok_in_period = - priv->ieee80211->NumRxDataInPeriod; - if (priv->link_detect.num_rx_ok_in_period > 666 || - priv->link_detect.num_tx_ok_in_period > 666) { - bBusyTraffic = true; - } - if ((priv->link_detect.num_rx_ok_in_period + - priv->link_detect.num_tx_ok_in_period > 8) - || (priv->link_detect.num_rx_ok_in_period > 2)) { - bEnterPS = false; - } else - bEnterPS = true; - - if (bEnterPS) - LeisurePSEnter(priv); - else - LeisurePSLeave(priv); - } else - LeisurePSLeave(priv); - priv->link_detect.b_busy_traffic = bBusyTraffic; - priv->link_detect.num_rx_ok_in_period = 0; - priv->link_detect.num_tx_ok_in_period = 0; - priv->ieee80211->NumRxDataInPeriod = 0; - priv->ieee80211->NumRxBcnInPeriod = 0; -} - -static int _rtl8180_up(struct net_device *dev) -{ - struct r8180_priv *priv = ieee80211_priv(dev); - - priv->up = 1; - - DMESG("Bringing up iface"); - rtl8185b_adapter_start(dev); - rtl8185b_rx_enable(dev); - rtl8185b_tx_enable(dev); - if (priv->bInactivePs) { - if (priv->ieee80211->iw_mode == IW_MODE_ADHOC) - IPSLeave(dev); - } - timer_rate_adaptive((unsigned long)dev); - watch_dog_adaptive((unsigned long)dev); - if (priv->bSwAntennaDiverity) - SwAntennaDiversityTimerCallback(dev); - ieee80211_softmac_start_protocol(priv->ieee80211); - return 0; -} - -static int rtl8180_open(struct net_device *dev) -{ - struct r8180_priv *priv = ieee80211_priv(dev); - int ret; - - down(&priv->wx_sem); - ret = rtl8180_up(dev); - up(&priv->wx_sem); - return ret; -} - -int rtl8180_up(struct net_device *dev) -{ - struct r8180_priv *priv = ieee80211_priv(dev); - - if (priv->up == 1) - return -1; - - return _rtl8180_up(dev); -} - -static int rtl8180_close(struct net_device *dev) -{ - struct r8180_priv *priv = ieee80211_priv(dev); - int ret; - - down(&priv->wx_sem); - ret = rtl8180_down(dev); - up(&priv->wx_sem); - - return ret; -} - -int rtl8180_down(struct net_device *dev) -{ - struct r8180_priv *priv = ieee80211_priv(dev); - - if (priv->up == 0) - return -1; - - priv->up = 0; - - ieee80211_softmac_stop_protocol(priv->ieee80211); - /* FIXME */ - if (!netif_queue_stopped(dev)) - netif_stop_queue(dev); - rtl8180_rtx_disable(dev); - rtl8180_irq_disable(dev); - del_timer_sync(&priv->watch_dog_timer); - del_timer_sync(&priv->rateadapter_timer); - cancel_delayed_work(&priv->ieee80211->rate_adapter_wq); - cancel_delayed_work(&priv->ieee80211->hw_wakeup_wq); - cancel_delayed_work(&priv->ieee80211->hw_sleep_wq); - cancel_delayed_work(&priv->ieee80211->hw_dig_wq); - cancel_delayed_work(&priv->ieee80211->tx_pw_wq); - del_timer_sync(&priv->SwAntennaDiversityTimer); - SetZebraRFPowerState8185(dev, RF_OFF); - memset(&priv->ieee80211->current_network, - 0, sizeof(struct ieee80211_network)); - priv->ieee80211->state = IEEE80211_NOLINK; - return 0; -} - -void rtl8180_restart_wq(struct work_struct *work) -{ - struct r8180_priv *priv = container_of( - work, struct r8180_priv, reset_wq); - struct net_device *dev = priv->dev; - - down(&priv->wx_sem); - - rtl8180_commit(dev); - - up(&priv->wx_sem); -} - -static void rtl8180_restart(struct net_device *dev) -{ - struct r8180_priv *priv = ieee80211_priv(dev); - - schedule_work(&priv->reset_wq); -} - -void rtl8180_commit(struct net_device *dev) -{ - struct r8180_priv *priv = ieee80211_priv(dev); - - if (priv->up == 0) - return; - - del_timer_sync(&priv->watch_dog_timer); - del_timer_sync(&priv->rateadapter_timer); - cancel_delayed_work(&priv->ieee80211->rate_adapter_wq); - cancel_delayed_work(&priv->ieee80211->hw_wakeup_wq); - cancel_delayed_work(&priv->ieee80211->hw_sleep_wq); - cancel_delayed_work(&priv->ieee80211->hw_dig_wq); - cancel_delayed_work(&priv->ieee80211->tx_pw_wq); - del_timer_sync(&priv->SwAntennaDiversityTimer); - ieee80211_softmac_stop_protocol(priv->ieee80211); - rtl8180_irq_disable(dev); - rtl8180_rtx_disable(dev); - _rtl8180_up(dev); -} - -static void r8180_set_multicast(struct net_device *dev) -{ - struct r8180_priv *priv = ieee80211_priv(dev); - short promisc; - - promisc = (dev->flags & IFF_PROMISC) ? 1 : 0; - - if (promisc != priv->promisc) - rtl8180_restart(dev); - - priv->promisc = promisc; -} - -static int r8180_set_mac_adr(struct net_device *dev, void *mac) -{ - struct r8180_priv *priv = ieee80211_priv(dev); - struct sockaddr *addr = mac; - - down(&priv->wx_sem); - - memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); - - if (priv->ieee80211->iw_mode == IW_MODE_MASTER) - memcpy(priv->ieee80211->current_network.bssid, - dev->dev_addr, ETH_ALEN); - - if (priv->up) { - rtl8180_down(dev); - rtl8180_up(dev); - } - - up(&priv->wx_sem); - - return 0; -} - -/* based on ipw2200 driver */ -static int rtl8180_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) -{ - struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); - struct iwreq *wrq = (struct iwreq *) rq; - int ret = -1; - - switch (cmd) { - case RTL_IOCTL_WPA_SUPPLICANT: - ret = ieee80211_wpa_supplicant_ioctl( - priv->ieee80211, &wrq->u.data); - return ret; - default: - return -EOPNOTSUPP; - } - - return -EOPNOTSUPP; -} - -static const struct net_device_ops rtl8180_netdev_ops = { - .ndo_open = rtl8180_open, - .ndo_stop = rtl8180_close, - .ndo_get_stats = rtl8180_stats, - .ndo_tx_timeout = rtl8180_restart, - .ndo_do_ioctl = rtl8180_ioctl, - .ndo_set_rx_mode = r8180_set_multicast, - .ndo_set_mac_address = r8180_set_mac_adr, - .ndo_validate_addr = eth_validate_addr, - .ndo_change_mtu = eth_change_mtu, - .ndo_start_xmit = ieee80211_rtl_xmit, -}; - -static int rtl8180_pci_probe(struct pci_dev *pdev, - const struct pci_device_id *id) -{ - unsigned long ioaddr = 0; - struct net_device *dev = NULL; - struct r8180_priv *priv = NULL; - u8 unit = 0; - int ret = -ENODEV; - - unsigned long pmem_start, pmem_len, pmem_flags; - - DMESG("Configuring chip resources"); - - if (pci_enable_device(pdev)) { - DMESG("Failed to enable PCI device"); - return -EIO; - } - - pci_set_master(pdev); - pci_set_dma_mask(pdev, 0xffffff00ULL); - pci_set_consistent_dma_mask(pdev, 0xffffff00ULL); - dev = alloc_ieee80211(sizeof(struct r8180_priv)); - if (!dev) { - ret = -ENOMEM; - goto fail_free; - } - priv = ieee80211_priv(dev); - priv->ieee80211 = netdev_priv(dev); - - pci_set_drvdata(pdev, dev); - SET_NETDEV_DEV(dev, &pdev->dev); - - priv = ieee80211_priv(dev); - priv->pdev = pdev; - - pmem_start = pci_resource_start(pdev, 1); - pmem_len = pci_resource_len(pdev, 1); - pmem_flags = pci_resource_flags(pdev, 1); - - if (!(pmem_flags & IORESOURCE_MEM)) { - DMESG("region #1 not a MMIO resource, aborting"); - goto fail; - } - - if (!request_mem_region(pmem_start, pmem_len, RTL8180_MODULE_NAME)) { - DMESG("request_mem_region failed!"); - goto fail; - } - - ioaddr = (unsigned long)ioremap_nocache(pmem_start, pmem_len); - if (ioaddr == (unsigned long)NULL) { - DMESG("ioremap failed!"); - goto fail1; - } - - dev->mem_start = ioaddr; /* shared mem start */ - dev->mem_end = ioaddr + pci_resource_len(pdev, 0); /* shared mem end */ - - pci_read_config_byte(pdev, 0x05, &unit); - pci_write_config_byte(pdev, 0x05, unit & (~0x04)); - - dev->irq = pdev->irq; - priv->irq = 0; - - dev->netdev_ops = &rtl8180_netdev_ops; - dev->wireless_handlers = &r8180_wx_handlers_def; - - dev->type = ARPHRD_ETHER; - dev->watchdog_timeo = HZ*3; - - if (dev_alloc_name(dev, ifname) < 0) { - DMESG("Oops: devname already taken! Trying wlan%%d...\n"); - strcpy(ifname, "wlan%d"); - dev_alloc_name(dev, ifname); - } - - if (rtl8180_init(dev) != 0) { - DMESG("Initialization failed"); - goto fail1; - } - - netif_carrier_off(dev); - - if (register_netdev(dev)) - goto fail1; - - rtl8180_proc_init_one(dev); - - DMESG("Driver probe completed\n"); - return 0; -fail1: - if (dev->mem_start != (unsigned long)NULL) { - iounmap((void __iomem *)dev->mem_start); - release_mem_region(pci_resource_start(pdev, 1), - pci_resource_len(pdev, 1)); - } -fail: - if (dev) { - if (priv->irq) { - free_irq(dev->irq, dev); - dev->irq = 0; - } - free_ieee80211(dev); - } - -fail_free: - pci_disable_device(pdev); - - DMESG("wlan driver load failed\n"); - return ret; -} - -static void rtl8180_pci_remove(struct pci_dev *pdev) -{ - struct r8180_priv *priv; - struct net_device *dev = pci_get_drvdata(pdev); - - if (dev) { - unregister_netdev(dev); - - priv = ieee80211_priv(dev); - - rtl8180_proc_remove_one(dev); - rtl8180_down(dev); - priv->rf_close(dev); - rtl8180_reset(dev); - mdelay(10); - - if (priv->irq) { - DMESG("Freeing irq %d", dev->irq); - free_irq(dev->irq, dev); - priv->irq = 0; - } - - free_rx_desc_ring(dev); - free_tx_desc_rings(dev); - - if (dev->mem_start != (unsigned long)NULL) { - iounmap((void __iomem *)dev->mem_start); - release_mem_region(pci_resource_start(pdev, 1), - pci_resource_len(pdev, 1)); - } - - free_ieee80211(dev); - } - pci_disable_device(pdev); - - DMESG("wlan driver removed\n"); -} - -static int __init rtl8180_pci_module_init(void) -{ - int ret; - - ret = ieee80211_crypto_init(); - if (ret) { - pr_err("ieee80211_crypto_init() failed %d\n", ret); - return ret; - } - ret = ieee80211_crypto_tkip_init(); - if (ret) { - pr_err("ieee80211_crypto_tkip_init() failed %d\n", ret); - return ret; - } - ret = ieee80211_crypto_ccmp_init(); - if (ret) { - pr_err("ieee80211_crypto_ccmp_init() failed %d\n", ret); - return ret; - } - ret = ieee80211_crypto_wep_init(); - if (ret) { - pr_err("ieee80211_crypto_wep_init() failed %d\n", ret); - return ret; - } - - pr_info("\nLinux kernel driver for RTL8180 / RTL8185 based WLAN cards\n"); - pr_info("Copyright (c) 2004-2005, Andrea Merello\n"); - DMESG("Initializing module"); - DMESG("Wireless extensions version %d", WIRELESS_EXT); - rtl8180_proc_module_init(); - - if (pci_register_driver(&rtl8180_pci_driver)) { - DMESG("No device found"); - return -ENODEV; - } - return 0; -} - -static void __exit rtl8180_pci_module_exit(void) -{ - pci_unregister_driver(&rtl8180_pci_driver); - rtl8180_proc_module_remove(); - ieee80211_crypto_tkip_exit(); - ieee80211_crypto_ccmp_exit(); - ieee80211_crypto_wep_exit(); - ieee80211_crypto_deinit(); - DMESG("Exiting"); -} - -static void rtl8180_try_wake_queue(struct net_device *dev, int pri) -{ - unsigned long flags; - short enough_desc; - struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); - - spin_lock_irqsave(&priv->tx_lock, flags); - enough_desc = check_nic_enought_desc(dev, pri); - spin_unlock_irqrestore(&priv->tx_lock, flags); - - if (enough_desc) - ieee80211_rtl_wake_queue(priv->ieee80211); -} - -static void rtl8180_tx_isr(struct net_device *dev, int pri, short error) -{ - struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); - u32 *tail; /* tail virtual addr */ - u32 *head; /* head virtual addr */ - u32 *begin; /* start of ring virtual addr */ - u32 *nicv; /* nic pointer virtual addr */ - u32 nic; /* nic pointer physical addr */ - u32 nicbegin; /* start of ring physical addr */ - unsigned long flag; - /* physical addr are ok on 32 bits since we set DMA mask */ - int offs; - int j, i; - int hd; - if (error) - priv->stats.txretry++; - spin_lock_irqsave(&priv->tx_lock, flag); - switch (pri) { - case MANAGE_PRIORITY: - tail = priv->txmapringtail; - begin = priv->txmapring; - head = priv->txmapringhead; - nic = read_nic_dword(dev, TX_MANAGEPRIORITY_RING_ADDR); - nicbegin = priv->txmapringdma; - break; - case BK_PRIORITY: - tail = priv->txbkpringtail; - begin = priv->txbkpring; - head = priv->txbkpringhead; - nic = read_nic_dword(dev, TX_BKPRIORITY_RING_ADDR); - nicbegin = priv->txbkpringdma; - break; - case BE_PRIORITY: - tail = priv->txbepringtail; - begin = priv->txbepring; - head = priv->txbepringhead; - nic = read_nic_dword(dev, TX_BEPRIORITY_RING_ADDR); - nicbegin = priv->txbepringdma; - break; - case VI_PRIORITY: - tail = priv->txvipringtail; - begin = priv->txvipring; - head = priv->txvipringhead; - nic = read_nic_dword(dev, TX_VIPRIORITY_RING_ADDR); - nicbegin = priv->txvipringdma; - break; - case VO_PRIORITY: - tail = priv->txvopringtail; - begin = priv->txvopring; - head = priv->txvopringhead; - nic = read_nic_dword(dev, TX_VOPRIORITY_RING_ADDR); - nicbegin = priv->txvopringdma; - break; - case HI_PRIORITY: - tail = priv->txhpringtail; - begin = priv->txhpring; - head = priv->txhpringhead; - nic = read_nic_dword(dev, TX_HIGHPRIORITY_RING_ADDR); - nicbegin = priv->txhpringdma; - break; - - default: - spin_unlock_irqrestore(&priv->tx_lock, flag); - return; - } - - nicv = (u32 *)((nic - nicbegin) + (u8 *)begin); - if ((head <= tail && (nicv > tail || nicv < head)) || - (head > tail && (nicv > tail && nicv < head))) { - DMESGW("nic has lost pointer"); - spin_unlock_irqrestore(&priv->tx_lock, flag); - rtl8180_restart(dev); - return; - } - - /* - * We check all the descriptors between the head and the nic, - * but not the currently pointed by the nic (the next to be txed) - * and the previous of the pointed (might be in process ??) - */ - offs = (nic - nicbegin); - offs = offs / 8 / 4; - hd = (head - begin) / 8; - - if (offs >= hd) - j = offs - hd; - else - j = offs + (priv->txringcount-1-hd); - - j -= 2; - if (j < 0) - j = 0; - - for (i = 0; i < j; i++) { - if ((*head) & (1<<31)) - break; - if (((*head)&(0x10000000)) != 0) { - priv->CurrRetryCnt += (u16)((*head) & (0x000000ff)); - if (!error) - priv->NumTxOkTotal++; - } - - if (!error) - priv->NumTxOkBytesTotal += (*(head+3)) & (0x00000fff); - - *head = *head & ~(1<<31); - - if ((head - begin)/8 == priv->txringcount-1) - head = begin; - else - head += 8; - } - - /* - * The head has been moved to the last certainly TXed - * (or at least processed by the nic) packet. - * The driver take forcefully owning of all these packets - * If the packet previous of the nic pointer has been - * processed this doesn't matter: it will be checked - * here at the next round. Anyway if no more packet are - * TXed no memory leak occur at all. - */ - - switch (pri) { - case MANAGE_PRIORITY: - priv->txmapringhead = head; - - if (priv->ack_tx_to_ieee) { - if (rtl8180_is_tx_queue_empty(dev)) { - priv->ack_tx_to_ieee = 0; - ieee80211_ps_tx_ack(priv->ieee80211, !error); - } - } - break; - case BK_PRIORITY: - priv->txbkpringhead = head; - break; - case BE_PRIORITY: - priv->txbepringhead = head; - break; - case VI_PRIORITY: - priv->txvipringhead = head; - break; - case VO_PRIORITY: - priv->txvopringhead = head; - break; - case HI_PRIORITY: - priv->txhpringhead = head; - break; - } - - spin_unlock_irqrestore(&priv->tx_lock, flag); -} - -static irqreturn_t rtl8180_interrupt(int irq, void *netdev) -{ - struct net_device *dev = (struct net_device *) netdev; - struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); - unsigned long flags; - u32 inta; - - /* We should return IRQ_NONE, but for now let me keep this */ - if (priv->irq_enabled == 0) - return IRQ_HANDLED; - - spin_lock_irqsave(&priv->irq_th_lock, flags); - - /* ISR: 4bytes */ - inta = read_nic_dword(dev, ISR); - write_nic_dword(dev, ISR, inta); /* reset int situation */ - - priv->stats.shints++; - - if (!inta) { - spin_unlock_irqrestore(&priv->irq_th_lock, flags); - return IRQ_HANDLED; - /* - * most probably we can safely return IRQ_NONE, - * but for now is better to avoid problems - */ - } - - if (inta == 0xffff) { - /* HW disappeared */ - spin_unlock_irqrestore(&priv->irq_th_lock, flags); - return IRQ_HANDLED; - } - - priv->stats.ints++; - - if (!netif_running(dev)) { - spin_unlock_irqrestore(&priv->irq_th_lock, flags); - return IRQ_HANDLED; - } - - if (inta & ISR_TimeOut) - write_nic_dword(dev, TimerInt, 0); - - if (inta & ISR_TBDOK) - priv->stats.txbeacon++; - - if (inta & ISR_TBDER) - priv->stats.txbeaconerr++; - - if (inta & IMR_TMGDOK) - rtl8180_tx_isr(dev, MANAGE_PRIORITY, 0); - - if (inta & ISR_THPDER) { - priv->stats.txhperr++; - rtl8180_tx_isr(dev, HI_PRIORITY, 1); - priv->ieee80211->stats.tx_errors++; - } - - if (inta & ISR_THPDOK) { /* High priority tx ok */ - priv->link_detect.num_tx_ok_in_period++; - priv->stats.txhpokint++; - rtl8180_tx_isr(dev, HI_PRIORITY, 0); - } - - if (inta & ISR_RER) - priv->stats.rxerr++; - - if (inta & ISR_TBKDER) { /* corresponding to BK_PRIORITY */ - priv->stats.txbkperr++; - priv->ieee80211->stats.tx_errors++; - rtl8180_tx_isr(dev, BK_PRIORITY, 1); - rtl8180_try_wake_queue(dev, BK_PRIORITY); - } - - if (inta & ISR_TBEDER) { /* corresponding to BE_PRIORITY */ - priv->stats.txbeperr++; - priv->ieee80211->stats.tx_errors++; - rtl8180_tx_isr(dev, BE_PRIORITY, 1); - rtl8180_try_wake_queue(dev, BE_PRIORITY); - } - if (inta & ISR_TNPDER) { /* corresponding to VO_PRIORITY */ - priv->stats.txnperr++; - priv->ieee80211->stats.tx_errors++; - rtl8180_tx_isr(dev, NORM_PRIORITY, 1); - rtl8180_try_wake_queue(dev, NORM_PRIORITY); - } - - if (inta & ISR_TLPDER) { /* corresponding to VI_PRIORITY */ - priv->stats.txlperr++; - priv->ieee80211->stats.tx_errors++; - rtl8180_tx_isr(dev, LOW_PRIORITY, 1); - rtl8180_try_wake_queue(dev, LOW_PRIORITY); - } - - if (inta & ISR_ROK) { - priv->stats.rxint++; - tasklet_schedule(&priv->irq_rx_tasklet); - } - - if (inta & ISR_RQoSOK) { - priv->stats.rxint++; - tasklet_schedule(&priv->irq_rx_tasklet); - } - - if (inta & ISR_BcnInt) - rtl8180_prepare_beacon(dev); - - if (inta & ISR_RDU) { - DMESGW("No RX descriptor available"); - priv->stats.rxrdu++; - tasklet_schedule(&priv->irq_rx_tasklet); - } - - if (inta & ISR_RXFOVW) { - priv->stats.rxoverflow++; - tasklet_schedule(&priv->irq_rx_tasklet); - } - - if (inta & ISR_TXFOVW) - priv->stats.txoverflow++; - - if (inta & ISR_TNPDOK) { /* Normal priority tx ok */ - priv->link_detect.num_tx_ok_in_period++; - priv->stats.txnpokint++; - rtl8180_tx_isr(dev, NORM_PRIORITY, 0); - rtl8180_try_wake_queue(dev, NORM_PRIORITY); - } - - if (inta & ISR_TLPDOK) { /* Low priority tx ok */ - priv->link_detect.num_tx_ok_in_period++; - priv->stats.txlpokint++; - rtl8180_tx_isr(dev, LOW_PRIORITY, 0); - rtl8180_try_wake_queue(dev, LOW_PRIORITY); - } - - if (inta & ISR_TBKDOK) { /* corresponding to BK_PRIORITY */ - priv->stats.txbkpokint++; - priv->link_detect.num_tx_ok_in_period++; - rtl8180_tx_isr(dev, BK_PRIORITY, 0); - rtl8180_try_wake_queue(dev, BE_PRIORITY); - } - - if (inta & ISR_TBEDOK) { /* corresponding to BE_PRIORITY */ - priv->stats.txbeperr++; - priv->link_detect.num_tx_ok_in_period++; - rtl8180_tx_isr(dev, BE_PRIORITY, 0); - rtl8180_try_wake_queue(dev, BE_PRIORITY); - } - force_pci_posting(dev); - spin_unlock_irqrestore(&priv->irq_th_lock, flags); - - return IRQ_HANDLED; -} - -void rtl8180_irq_rx_tasklet(struct r8180_priv *priv) -{ - rtl8180_rx(priv->dev); -} - -void GPIOChangeRFWorkItemCallBack(struct work_struct *work) -{ - struct ieee80211_device *ieee = container_of( - work, struct ieee80211_device, GPIOChangeRFWorkItem.work); - struct net_device *dev = ieee->dev; - struct r8180_priv *priv = ieee80211_priv(dev); - u8 btPSR; - u8 btConfig0; - enum rt_rf_power_state eRfPowerStateToSet; - bool bActuallySet = false; - - char *argv[3]; - static char *RadioPowerPath = "/etc/acpi/events/RadioPower.sh"; - static char *envp[] = {"HOME=/", "TERM=linux", - "PATH=/usr/bin:/bin", NULL}; - static int readf_count; - - readf_count = (readf_count+1)%0xffff; - /* We should turn off LED before polling FF51[4]. */ - - /* Turn off LED. */ - btPSR = read_nic_byte(dev, PSR); - write_nic_byte(dev, PSR, (btPSR & ~BIT3)); - - /* It need to delay 4us suggested */ - udelay(4); - - /* HW radio On/Off according to the value of FF51[4](config0) */ - btConfig0 = btPSR = read_nic_byte(dev, CONFIG0); - - eRfPowerStateToSet = (btConfig0 & BIT4) ? RF_ON : RF_OFF; - - /* Turn LED back on when radio enabled */ - if (eRfPowerStateToSet == RF_ON) - write_nic_byte(dev, PSR, btPSR | BIT3); - - if ((priv->ieee80211->bHwRadioOff == true) && - (eRfPowerStateToSet == RF_ON)) { - priv->ieee80211->bHwRadioOff = false; - bActuallySet = true; - } else if ((priv->ieee80211->bHwRadioOff == false) && - (eRfPowerStateToSet == RF_OFF)) { - priv->ieee80211->bHwRadioOff = true; - bActuallySet = true; - } - - if (bActuallySet) { - MgntActSet_RF_State(dev, eRfPowerStateToSet, RF_CHANGE_BY_HW); - - /* To update the UI status for Power status changed */ - if (priv->ieee80211->bHwRadioOff == true) - argv[1] = "RFOFF"; - else - argv[1] = "RFON"; - argv[0] = RadioPowerPath; - argv[2] = NULL; - - call_usermodehelper(RadioPowerPath, argv, envp, UMH_WAIT_PROC); - } -} - -module_init(rtl8180_pci_module_init); -module_exit(rtl8180_pci_module_exit); diff --git a/drivers/staging/rtl8187se/r8180_dm.c b/drivers/staging/rtl8187se/r8180_dm.c deleted file mode 100644 index 8c020e06486..00000000000 --- a/drivers/staging/rtl8187se/r8180_dm.c +++ /dev/null @@ -1,1139 +0,0 @@ -#include "r8180_dm.h" -#include "r8180_hw.h" -#include "r8180_93cx6.h" - - /* Return TRUE if we shall perform High Power Mechanism, FALSE otherwise. */ -#define RATE_ADAPTIVE_TIMER_PERIOD 300 - -bool CheckHighPower(struct net_device *dev) -{ - struct r8180_priv *priv = ieee80211_priv(dev); - struct ieee80211_device *ieee = priv->ieee80211; - - if (!priv->bRegHighPowerMechanism) - return false; - - if (ieee->state == IEEE80211_LINKED_SCANNING) - return false; - - return true; -} - -/* - * Description: - * Update Tx power level if necessary. - * See also DoRxHighPower() and SetTxPowerLevel8185() for reference. - * - * Note: - * The reason why we udpate Tx power level here instead of DoRxHighPower() - * is the number of IO to change Tx power is much more than channel TR switch - * and they are related to OFDM and MAC registers. - * So, we don't want to update it so frequently in per-Rx packet base. - */ -static void DoTxHighPower(struct net_device *dev) -{ - struct r8180_priv *priv = ieee80211_priv(dev); - u16 HiPwrUpperTh = 0; - u16 HiPwrLowerTh = 0; - u8 RSSIHiPwrUpperTh; - u8 RSSIHiPwrLowerTh; - u8 u1bTmp; - char OfdmTxPwrIdx, CckTxPwrIdx; - - HiPwrUpperTh = priv->RegHiPwrUpperTh; - HiPwrLowerTh = priv->RegHiPwrLowerTh; - - HiPwrUpperTh = HiPwrUpperTh * 10; - HiPwrLowerTh = HiPwrLowerTh * 10; - RSSIHiPwrUpperTh = priv->RegRSSIHiPwrUpperTh; - RSSIHiPwrLowerTh = priv->RegRSSIHiPwrLowerTh; - - /* lzm add 080826 */ - OfdmTxPwrIdx = priv->chtxpwr_ofdm[priv->ieee80211->current_network.channel]; - CckTxPwrIdx = priv->chtxpwr[priv->ieee80211->current_network.channel]; - - if ((priv->UndecoratedSmoothedSS > HiPwrUpperTh) || - (priv->bCurCCKPkt && (priv->CurCCKRSSI > RSSIHiPwrUpperTh))) { - /* Stevenl suggested that degrade 8dbm in high power sate. 2007-12-04 Isaiah */ - - priv->bToUpdateTxPwr = true; - u1bTmp = read_nic_byte(dev, CCK_TXAGC); - - /* If it never enter High Power. */ - if (CckTxPwrIdx == u1bTmp) { - u1bTmp = (u1bTmp > 16) ? (u1bTmp - 16) : 0; /* 8dbm */ - write_nic_byte(dev, CCK_TXAGC, u1bTmp); - - u1bTmp = read_nic_byte(dev, OFDM_TXAGC); - u1bTmp = (u1bTmp > 16) ? (u1bTmp - 16) : 0; /* 8dbm */ - write_nic_byte(dev, OFDM_TXAGC, u1bTmp); - } - - } else if ((priv->UndecoratedSmoothedSS < HiPwrLowerTh) && - (!priv->bCurCCKPkt || priv->CurCCKRSSI < RSSIHiPwrLowerTh)) { - if (priv->bToUpdateTxPwr) { - priv->bToUpdateTxPwr = false; - /* SD3 required. */ - u1bTmp = read_nic_byte(dev, CCK_TXAGC); - if (u1bTmp < CckTxPwrIdx) { - write_nic_byte(dev, CCK_TXAGC, CckTxPwrIdx); - } - - u1bTmp = read_nic_byte(dev, OFDM_TXAGC); - if (u1bTmp < OfdmTxPwrIdx) { - write_nic_byte(dev, OFDM_TXAGC, OfdmTxPwrIdx); - } - } - } -} - - -/* - * Description: - * Callback function of UpdateTxPowerWorkItem. - * Because of some event happened, e.g. CCX TPC, High Power Mechanism, - * We update Tx power of current channel again. - */ -void rtl8180_tx_pw_wq(struct work_struct *work) -{ - struct delayed_work *dwork = to_delayed_work(work); - struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, tx_pw_wq); - struct net_device *dev = ieee->dev; - - DoTxHighPower(dev); -} - - -/* - * Return TRUE if we shall perform DIG Mechanism, FALSE otherwise. - */ -bool CheckDig(struct net_device *dev) -{ - struct r8180_priv *priv = ieee80211_priv(dev); - struct ieee80211_device *ieee = priv->ieee80211; - - if (!priv->bDigMechanism) - return false; - - if (ieee->state != IEEE80211_LINKED) - return false; - - if ((priv->ieee80211->rate / 5) < 36) /* Schedule Dig under all OFDM rates. By Bruce, 2007-06-01. */ - return false; - return true; -} -/* - * Implementation of DIG for Zebra and Zebra2. - */ -static void DIG_Zebra(struct net_device *dev) -{ - struct r8180_priv *priv = ieee80211_priv(dev); - u16 CCKFalseAlarm, OFDMFalseAlarm; - u16 OfdmFA1, OfdmFA2; - int InitialGainStep = 7; /* The number of initial gain stages. */ - int LowestGainStage = 4; /* The capable lowest stage of performing dig workitem. */ - u32 AwakePeriodIn2Sec = 0; - - CCKFalseAlarm = (u16)(priv->FalseAlarmRegValue & 0x0000ffff); - OFDMFalseAlarm = (u16)((priv->FalseAlarmRegValue >> 16) & 0x0000ffff); - OfdmFA1 = 0x15; - OfdmFA2 = ((u16)(priv->RegDigOfdmFaUpTh)) << 8; - - /* The number of initial gain steps is different, by Bruce, 2007-04-13. */ - if (priv->InitialGain == 0) { /* autoDIG */ - /* Advised from SD3 DZ */ - priv->InitialGain = 4; /* In 87B, m74dBm means State 4 (m82dBm) */ - } - /* Advised from SD3 DZ */ - OfdmFA1 = 0x20; - -#if 1 /* lzm reserved 080826 */ - AwakePeriodIn2Sec = (2000 - priv->DozePeriodInPast2Sec); - priv->DozePeriodInPast2Sec = 0; - - if (AwakePeriodIn2Sec) { - OfdmFA1 = (u16)((OfdmFA1 * AwakePeriodIn2Sec) / 2000); - OfdmFA2 = (u16)((OfdmFA2 * AwakePeriodIn2Sec) / 2000); - } else { - ; - } -#endif - - InitialGainStep = 8; - LowestGainStage = priv->RegBModeGainStage; /* Lowest gain stage. */ - - if (OFDMFalseAlarm > OfdmFA1) { - if (OFDMFalseAlarm > OfdmFA2) { - priv->DIG_NumberFallbackVote++; - if (priv->DIG_NumberFallbackVote > 1) { - /* serious OFDM False Alarm, need fallback */ - if (priv->InitialGain < InitialGainStep) { - priv->InitialGainBackUp = priv->InitialGain; - - priv->InitialGain = (priv->InitialGain + 1); - UpdateInitialGain(dev); - } - priv->DIG_NumberFallbackVote = 0; - priv->DIG_NumberUpgradeVote = 0; - } - } else { - if (priv->DIG_NumberFallbackVote) - priv->DIG_NumberFallbackVote--; - } - priv->DIG_NumberUpgradeVote = 0; - } else { - if (priv->DIG_NumberFallbackVote) - priv->DIG_NumberFallbackVote--; - priv->DIG_NumberUpgradeVote++; - - if (priv->DIG_NumberUpgradeVote > 9) { - if (priv->InitialGain > LowestGainStage) { /* In 87B, m78dBm means State 4 (m864dBm) */ - priv->InitialGainBackUp = priv->InitialGain; - - priv->InitialGain = (priv->InitialGain - 1); - UpdateInitialGain(dev); - } - priv->DIG_NumberFallbackVote = 0; - priv->DIG_NumberUpgradeVote = 0; - } - } -} - -/* - * Dispatch DIG implementation according to RF. - */ -static void DynamicInitGain(struct net_device *dev) -{ - DIG_Zebra(dev); -} - -void rtl8180_hw_dig_wq(struct work_struct *work) -{ - struct delayed_work *dwork = to_delayed_work(work); - struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, hw_dig_wq); - struct net_device *dev = ieee->dev; - struct r8180_priv *priv = ieee80211_priv(dev); - - /* Read CCK and OFDM False Alarm. */ - priv->FalseAlarmRegValue = read_nic_dword(dev, CCK_FALSE_ALARM); - - - /* Adjust Initial Gain dynamically. */ - DynamicInitGain(dev); - -} - -static int IncludedInSupportedRates(struct r8180_priv *priv, u8 TxRate) -{ - u8 rate_len; - u8 rate_ex_len; - u8 RateMask = 0x7F; - u8 idx; - unsigned short Found = 0; - u8 NaiveTxRate = TxRate&RateMask; - - rate_len = priv->ieee80211->current_network.rates_len; - rate_ex_len = priv->ieee80211->current_network.rates_ex_len; - for (idx = 0; idx < rate_len; idx++) { - if ((priv->ieee80211->current_network.rates[idx] & RateMask) == NaiveTxRate) { - Found = 1; - goto found_rate; - } - } - for (idx = 0; idx < rate_ex_len; idx++) { - if ((priv->ieee80211->current_network.rates_ex[idx] & RateMask) == NaiveTxRate) { - Found = 1; - goto found_rate; - } - } - return Found; -found_rate: - return Found; -} - -/* - * Get the Tx rate one degree up form the input rate in the supported rates. - * Return the upgrade rate if it is successed, otherwise return the input rate. - */ -static u8 GetUpgradeTxRate(struct net_device *dev, u8 rate) -{ - struct r8180_priv *priv = ieee80211_priv(dev); - u8 UpRate; - - /* Upgrade 1 degree. */ - switch (rate) { - case 108: /* Up to 54Mbps. */ - UpRate = 108; - break; - - case 96: /* Up to 54Mbps. */ - UpRate = 108; - break; - - case 72: /* Up to 48Mbps. */ - UpRate = 96; - break; - - case 48: /* Up to 36Mbps. */ - UpRate = 72; - break; - - case 36: /* Up to 24Mbps. */ - UpRate = 48; - break; - - case 22: /* Up to 18Mbps. */ - UpRate = 36; - break; - - case 11: /* Up to 11Mbps. */ - UpRate = 22; - break; - - case 4: /* Up to 5.5Mbps. */ - UpRate = 11; - break; - - case 2: /* Up to 2Mbps. */ - UpRate = 4; - break; - - default: - printk("GetUpgradeTxRate(): Input Tx Rate(%d) is undefined!\n", rate); - return rate; - } - /* Check if the rate is valid. */ - if (IncludedInSupportedRates(priv, UpRate)) { - return UpRate; - } else { - return rate; - } - return rate; -} -/* - * Get the Tx rate one degree down form the input rate in the supported rates. - * Return the degrade rate if it is successed, otherwise return the input rate. - */ - -static u8 GetDegradeTxRate(struct net_device *dev, u8 rate) -{ - struct r8180_priv *priv = ieee80211_priv(dev); - u8 DownRate; - - /* Upgrade 1 degree. */ - switch (rate) { - case 108: /* Down to 48Mbps. */ - DownRate = 96; - break; - - case 96: /* Down to 36Mbps. */ - DownRate = 72; - break; - - case 72: /* Down to 24Mbps. */ - DownRate = 48; - break; - - case 48: /* Down to 18Mbps. */ - DownRate = 36; - break; - - case 36: /* Down to 11Mbps. */ - DownRate = 22; - break; - - case 22: /* Down to 5.5Mbps. */ - DownRate = 11; - break; - - case 11: /* Down to 2Mbps. */ - DownRate = 4; - break; - - case 4: /* Down to 1Mbps. */ - DownRate = 2; - break; - - case 2: /* Down to 1Mbps. */ - DownRate = 2; - break; - - default: - printk("GetDegradeTxRate(): Input Tx Rate(%d) is undefined!\n", rate); - return rate; - } - /* Check if the rate is valid. */ - if (IncludedInSupportedRates(priv, DownRate)) { - return DownRate; - } else { - return rate; - } - return rate; -} -/* - * Helper function to determine if specified data rate is - * CCK rate. - */ - -static bool MgntIsCckRate(u16 rate) -{ - bool bReturn = false; - - if ((rate <= 22) && (rate != 12) && (rate != 18)) { - bReturn = true; - } - - return bReturn; -} -/* - * Description: - * Tx Power tracking mechanism routine on 87SE. - */ -void TxPwrTracking87SE(struct net_device *dev) -{ - struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); - u8 tmpu1Byte, CurrentThermal, Idx; - char CckTxPwrIdx, OfdmTxPwrIdx; - - tmpu1Byte = read_nic_byte(dev, EN_LPF_CAL); - CurrentThermal = (tmpu1Byte & 0xf0) >> 4; /*[ 7:4]: thermal meter indication. */ - CurrentThermal = (CurrentThermal > 0x0c) ? 0x0c : CurrentThermal;/* lzm add 080826 */ - - if (CurrentThermal != priv->ThermalMeter) { - /* Update Tx Power level on each channel. */ - for (Idx = 1; Idx < 15; Idx++) { - CckTxPwrIdx = priv->chtxpwr[Idx]; - OfdmTxPwrIdx = priv->chtxpwr_ofdm[Idx]; - - if (CurrentThermal > priv->ThermalMeter) { - /* higher thermal meter. */ - CckTxPwrIdx += (CurrentThermal - priv->ThermalMeter) * 2; - OfdmTxPwrIdx += (CurrentThermal - priv->ThermalMeter) * 2; - - if (CckTxPwrIdx > 35) - CckTxPwrIdx = 35; /* Force TxPower to maximal index. */ - if (OfdmTxPwrIdx > 35) - OfdmTxPwrIdx = 35; - } else { - /* lower thermal meter. */ - CckTxPwrIdx -= (priv->ThermalMeter - CurrentThermal) * 2; - OfdmTxPwrIdx -= (priv->ThermalMeter - CurrentThermal) * 2; - - if (CckTxPwrIdx < 0) - CckTxPwrIdx = 0; - if (OfdmTxPwrIdx < 0) - OfdmTxPwrIdx = 0; - } - - /* Update TxPower level on CCK and OFDM resp. */ - priv->chtxpwr[Idx] = CckTxPwrIdx; - priv->chtxpwr_ofdm[Idx] = OfdmTxPwrIdx; - } - - /* Update TxPower level immediately. */ - rtl8225z2_SetTXPowerLevel(dev, priv->ieee80211->current_network.channel); - } - priv->ThermalMeter = CurrentThermal; -} -static void StaRateAdaptive87SE(struct net_device *dev) -{ - struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); - unsigned long CurrTxokCnt; - u16 CurrRetryCnt; - u16 CurrRetryRate; - unsigned long CurrRxokCnt; - bool bTryUp = false; - bool bTryDown = false; - u8 TryUpTh = 1; - u8 TryDownTh = 2; - u32 TxThroughput; - long CurrSignalStrength; - bool bUpdateInitialGain = false; - u8 u1bOfdm = 0, u1bCck = 0; - char OfdmTxPwrIdx, CckTxPwrIdx; - - priv->RateAdaptivePeriod = RATE_ADAPTIVE_TIMER_PERIOD; - - - CurrRetryCnt = priv->CurrRetryCnt; - CurrTxokCnt = priv->NumTxOkTotal - priv->LastTxokCnt; - CurrRxokCnt = priv->ieee80211->NumRxOkTotal - priv->LastRxokCnt; - CurrSignalStrength = priv->Stats_RecvSignalPower; - TxThroughput = (u32)(priv->NumTxOkBytesTotal - priv->LastTxOKBytes); - priv->LastTxOKBytes = priv->NumTxOkBytesTotal; - priv->CurrentOperaRate = priv->ieee80211->rate / 5; - /* 2 Compute retry ratio. */ - if (CurrTxokCnt > 0) { - CurrRetryRate = (u16)(CurrRetryCnt * 100 / CurrTxokCnt); - } else { - /* It may be serious retry. To distinguish serious retry or no packets modified by Bruce */ - CurrRetryRate = (u16)(CurrRetryCnt * 100 / 1); - } - - priv->LastRetryCnt = priv->CurrRetryCnt; - priv->LastTxokCnt = priv->NumTxOkTotal; - priv->LastRxokCnt = priv->ieee80211->NumRxOkTotal; - priv->CurrRetryCnt = 0; - - /* 2No Tx packets, return to init_rate or not? */ - if (CurrRetryRate == 0 && CurrTxokCnt == 0) { - /* - * After 9 (30*300ms) seconds in this condition, we try to raise rate. - */ - priv->TryupingCountNoData++; - - /* [TRC Dell Lab] Extend raised period from 4.5sec to 9sec, Isaiah 2008-02-15 18:00 */ - if (priv->TryupingCountNoData > 30) { - priv->TryupingCountNoData = 0; - priv->CurrentOperaRate = GetUpgradeTxRate(dev, priv->CurrentOperaRate); - /* Reset Fail Record */ - priv->LastFailTxRate = 0; - priv->LastFailTxRateSS = -200; - priv->FailTxRateCount = 0; - } - goto SetInitialGain; - } else { - priv->TryupingCountNoData = 0; /*Reset trying up times. */ - } - - - /* - * For Netgear case, I comment out the following signal strength estimation, - * which can results in lower rate to transmit when sample is NOT enough (e.g. PING request). - * - * Restructure rate adaptive as the following main stages: - * (1) Add retry threshold in 54M upgrading condition with signal strength. - * (2) Add the mechanism to degrade to CCK rate according to signal strength - * and retry rate. - * (3) Remove all Initial Gain Updates over OFDM rate. To avoid the complicated - * situation, Initial Gain Update is upon on DIG mechanism except CCK rate. - * (4) Add the mechanism of trying to upgrade tx rate. - * (5) Record the information of upping tx rate to avoid trying upping tx rate constantly. - * - */ - - /* - * 11Mbps or 36Mbps - * Check more times in these rate(key rates). - */ - if (priv->CurrentOperaRate == 22 || priv->CurrentOperaRate == 72) - TryUpTh += 9; - /* - * Let these rates down more difficult. - */ - if (MgntIsCckRate(priv->CurrentOperaRate) || priv->CurrentOperaRate == 36) - TryDownTh += 1; - - /* 1 Adjust Rate. */ - if (priv->bTryuping == true) { - /* 2 For Test Upgrading mechanism - * Note: - * Sometimes the throughput is upon on the capability between the AP and NIC, - * thus the low data rate does not improve the performance. - * We randomly upgrade the data rate and check if the retry rate is improved. - */ - - /* Upgrading rate did not improve the retry rate, fallback to the original rate. */ - if ((CurrRetryRate > 25) && TxThroughput < priv->LastTxThroughput) { - /*Not necessary raising rate, fall back rate. */ - bTryDown = true; - } else { - priv->bTryuping = false; - } - } else if (CurrSignalStrength > -47 && (CurrRetryRate < 50)) { - /* - * 2For High Power - * - * Return to highest data rate, if signal strength is good enough. - * SignalStrength threshold(-50dbm) is for RTL8186. - * Revise SignalStrength threshold to -51dbm. - */ - /* Also need to check retry rate for safety, by Bruce, 2007-06-05. */ - if (priv->CurrentOperaRate != priv->ieee80211->current_network.HighestOperaRate) { - bTryUp = true; - /* Upgrade Tx Rate directly. */ - priv->TryupingCount += TryUpTh; - } - - } else if (CurrTxokCnt > 9 && CurrTxokCnt < 100 && CurrRetryRate >= 600) { - /* - *2 For Serious Retry - * - * Traffic is not busy but our Tx retry is serious. - */ - bTryDown = true; - /* Let Rate Mechanism to degrade tx rate directly. */ - priv->TryDownCountLowData += TryDownTh; - } else if (priv->CurrentOperaRate == 108) { - /* 2For 54Mbps */ - /* Air Link */ - if ((CurrRetryRate > 26) && (priv->LastRetryRate > 25)) { - bTryDown = true; - } - /* Cable Link */ - else if ((CurrRetryRate > 17) && (priv->LastRetryRate > 16) && (CurrSignalStrength > -72)) { - bTryDown = true; - } - - if (bTryDown && (CurrSignalStrength < -75)) /* cable link */ - priv->TryDownCountLowData += TryDownTh; - } else if (priv->CurrentOperaRate == 96) { - /* 2For 48Mbps */ - /* Air Link */ - if (((CurrRetryRate > 48) && (priv->LastRetryRate > 47))) { - bTryDown = true; - } else if (((CurrRetryRate > 21) && (priv->LastRetryRate > 20)) && (CurrSignalStrength > -74)) { /* Cable Link */ - /* Down to rate 36Mbps. */ - bTryDown = true; - } else if ((CurrRetryRate > (priv->LastRetryRate + 50)) && (priv->FailTxRateCount > 2)) { - bTryDown = true; - priv->TryDownCountLowData += TryDownTh; - } else if ((CurrRetryRate < 8) && (priv->LastRetryRate < 8)) { /* TO DO: need to consider (RSSI) */ - bTryUp = true; - } - - if (bTryDown && (CurrSignalStrength < -75)) { - priv->TryDownCountLowData += TryDownTh; - } - } else if (priv->CurrentOperaRate == 72) { - /* 2For 36Mbps */ - if ((CurrRetryRate > 43) && (priv->LastRetryRate > 41)) { - /* Down to rate 24Mbps. */ - bTryDown = true; - } else if ((CurrRetryRate > (priv->LastRetryRate + 50)) && (priv->FailTxRateCount > 2)) { - bTryDown = true; - priv->TryDownCountLowData += TryDownTh; - } else if ((CurrRetryRate < 15) && (priv->LastRetryRate < 16)) { /* TO DO: need to consider (RSSI) */ - bTryUp = true; - } - - if (bTryDown && (CurrSignalStrength < -80)) - priv->TryDownCountLowData += TryDownTh; - - } else if (priv->CurrentOperaRate == 48) { - /* 2For 24Mbps */ - /* Air Link */ - if (((CurrRetryRate > 63) && (priv->LastRetryRate > 62))) { - bTryDown = true; - } else if (((CurrRetryRate > 33) && (priv->LastRetryRate > 32)) && (CurrSignalStrength > -82)) { /* Cable Link */ - bTryDown = true; - } else if ((CurrRetryRate > (priv->LastRetryRate + 50)) && (priv->FailTxRateCount > 2)) { - bTryDown = true; - priv->TryDownCountLowData += TryDownTh; - } else if ((CurrRetryRate < 20) && (priv->LastRetryRate < 21)) { /* TO DO: need to consider (RSSI) */ - bTryUp = true; - } - - if (bTryDown && (CurrSignalStrength < -82)) - priv->TryDownCountLowData += TryDownTh; - - } else if (priv->CurrentOperaRate == 36) { - if (((CurrRetryRate > 85) && (priv->LastRetryRate > 86))) { - bTryDown = true; - } else if ((CurrRetryRate > (priv->LastRetryRate + 50)) && (priv->FailTxRateCount > 2)) { - bTryDown = true; - priv->TryDownCountLowData += TryDownTh; - } else if ((CurrRetryRate < 22) && (priv->LastRetryRate < 23)) { /* TO DO: need to consider (RSSI) */ - bTryUp = true; - } - } else if (priv->CurrentOperaRate == 22) { - /* 2For 11Mbps */ - if (CurrRetryRate > 95) { - bTryDown = true; - } else if ((CurrRetryRate < 29) && (priv->LastRetryRate < 30)) { /*TO DO: need to consider (RSSI) */ - bTryUp = true; - } - } else if (priv->CurrentOperaRate == 11) { - /* 2For 5.5Mbps */ - if (CurrRetryRate > 149) { - bTryDown = true; - } else if ((CurrRetryRate < 60) && (priv->LastRetryRate < 65)) { - bTryUp = true; - } - } else if (priv->CurrentOperaRate == 4) { - /* 2For 2 Mbps */ - if ((CurrRetryRate > 99) && (priv->LastRetryRate > 99)) { - bTryDown = true; - } else if ((CurrRetryRate < 65) && (priv->LastRetryRate < 70)) { - bTryUp = true; - } - } else if (priv->CurrentOperaRate == 2) { - /* 2For 1 Mbps */ - if ((CurrRetryRate < 70) && (priv->LastRetryRate < 75)) { - bTryUp = true; - } - } - - if (bTryUp && bTryDown) - printk("StaRateAdaptive87B(): Tx Rate tried upping and downing simultaneously!\n"); - - /* 1 Test Upgrading Tx Rate - * Sometimes the cause of the low throughput (high retry rate) is the compatibility between the AP and NIC. - * To test if the upper rate may cause lower retry rate, this mechanism randomly occurs to test upgrading tx rate. - */ - if (!bTryUp && !bTryDown && (priv->TryupingCount == 0) && (priv->TryDownCountLowData == 0) - && priv->CurrentOperaRate != priv->ieee80211->current_network.HighestOperaRate && priv->FailTxRateCount < 2) { - if (jiffies % (CurrRetryRate + 101) == 0) { - bTryUp = true; - priv->bTryuping = true; - } - } - - /* 1 Rate Mechanism */ - if (bTryUp) { - priv->TryupingCount++; - priv->TryDownCountLowData = 0; - - /* - * Check more times if we need to upgrade indeed. - * Because the largest value of pHalData->TryupingCount is 0xFFFF and - * the largest value of pHalData->FailTxRateCount is 0x14, - * this condition will be satisfied at most every 2 min. - */ - - if ((priv->TryupingCount > (TryUpTh + priv->FailTxRateCount * priv->FailTxRateCount)) || - (CurrSignalStrength > priv->LastFailTxRateSS) || priv->bTryuping) { - priv->TryupingCount = 0; - /* - * When transferring from CCK to OFDM, DIG is an important issue. - */ - if (priv->CurrentOperaRate == 22) - bUpdateInitialGain = true; - - /* - * The difference in throughput between 48Mbps and 36Mbps is 8M. - * So, we must be careful in this rate scale. Isaiah 2008-02-15. - */ - if (((priv->CurrentOperaRate == 72) || (priv->CurrentOperaRate == 48) || (priv->CurrentOperaRate == 36)) && - (priv->FailTxRateCount > 2)) - priv->RateAdaptivePeriod = (RATE_ADAPTIVE_TIMER_PERIOD / 2); - - /* (1)To avoid upgrade frequently to the fail tx rate, add the FailTxRateCount into the threshold. */ - /* (2)If the signal strength is increased, it may be able to upgrade. */ - - priv->CurrentOperaRate = GetUpgradeTxRate(dev, priv->CurrentOperaRate); - - if (priv->CurrentOperaRate == 36) { - priv->bUpdateARFR = true; - write_nic_word(dev, ARFR, 0x0F8F); /* bypass 12/9/6 */ - } else if (priv->bUpdateARFR) { - priv->bUpdateARFR = false; - write_nic_word(dev, ARFR, 0x0FFF); /* set 1M ~ 54Mbps. */ - } - - /* Update Fail Tx rate and count. */ - if (priv->LastFailTxRate != priv->CurrentOperaRate) { - priv->LastFailTxRate = priv->CurrentOperaRate; - priv->FailTxRateCount = 0; - priv->LastFailTxRateSS = -200; /* Set lowest power. */ - } - } - } else { - if (priv->TryupingCount > 0) - priv->TryupingCount--; - } - - if (bTryDown) { - priv->TryDownCountLowData++; - priv->TryupingCount = 0; - - /* Check if Tx rate can be degraded or Test trying upgrading should fallback. */ - if (priv->TryDownCountLowData > TryDownTh || priv->bTryuping) { - priv->TryDownCountLowData = 0; - priv->bTryuping = false; - /* Update fail information. */ - if (priv->LastFailTxRate == priv->CurrentOperaRate) { - priv->FailTxRateCount++; - /* Record the Tx fail rate signal strength. */ - if (CurrSignalStrength > priv->LastFailTxRateSS) - priv->LastFailTxRateSS = CurrSignalStrength; - } else { - priv->LastFailTxRate = priv->CurrentOperaRate; - priv->FailTxRateCount = 1; - priv->LastFailTxRateSS = CurrSignalStrength; - } - priv->CurrentOperaRate = GetDegradeTxRate(dev, priv->CurrentOperaRate); - - /* Reduce chariot training time at weak signal strength situation. SD3 ED demand. */ - if ((CurrSignalStrength < -80) && (priv->CurrentOperaRate > 72)) { - priv->CurrentOperaRate = 72; - } - - if (priv->CurrentOperaRate == 36) { - priv->bUpdateARFR = true; - write_nic_word(dev, ARFR, 0x0F8F); /* bypass 12/9/6 */ - } else if (priv->bUpdateARFR) { - priv->bUpdateARFR = false; - write_nic_word(dev, ARFR, 0x0FFF); /* set 1M ~ 54Mbps. */ - } - - /* - * When it is CCK rate, it may need to update initial gain to receive lower power packets. - */ - if (MgntIsCckRate(priv->CurrentOperaRate)) { - bUpdateInitialGain = true; - } - } - } else { - if (priv->TryDownCountLowData > 0) - priv->TryDownCountLowData--; - } - - /* - * Keep the Tx fail rate count to equal to 0x15 at most. - * Reduce the fail count at least to 10 sec if tx rate is tending stable. - */ - if (priv->FailTxRateCount >= 0x15 || - (!bTryUp && !bTryDown && priv->TryDownCountLowData == 0 && priv->TryupingCount && priv->FailTxRateCount > 0x6)) { - priv->FailTxRateCount--; - } - - - OfdmTxPwrIdx = priv->chtxpwr_ofdm[priv->ieee80211->current_network.channel]; - CckTxPwrIdx = priv->chtxpwr[priv->ieee80211->current_network.channel]; - - /* Mac0x9e increase 2 level in 36M~18M situation */ - if ((priv->CurrentOperaRate < 96) && (priv->CurrentOperaRate > 22)) { - u1bCck = read_nic_byte(dev, CCK_TXAGC); - u1bOfdm = read_nic_byte(dev, OFDM_TXAGC); - - /* case 1: Never enter High power */ - if (u1bCck == CckTxPwrIdx) { - if (u1bOfdm != (OfdmTxPwrIdx + 2)) { - priv->bEnhanceTxPwr = true; - u1bOfdm = ((u1bOfdm + 2) > 35) ? 35 : (u1bOfdm + 2); - write_nic_byte(dev, OFDM_TXAGC, u1bOfdm); - } - } else if (u1bCck < CckTxPwrIdx) { - /* case 2: enter high power */ - if (!priv->bEnhanceTxPwr) { - priv->bEnhanceTxPwr = true; - u1bOfdm = ((u1bOfdm + 2) > 35) ? 35 : (u1bOfdm + 2); - write_nic_byte(dev, OFDM_TXAGC, u1bOfdm); - } - } - } else if (priv->bEnhanceTxPwr) { /* 54/48/11/5.5/2/1 */ - u1bCck = read_nic_byte(dev, CCK_TXAGC); - u1bOfdm = read_nic_byte(dev, OFDM_TXAGC); - - /* case 1: Never enter High power */ - if (u1bCck == CckTxPwrIdx) { - priv->bEnhanceTxPwr = false; - write_nic_byte(dev, OFDM_TXAGC, OfdmTxPwrIdx); - } - /* case 2: enter high power */ - else if (u1bCck < CckTxPwrIdx) { - priv->bEnhanceTxPwr = false; - u1bOfdm = ((u1bOfdm - 2) > 0) ? (u1bOfdm - 2) : 0; - write_nic_byte(dev, OFDM_TXAGC, u1bOfdm); - } - } - - /* - * We need update initial gain when we set tx rate "from OFDM to CCK" or - * "from CCK to OFDM". - */ -SetInitialGain: - if (bUpdateInitialGain) { - if (MgntIsCckRate(priv->CurrentOperaRate)) { /* CCK */ - if (priv->InitialGain > priv->RegBModeGainStage) { - priv->InitialGainBackUp = priv->InitialGain; - - if (CurrSignalStrength < -85) /* Low power, OFDM [0x17] = 26. */ - /* SD3 SYs suggest that CurrSignalStrength < -65, ofdm 0x17=26. */ - priv->InitialGain = priv->RegBModeGainStage; - - else if (priv->InitialGain > priv->RegBModeGainStage + 1) - priv->InitialGain -= 2; - - else - priv->InitialGain--; - - printk("StaRateAdaptive87SE(): update init_gain to index %d for date rate %d\n", priv->InitialGain, priv->CurrentOperaRate); - UpdateInitialGain(dev); - } - } else { /* OFDM */ - if (priv->InitialGain < 4) { - priv->InitialGainBackUp = priv->InitialGain; - - priv->InitialGain++; - printk("StaRateAdaptive87SE(): update init_gain to index %d for date rate %d\n", priv->InitialGain, priv->CurrentOperaRate); - UpdateInitialGain(dev); - } - } - } - - /* Record the related info */ - priv->LastRetryRate = CurrRetryRate; - priv->LastTxThroughput = TxThroughput; - priv->ieee80211->rate = priv->CurrentOperaRate * 5; -} - -void rtl8180_rate_adapter(struct work_struct *work) -{ - struct delayed_work *dwork = to_delayed_work(work); - struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, rate_adapter_wq); - struct net_device *dev = ieee->dev; - StaRateAdaptive87SE(dev); -} -void timer_rate_adaptive(unsigned long data) -{ - struct r8180_priv *priv = ieee80211_priv((struct net_device *)data); - if (!priv->up) { - return; - } - if ((priv->ieee80211->iw_mode != IW_MODE_MASTER) - && (priv->ieee80211->state == IEEE80211_LINKED) && - (priv->ForcedDataRate == 0)) { - queue_work(priv->ieee80211->wq, (void *)&priv->ieee80211->rate_adapter_wq); - } - priv->rateadapter_timer.expires = jiffies + MSECS(priv->RateAdaptivePeriod); - add_timer(&priv->rateadapter_timer); -} - -void SwAntennaDiversityRxOk8185(struct net_device *dev, u8 SignalStrength) -{ - struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); - - priv->AdRxOkCnt++; - - if (priv->AdRxSignalStrength != -1) { - priv->AdRxSignalStrength = ((priv->AdRxSignalStrength * 7) + (SignalStrength * 3)) / 10; - } else { /* Initialization case. */ - priv->AdRxSignalStrength = SignalStrength; - } - - if (priv->LastRxPktAntenna) /* Main antenna. */ - priv->AdMainAntennaRxOkCnt++; - else /* Aux antenna. */ - priv->AdAuxAntennaRxOkCnt++; -} - /* Change Antenna Switch. */ -bool SetAntenna8185(struct net_device *dev, u8 u1bAntennaIndex) -{ - struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); - bool bAntennaSwitched = false; - - switch (u1bAntennaIndex) { - case 0: - /* Mac register, main antenna */ - write_nic_byte(dev, ANTSEL, 0x03); - /* base band */ - write_phy_cck(dev, 0x11, 0x9b); /* Config CCK RX antenna. */ - write_phy_ofdm(dev, 0x0d, 0x5c); /* Config OFDM RX antenna. */ - - bAntennaSwitched = true; - break; - - case 1: - /* Mac register, aux antenna */ - write_nic_byte(dev, ANTSEL, 0x00); - /* base band */ - write_phy_cck(dev, 0x11, 0xbb); /* Config CCK RX antenna. */ - write_phy_ofdm(dev, 0x0d, 0x54); /* Config OFDM RX antenna. */ - - bAntennaSwitched = true; - - break; - - default: - printk("SetAntenna8185: unknown u1bAntennaIndex(%d)\n", u1bAntennaIndex); - break; - } - - if (bAntennaSwitched) - priv->CurrAntennaIndex = u1bAntennaIndex; - - return bAntennaSwitched; -} - /* Toggle Antenna switch. */ -bool SwitchAntenna(struct net_device *dev) -{ - struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); - - bool bResult; - - if (priv->CurrAntennaIndex == 0) { - bResult = SetAntenna8185(dev, 1); - } else { - bResult = SetAntenna8185(dev, 0); - } - - return bResult; -} -/* - * Engine of SW Antenna Diversity mechanism. - * Since 8187 has no Tx part information, - * this implementation is only dependend on Rx part information. - */ -void SwAntennaDiversity(struct net_device *dev) -{ - struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); - bool bSwCheckSS = false; - if (bSwCheckSS) { - priv->AdTickCount++; - - printk("(1) AdTickCount: %d, AdCheckPeriod: %d\n", - priv->AdTickCount, priv->AdCheckPeriod); - printk("(2) AdRxSignalStrength: %ld, AdRxSsThreshold: %ld\n", - priv->AdRxSignalStrength, priv->AdRxSsThreshold); - } - - /* Case 1. No Link. */ - if (priv->ieee80211->state != IEEE80211_LINKED) { - priv->bAdSwitchedChecking = false; - /* I switch antenna here to prevent any one of antenna is broken before link established, 2006.04.18, by rcnjko.. */ - SwitchAntenna(dev); - - /* Case 2. Linked but no packet receive.d */ - } else if (priv->AdRxOkCnt == 0) { - priv->bAdSwitchedChecking = false; - SwitchAntenna(dev); - - /* Case 3. Evaluate last antenna switch action and undo it if necessary. */ - } else if (priv->bAdSwitchedChecking == true) { - priv->bAdSwitchedChecking = false; - - /* Adjust Rx signal strength threshold. */ - priv->AdRxSsThreshold = (priv->AdRxSignalStrength + priv->AdRxSsBeforeSwitched) / 2; - - priv->AdRxSsThreshold = (priv->AdRxSsThreshold > priv->AdMaxRxSsThreshold) ? - priv->AdMaxRxSsThreshold : priv->AdRxSsThreshold; - if (priv->AdRxSignalStrength < priv->AdRxSsBeforeSwitched) { - /* Rx signal strength is not improved after we swtiched antenna. => Swich back. */ - /* Increase Antenna Diversity checking period due to bad decision. */ - priv->AdCheckPeriod *= 2; - /* Increase Antenna Diversity checking period. */ - if (priv->AdCheckPeriod > priv->AdMaxCheckPeriod) - priv->AdCheckPeriod = priv->AdMaxCheckPeriod; - - /* Wrong decision => switch back. */ - SwitchAntenna(dev); - } else { - /* Rx Signal Strength is improved. */ - - /* Reset Antenna Diversity checking period to its min value. */ - priv->AdCheckPeriod = priv->AdMinCheckPeriod; - } - - } - /* Case 4. Evaluate if we shall switch antenna now. */ - /* Cause Table Speed is very fast in TRC Dell Lab, we check it every time. */ - else { - priv->AdTickCount = 0; - - /* - * We evaluate RxOk counts for each antenna first and than - * evaluate signal strength. - * The following operation can overcome the disability of CCA on both two antennas - * When signal strength was extremely low or high. - * 2008.01.30. - */ - - /* - * Evaluate RxOk count from each antenna if we shall switch default antenna now. - */ - if ((priv->AdMainAntennaRxOkCnt < priv->AdAuxAntennaRxOkCnt) - && (priv->CurrAntennaIndex == 0)) { - /* We set Main antenna as default but RxOk count was less than Aux ones. */ - - /* Switch to Aux antenna. */ - SwitchAntenna(dev); - priv->bHWAdSwitched = true; - } else if ((priv->AdAuxAntennaRxOkCnt < priv->AdMainAntennaRxOkCnt) - && (priv->CurrAntennaIndex == 1)) { - /* We set Aux antenna as default but RxOk count was less than Main ones. */ - - /* Switch to Main antenna. */ - SwitchAntenna(dev); - priv->bHWAdSwitched = true; - } else { - /* Default antenna is better. */ - - /* Still need to check current signal strength. */ - priv->bHWAdSwitched = false; - } - /* - * We evaluate Rx signal strength ONLY when default antenna - * didn't change by HW evaluation. - * 2008.02.27. - * - * [TRC Dell Lab] SignalStrength is inaccuracy. Isaiah 2008-03-05 - * For example, Throughput of aux is better than main antenna(about 10M v.s 2M), - * but AdRxSignalStrength is less than main. - * Our guess is that main antenna have lower throughput and get many change - * to receive more CCK packets(ex.Beacon) which have stronger SignalStrength. - */ - if ((!priv->bHWAdSwitched) && (bSwCheckSS)) { - /* Evaluate Rx signal strength if we shall switch antenna now. */ - if (priv->AdRxSignalStrength < priv->AdRxSsThreshold) { - /* Rx signal strength is weak => Switch Antenna. */ - priv->AdRxSsBeforeSwitched = priv->AdRxSignalStrength; - priv->bAdSwitchedChecking = true; - - SwitchAntenna(dev); - } else { - /* Rx signal strength is OK. */ - priv->bAdSwitchedChecking = false; - /* Increase Rx signal strength threshold if necessary. */ - if ((priv->AdRxSignalStrength > (priv->AdRxSsThreshold + 10)) && /* Signal is much stronger than current threshold */ - priv->AdRxSsThreshold <= priv->AdMaxRxSsThreshold) { /* Current threhold is not yet reach upper limit. */ - - priv->AdRxSsThreshold = (priv->AdRxSsThreshold + priv->AdRxSignalStrength) / 2; - priv->AdRxSsThreshold = (priv->AdRxSsThreshold > priv->AdMaxRxSsThreshold) ? - priv->AdMaxRxSsThreshold : priv->AdRxSsThreshold;/* +by amy 080312 */ - } - - /* Reduce Antenna Diversity checking period if possible. */ - if (priv->AdCheckPeriod > priv->AdMinCheckPeriod) - priv->AdCheckPeriod /= 2; - } - } - } - /* Reset antenna diversity Rx related statistics. */ - priv->AdRxOkCnt = 0; - priv->AdMainAntennaRxOkCnt = 0; - priv->AdAuxAntennaRxOkCnt = 0; -} - - /* Return TRUE if we shall perform Tx Power Tracking Mechanism, FALSE otherwise. */ -bool CheckTxPwrTracking(struct net_device *dev) -{ - struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); - - if (!priv->bTxPowerTrack) - return false; - - /* if 87SE is in High Power , don't do Tx Power Tracking. asked by SD3 ED. 2008-08-08 Isaiah */ - if (priv->bToUpdateTxPwr) - return false; - - return true; -} - - - /* Timer callback function of SW Antenna Diversity. */ -void SwAntennaDiversityTimerCallback(struct net_device *dev) -{ - struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); - enum rt_rf_power_state rtState; - - /* We do NOT need to switch antenna while RF is off. */ - rtState = priv->eRFPowerState; - do { - if (rtState == RF_OFF) { - break; - } else if (rtState == RF_SLEEP) { - /* Don't access BB/RF under Disable PLL situation. */ - break; - } - SwAntennaDiversity(dev); - - } while (false); - - if (priv->up) { - priv->SwAntennaDiversityTimer.expires = jiffies + MSECS(ANTENNA_DIVERSITY_TIMER_PERIOD); - add_timer(&priv->SwAntennaDiversityTimer); - } -} - diff --git a/drivers/staging/rtl8187se/r8180_dm.h b/drivers/staging/rtl8187se/r8180_dm.h deleted file mode 100644 index cb4046f346e..00000000000 --- a/drivers/staging/rtl8187se/r8180_dm.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef R8180_DM_H -#define R8180_DM_H - -#include "r8180.h" -/* #include "r8180_hw.h" */ -/* #include "r8180_93cx6.h" */ -void SwAntennaDiversityRxOk8185(struct net_device *dev, u8 SignalStrength); -bool SetAntenna8185(struct net_device *dev, u8 u1bAntennaIndex); -bool SwitchAntenna(struct net_device *dev); -void SwAntennaDiversity(struct net_device *dev); -void SwAntennaDiversityTimerCallback(struct net_device *dev); -bool CheckDig(struct net_device *dev); -bool CheckHighPower(struct net_device *dev); -void rtl8180_hw_dig_wq(struct work_struct *work); -void rtl8180_tx_pw_wq(struct work_struct *work); -void rtl8180_rate_adapter(struct work_struct *work); -void TxPwrTracking87SE(struct net_device *dev); -bool CheckTxPwrTracking(struct net_device *dev); -void rtl8180_rate_adapter(struct work_struct *work); -void timer_rate_adaptive(unsigned long data); - - -#endif diff --git a/drivers/staging/rtl8187se/r8180_hw.h b/drivers/staging/rtl8187se/r8180_hw.h deleted file mode 100644 index e59d74f8ecf..00000000000 --- a/drivers/staging/rtl8187se/r8180_hw.h +++ /dev/null @@ -1,588 +0,0 @@ -/* - This is part of rtl8180 OpenSource driver. - Copyright (C) Andrea Merello 2004-2005 - Released under the terms of GPL (General Public Licence) - - Parts of this driver are based on the GPL part of the - official Realtek driver. - Parts of this driver are based on the rtl8180 driver skeleton - from Patric Schenke & Andres Salomon. - Parts of this driver are based on the Intel Pro Wireless - 2100 GPL driver. - - We want to tanks the Authors of those projects - and the Ndiswrapper project Authors. -*/ - -/* Mariusz Matuszek added full registers definition with Realtek's name */ - -/* this file contains register definitions for the rtl8180 MAC controller */ -#ifndef R8180_HW -#define R8180_HW - - -#define BIT0 0x00000001 -#define BIT1 0x00000002 -#define BIT2 0x00000004 -#define BIT3 0x00000008 -#define BIT4 0x00000010 -#define BIT5 0x00000020 -#define BIT6 0x00000040 -#define BIT7 0x00000080 -#define BIT9 0x00000200 -#define BIT11 0x00000800 -#define BIT13 0x00002000 -#define BIT15 0x00008000 -#define BIT20 0x00100000 -#define BIT21 0x00200000 -#define BIT22 0x00400000 -#define BIT23 0x00800000 -#define BIT24 0x01000000 -#define BIT25 0x02000000 -#define BIT26 0x04000000 -#define BIT27 0x08000000 -#define BIT28 0x10000000 -#define BIT29 0x20000000 -#define BIT30 0x40000000 -#define BIT31 0x80000000 - -#define MAX_SLEEP_TIME (10000) -#define MIN_SLEEP_TIME (50) - -#define BB_HOST_BANG_EN (1<<2) -#define BB_HOST_BANG_CLK (1<<1) - -#define MAC0 0 -#define MAC4 4 - -#define CMD 0x37 -#define CMD_RST_SHIFT 4 -#define CMD_RX_ENABLE_SHIFT 3 -#define CMD_TX_ENABLE_SHIFT 2 - -#define EPROM_CMD 0x50 -#define EPROM_CMD_RESERVED_MASK ((1<<5)|(1<<4)) -#define EPROM_CMD_OPERATING_MODE_SHIFT 6 -#define EPROM_CMD_OPERATING_MODE_MASK ((1<<7)|(1<<6)) -#define EPROM_CMD_CONFIG 0x3 -#define EPROM_CMD_NORMAL 0 -#define EPROM_CMD_LOAD 1 -#define EPROM_CMD_PROGRAM 2 -#define EPROM_CS_SHIFT 3 -#define EPROM_CK_SHIFT 2 -#define EPROM_W_SHIFT 1 -#define EPROM_R_SHIFT 0 -#define CONFIG2_DMA_POLLING_MODE_SHIFT 3 - -#define INTA_TXOVERFLOW (1<<15) -#define INTA_TIMEOUT (1<<14) -#define INTA_HIPRIORITYDESCERR (1<<9) -#define INTA_HIPRIORITYDESCOK (1<<8) -#define INTA_NORMPRIORITYDESCERR (1<<7) -#define INTA_NORMPRIORITYDESCOK (1<<6) -#define INTA_RXOVERFLOW (1<<5) -#define INTA_RXDESCERR (1<<4) -#define INTA_LOWPRIORITYDESCERR (1<<3) -#define INTA_LOWPRIORITYDESCOK (1<<2) -#define INTA_RXOK (1) -#define INTA_MASK 0x3c - -#define RXRING_ADDR 0xe4 /* page 0 */ -#define PGSELECT 0x5e -#define PGSELECT_PG_SHIFT 0 -#define RX_CONF 0x44 -#define MAC_FILTER_MASK ((1<<0) | (1<<1) | (1<<2) | (1<<3) | (1<<5) | \ -(1<<12) | (1<<18) | (1<<19) | (1<<20) | (1<<21) | (1<<22) | (1<<23)) -#define RX_CHECK_BSSID_SHIFT 23 -#define ACCEPT_PWR_FRAME_SHIFT 22 -#define ACCEPT_MNG_FRAME_SHIFT 20 -#define ACCEPT_CTL_FRAME_SHIFT 19 -#define ACCEPT_DATA_FRAME_SHIFT 18 -#define ACCEPT_ICVERR_FRAME_SHIFT 12 -#define ACCEPT_CRCERR_FRAME_SHIFT 5 -#define ACCEPT_BCAST_FRAME_SHIFT 3 -#define ACCEPT_MCAST_FRAME_SHIFT 2 -#define ACCEPT_ALLMAC_FRAME_SHIFT 0 -#define ACCEPT_NICMAC_FRAME_SHIFT 1 - -#define RX_FIFO_THRESHOLD_MASK ((1<<13) | (1<<14) | (1<<15)) -#define RX_FIFO_THRESHOLD_SHIFT 13 -#define RX_FIFO_THRESHOLD_NONE 7 -#define RX_AUTORESETPHY_SHIFT 28 - -#define TX_CONF 0x40 -#define TX_CONF_HEADER_AUTOICREMENT_SHIFT 30 -#define TX_LOOPBACK_SHIFT 17 -#define TX_LOOPBACK_NONE 0 -#define TX_LOOPBACK_CONTINUE 3 -#define TX_LOOPBACK_MASK ((1<<17)|(1<<18)) -#define TX_DPRETRY_SHIFT 0 -#define R8180_MAX_RETRY 255 -#define TX_RTSRETRY_SHIFT 8 -#define TX_NOICV_SHIFT 19 -#define TX_NOCRC_SHIFT 16 -#define TX_DMA_POLLING 0xd9 -#define TX_DMA_POLLING_BEACON_SHIFT 7 -#define TX_DMA_POLLING_HIPRIORITY_SHIFT 6 -#define TX_DMA_POLLING_NORMPRIORITY_SHIFT 5 -#define TX_DMA_POLLING_LOWPRIORITY_SHIFT 4 -#define TX_MANAGEPRIORITY_RING_ADDR 0x0C -#define TX_BKPRIORITY_RING_ADDR 0x10 -#define TX_BEPRIORITY_RING_ADDR 0x14 -#define TX_VIPRIORITY_RING_ADDR 0x20 -#define TX_VOPRIORITY_RING_ADDR 0x24 -#define TX_HIGHPRIORITY_RING_ADDR 0x28 -#define MAX_RX_DMA_MASK ((1<<8) | (1<<9) | (1<<10)) -#define MAX_RX_DMA_2048 7 -#define MAX_RX_DMA_1024 6 -#define MAX_RX_DMA_SHIFT 10 -#define INT_TIMEOUT 0x48 -#define CONFIG3_CLKRUN_SHIFT 2 -#define CONFIG3_ANAPARAM_W_SHIFT 6 -#define ANAPARAM 0x54 -#define BEACON_INTERVAL 0x70 -#define BEACON_INTERVAL_MASK ((1<<0)|(1<<1)|(1<<2)|(1<<3)|(1<<4)|(1<<5)| \ -(1<<6)|(1<<7)|(1<<8)|(1<<9)) -#define ATIM_MASK ((1<<0)|(1<<1)|(1<<2)|(1<<3)|(1<<4)|(1<<5)|(1<<6)|(1<<7)| \ -(1<<8)|(1<<9)) -#define ATIM 0x72 -#define EPROM_CS_SHIFT 3 -#define EPROM_CK_SHIFT 2 -#define PHY_ADR 0x7c -#define SECURITY 0x5f /* 1209 this is sth wrong */ -#define SECURITY_WEP_TX_ENABLE_SHIFT 1 -#define SECURITY_WEP_RX_ENABLE_SHIFT 0 -#define SECURITY_ENCRYP_104 1 -#define SECURITY_ENCRYP_SHIFT 4 -#define SECURITY_ENCRYP_MASK ((1<<4)|(1<<5)) -#define KEY0 0x90 /* 1209 this is sth wrong */ -#define CONFIG2_ANTENNA_SHIFT 6 -#define TX_BEACON_RING_ADDR 0x4c -#define CONFIG0_WEP40_SHIFT 7 -#define CONFIG0_WEP104_SHIFT 6 -#define AGCRESET_SHIFT 5 - - - -/* - * Operational registers offsets in PCI (I/O) space. - * RealTek names are used. - */ - -#define TSFTR 0x0018 - -#define TLPDA 0x0020 - -#define BSSID 0x002E - -#define CR 0x0037 - -#define RF_SW_CONFIG 0x8 /* store data which is transmitted to RF for driver */ -#define RF_SW_CFG_SI BIT1 -#define EIFS 0x2D /* Extended InterFrame Space Timer, in unit of 4 us. */ - -#define BRSR 0x34 /* Basic rate set */ - -#define IMR 0x006C -#define ISR 0x003C - -#define TCR 0x0040 - -#define RCR 0x0044 - -#define TimerInt 0x0048 - -#define CR9346 0x0050 - -#define CONFIG0 0x0051 -#define CONFIG2 0x0053 - -#define MSR 0x0058 - -#define CONFIG3 0x0059 -#define CONFIG4 0x005A - /* SD3 szuyitasi: Mac0x57= CC -> B0 Mac0x60= D1 -> C6 */ - /* Mac0x60 = 0x000004C6 power save parameters */ - #define ANAPARM_ASIC_ON 0xB0054D00 - #define ANAPARM2_ASIC_ON 0x000004C6 - - #define ANAPARM_ON ANAPARM_ASIC_ON - #define ANAPARM2_ON ANAPARM2_ASIC_ON - -#define TESTR 0x005B - -#define PSR 0x005E - -#define BcnItv 0x0070 - -#define AtimWnd 0x0072 - -#define BintrItv 0x0074 - -#define PhyAddr 0x007C -#define PhyDataR 0x007E - -/* following are for rtl8185 */ -#define RFPinsOutput 0x80 -#define RFPinsEnable 0x82 -#define RF_TIMING 0x8c -#define RFPinsSelect 0x84 -#define ANAPARAM2 0x60 -#define RF_PARA 0x88 -#define RFPinsInput 0x86 -#define GP_ENABLE 0x90 -#define GPIO 0x91 -#define SW_CONTROL_GPIO 0x400 -#define TX_ANTENNA 0x9f -#define TX_GAIN_OFDM 0x9e -#define TX_GAIN_CCK 0x9d -#define WPA_CONFIG 0xb0 -#define TX_AGC_CTL 0x9c -#define TX_AGC_CTL_PERPACKET_GAIN_SHIFT 0 -#define TX_AGC_CTL_PERPACKET_ANTSEL_SHIFT 1 -#define TX_AGC_CTL_FEEDBACK_ANT 2 -#define RESP_RATE 0x34 -#define SIFS 0xb4 -#define DIFS 0xb5 - -#define SLOT 0xb6 -#define CW_CONF 0xbc -#define CW_CONF_PERPACKET_RETRY_SHIFT 1 -#define CW_CONF_PERPACKET_CW_SHIFT 0 -#define CW_VAL 0xbd -#define MAX_RESP_RATE_SHIFT 4 -#define MIN_RESP_RATE_SHIFT 0 -#define RATE_FALLBACK 0xbe - -#define CONFIG5 0x00D8 - -#define PHYPR 0xDA /* 0xDA - 0x0B PHY Parameter Register. */ - -#define FEMR 0x1D4 /* Function Event Mask register */ - -#define FFER 0x00FC -#define FFER_END 0x00FF - - - -/* - * Bitmasks for specific register functions. - * Names are derived from the register name and function name. - * - * _[] - * - * this leads to some awkward names... - */ - -#define BRSR_BPLCP ((1 << 8)) -#define BRSR_MBR ((1 << 1)|(1 << 0)) -#define BRSR_MBR_8185 ((1 << 11)|(1 << 10)|(1 << 9)|(1 << 8)|(1 << 7)|(1 << 6)|(1 << 5)|(1 << 4)|(1 << 3)|(1 << 2)|(1 << 1)|(1 << 0)) -#define BRSR_MBR0 ((1 << 0)) -#define BRSR_MBR1 ((1 << 1)) - -#define CR_RST ((1 << 4)) -#define CR_RE ((1 << 3)) -#define CR_TE ((1 << 2)) -#define CR_MulRW ((1 << 0)) - -#define IMR_Dot11hInt ((1 << 25)) /*802.11h Measurement Interrupt */ -#define IMR_BcnDmaInt ((1 << 24)) /*Beacon DMA Interrupt */ /*What differenct between BcnDmaInt and BcnInt??? */ -#define IMR_WakeInt ((1 << 23)) /*Wake Up Interrupt */ -#define IMR_TXFOVW ((1 << 22)) /*Tx FIFO Overflow Interrupt */ -#define IMR_TimeOut1 ((1 << 21)) /*Time Out Interrupt 1 */ -#define IMR_BcnInt ((1 << 20)) /*Beacon Time out Interrupt */ -#define IMR_ATIMInt ((1 << 19)) /*ATIM Time Out Interrupt */ -#define IMR_TBDER ((1 << 18)) /*Tx Beacon Descriptor Error Interrupt */ -#define IMR_TBDOK ((1 << 17)) /*Tx Beacon Descriptor OK Interrupt */ -#define IMR_THPDER ((1 << 16)) /*Tx High Priority Descriptor Error Interrupt */ -#define IMR_THPDOK ((1 << 15)) /*Tx High Priority Descriptor OK Interrupt */ -#define IMR_TVODER ((1 << 14)) /*Tx AC_VO Descriptor Error Interrupt */ -#define IMR_TVODOK ((1 << 13)) /*Tx AC_VO Descriptor OK Interrupt */ -#define IMR_FOVW ((1 << 12)) /*Rx FIFO Overflow Interrupt */ -#define IMR_RDU ((1 << 11)) /*Rx Descriptor Unavailable Interrupt */ -#define IMR_TVIDER ((1 << 10)) /*Tx AC_VI Descriptor Error Interrupt */ -#define IMR_TVIDOK ((1 << 9)) /*Tx AC_VI Descriptor OK Interrupt */ -#define IMR_RER ((1 << 8)) /*Rx Error Interrupt */ -#define IMR_ROK ((1 << 7)) /*Receive OK Interrupt */ -#define IMR_TBEDER ((1 << 6)) /*Tx AC_BE Descriptor Error Interrupt */ -#define IMR_TBEDOK ((1 << 5)) /*Tx AC_BE Descriptor OK Interrupt */ -#define IMR_TBKDER ((1 << 4)) /*Tx AC_BK Descriptor Error Interrupt */ -#define IMR_TBKDOK ((1 << 3)) /*Tx AC_BK Descriptor OK Interrupt */ -#define IMR_RQoSOK ((1 << 2)) /*Rx QoS OK Interrupt */ -#define IMR_TimeOut2 ((1 << 1)) /*Time Out Interrupt 2 */ -#define IMR_TimeOut3 ((1 << 0)) /*Time Out Interrupt 3 */ -#define IMR_TMGDOK ((1 << 30)) -#define ISR_Dot11hInt ((1 << 25)) /*802.11h Measurement Interrupt */ -#define ISR_BcnDmaInt ((1 << 24)) /*Beacon DMA Interrupt */ /*What differenct between BcnDmaInt and BcnInt??? */ -#define ISR_WakeInt ((1 << 23)) /*Wake Up Interrupt */ -#define ISR_TXFOVW ((1 << 22)) /*Tx FIFO Overflow Interrupt */ -#define ISR_TimeOut1 ((1 << 21)) /*Time Out Interrupt 1 */ -#define ISR_BcnInt ((1 << 20)) /*Beacon Time out Interrupt */ -#define ISR_ATIMInt ((1 << 19)) /*ATIM Time Out Interrupt */ -#define ISR_TBDER ((1 << 18)) /*Tx Beacon Descriptor Error Interrupt */ -#define ISR_TBDOK ((1 << 17)) /*Tx Beacon Descriptor OK Interrupt */ -#define ISR_THPDER ((1 << 16)) /*Tx High Priority Descriptor Error Interrupt */ -#define ISR_THPDOK ((1 << 15)) /*Tx High Priority Descriptor OK Interrupt */ -#define ISR_TVODER ((1 << 14)) /*Tx AC_VO Descriptor Error Interrupt */ -#define ISR_TVODOK ((1 << 13)) /*Tx AC_VO Descriptor OK Interrupt */ -#define ISR_FOVW ((1 << 12)) /*Rx FIFO Overflow Interrupt */ -#define ISR_RDU ((1 << 11)) /*Rx Descriptor Unavailable Interrupt */ -#define ISR_TVIDER ((1 << 10)) /*Tx AC_VI Descriptor Error Interrupt */ -#define ISR_TVIDOK ((1 << 9)) /*Tx AC_VI Descriptor OK Interrupt */ -#define ISR_RER ((1 << 8)) /*Rx Error Interrupt */ -#define ISR_ROK ((1 << 7)) /*Receive OK Interrupt */ -#define ISR_TBEDER ((1 << 6)) /*Tx AC_BE Descriptor Error Interrupt */ -#define ISR_TBEDOK ((1 << 5)) /*Tx AC_BE Descriptor OK Interrupt */ -#define ISR_TBKDER ((1 << 4)) /*Tx AC_BK Descriptor Error Interrupt */ -#define ISR_TBKDOK ((1 << 3)) /*Tx AC_BK Descriptor OK Interrupt */ -#define ISR_RQoSOK ((1 << 2)) /*Rx QoS OK Interrupt */ -#define ISR_TimeOut2 ((1 << 1)) /*Time Out Interrupt 2 */ -#define ISR_TimeOut3 ((1 << 0)) /*Time Out Interrupt 3 */ - -/* these definition is used for Tx/Rx test temporarily */ -#define ISR_TLPDER ISR_TVIDER -#define ISR_TLPDOK ISR_TVIDOK -#define ISR_TNPDER ISR_TVODER -#define ISR_TNPDOK ISR_TVODOK -#define ISR_TimeOut ISR_TimeOut1 -#define ISR_RXFOVW ISR_FOVW - - -#define HW_VERID_R8180_F 3 -#define HW_VERID_R8180_ABCD 2 -#define HW_VERID_R8185_ABC 4 -#define HW_VERID_R8185_D 5 -#define HW_VERID_R8185B_B 6 - -#define TCR_CWMIN ((1 << 31)) -#define TCR_SWSEQ ((1 << 30)) -#define TCR_HWVERID_MASK ((1 << 27)|(1 << 26)|(1 << 25)) -#define TCR_HWVERID_SHIFT 25 -#define TCR_SAT ((1 << 24)) -#define TCR_PLCP_LEN TCR_SAT /* rtl8180 */ -#define TCR_MXDMA_MASK ((1 << 23)|(1 << 22)|(1 << 21)) -#define TCR_MXDMA_1024 6 -#define TCR_MXDMA_2048 7 -#define TCR_MXDMA_SHIFT 21 -#define TCR_DISCW ((1 << 20)) -#define TCR_ICV ((1 << 19)) -#define TCR_LBK ((1 << 18)|(1 << 17)) -#define TCR_LBK1 ((1 << 18)) -#define TCR_LBK0 ((1 << 17)) -#define TCR_CRC ((1 << 16)) -#define TCR_DPRETRY_MASK ((1 << 15)|(1 << 14)|(1 << 13)|(1 << 12)|(1 << 11)|(1 << 10)|(1 << 9)|(1 << 8)) -#define TCR_RTSRETRY_MASK ((1 << 0)|(1 << 1)|(1 << 2)|(1 << 3)|(1 << 4)|(1 << 5)|(1 << 6)|(1 << 7)) -#define TCR_PROBE_NOTIMESTAMP_SHIFT 29 /* rtl8185 */ - -#define RCR_ONLYERLPKT ((1 << 31)) -#define RCR_CS_SHIFT 29 -#define RCR_CS_MASK ((1 << 30) | (1 << 29)) -#define RCR_ENMARP ((1 << 28)) -#define RCR_CBSSID ((1 << 23)) -#define RCR_APWRMGT ((1 << 22)) -#define RCR_ADD3 ((1 << 21)) -#define RCR_AMF ((1 << 20)) -#define RCR_ACF ((1 << 19)) -#define RCR_ADF ((1 << 18)) -#define RCR_RXFTH ((1 << 15)|(1 << 14)|(1 << 13)) -#define RCR_RXFTH2 ((1 << 15)) -#define RCR_RXFTH1 ((1 << 14)) -#define RCR_RXFTH0 ((1 << 13)) -#define RCR_AICV ((1 << 12)) -#define RCR_MXDMA ((1 << 10)|(1 << 9)|(1 << 8)) -#define RCR_MXDMA2 ((1 << 10)) -#define RCR_MXDMA1 ((1 << 9)) -#define RCR_MXDMA0 ((1 << 8)) -#define RCR_9356SEL ((1 << 6)) -#define RCR_ACRC32 ((1 << 5)) -#define RCR_AB ((1 << 3)) -#define RCR_AM ((1 << 2)) -#define RCR_APM ((1 << 1)) -#define RCR_AAP ((1 << 0)) - -#define CR9346_EEM ((1 << 7)|(1 << 6)) -#define CR9346_EEM1 ((1 << 7)) -#define CR9346_EEM0 ((1 << 6)) -#define CR9346_EECS ((1 << 3)) -#define CR9346_EESK ((1 << 2)) -#define CR9346_EED1 ((1 << 1)) -#define CR9346_EED0 ((1 << 0)) - -#define CONFIG3_PARM_En ((1 << 6)) -#define CONFIG3_FuncRegEn ((1 << 1)) - -#define CONFIG4_PWRMGT ((1 << 5)) - -#define MSR_LINK_MASK ((1 << 2)|(1 << 3)) -#define MSR_LINK_MANAGED 2 -#define MSR_LINK_NONE 0 -#define MSR_LINK_SHIFT 2 -#define MSR_LINK_ADHOC 1 -#define MSR_LINK_MASTER 3 - -#define BcnItv_BcnItv (0x01FF) - -#define AtimWnd_AtimWnd (0x01FF) - -#define BintrItv_BintrItv (0x01FF) - -#define FEMR_INTR ((1 << 15)) -#define FEMR_WKUP ((1 << 14)) -#define FEMR_GWAKE ((1 << 4)) - -#define FFER_INTR ((1 << 15)) -#define FFER_GWAKE ((1 << 4)) - -/* Three wire mode. */ -#define SW_THREE_WIRE 0 -#define HW_THREE_WIRE 2 -/* RTL8187S by amy */ -#define HW_THREE_WIRE_PI 5 -#define HW_THREE_WIRE_SI 6 -/* by amy */ -#define TCR_LRL_OFFSET 0 -#define TCR_SRL_OFFSET 8 -#define TCR_MXDMA_OFFSET 21 -#define TCR_DISReqQsize_OFFSET 28 -#define TCR_DurProcMode_OFFSET 30 - -#define RCR_MXDMA_OFFSET 8 -#define RCR_FIFO_OFFSET 13 - -#define AckTimeOutReg 0x79 /* ACK timeout register, in unit of 4 us. */ - -#define RFTiming 0x8C - -#define TPPollStop 0x93 - -#define TXAGC_CTL 0x9C /*< RJ_TODO_8185B> TX_AGC_CONTROL (0x9C seems be removed at 8185B, see p37). */ -#define CCK_TXAGC 0x9D -#define OFDM_TXAGC 0x9E -#define ANTSEL 0x9F - -#define ACM_CONTROL 0x00BF /* ACM Control Registe */ - -#define IntMig 0xE2 /* Interrupt Migration (0xE2 ~ 0xE3) */ - -#define TID_AC_MAP 0xE8 /* TID to AC Mapping Register */ - -#define ANAPARAM3 0xEE /* How to use it? */ - -#define AC_VO_PARAM 0xF0 /* AC_VO Parameters Record */ -#define AC_VI_PARAM 0xF4 /* AC_VI Parameters Record */ -#define AC_BE_PARAM 0xF8 /* AC_BE Parameters Record */ -#define AC_BK_PARAM 0xFC /* AC_BK Parameters Record */ - -#define GPIOCtrl 0x16B /*GPIO Control Register. */ -#define ARFR 0x1E0 /* Auto Rate Fallback Register (0x1e0 ~ 0x1e2) */ - -#define RFSW_CTRL 0x272 /* 0x272-0x273. */ -#define SW_3W_DB0 0x274 /* Software 3-wire data buffer bit 31~0. */ -#define SW_3W_DB1 0x278 /* Software 3-wire data buffer bit 63~32. */ -#define SW_3W_CMD0 0x27C /* Software 3-wire Control/Status Register. */ -#define SW_3W_CMD1 0x27D /* Software 3-wire Control/Status Register. */ - -#define PI_DATA_READ 0X360 /* 0x360 - 0x361 Parallel Interface Data Register. */ -#define SI_DATA_READ 0x362 /* 0x362 - 0x363 Serial Interface Data Register. */ - -/* ----------------------------------------------------------------------------- - 8185B TPPollStop bits (offset 0x93, 1 byte) ----------------------------------------------------------------------------- -*/ -#define TPPOLLSTOP_BQ (0x01 << 7) -#define TPPOLLSTOP_AC_VIQ (0x01 << 4) - -#define MSR_LINK_ENEDCA (1<<4) - -/* ----------------------------------------------------------------------------- - 8187B AC_XX_PARAM bits ----------------------------------------------------------------------------- -*/ -#define AC_PARAM_TXOP_LIMIT_OFFSET 16 -#define AC_PARAM_ECW_MAX_OFFSET 12 -#define AC_PARAM_ECW_MIN_OFFSET 8 -#define AC_PARAM_AIFS_OFFSET 0 - -/* ----------------------------------------------------------------------------- - 8187B ACM_CONTROL bits (Offset 0xBF, 1 Byte) ----------------------------------------------------------------------------- -*/ -#define VOQ_ACM_EN (0x01 << 7) /*BIT7 */ -#define VIQ_ACM_EN (0x01 << 6) /*BIT6 */ -#define BEQ_ACM_EN (0x01 << 5) /*BIT5 */ -#define ACM_HW_EN (0x01 << 4) /*BIT4 */ -#define VOQ_ACM_CTL (0x01 << 2) /*BIT2 */ /* Set to 1 when AC_VO used time reaches or exceeds the admitted time */ -#define VIQ_ACM_CTL (0x01 << 1) /*BIT1 */ /* Set to 1 when AC_VI used time reaches or exceeds the admitted time */ -#define BEQ_ACM_CTL (0x01 << 0) /*BIT0 */ /* Set to 1 when AC_BE used time reaches or exceeds the admitted time */ - - -/* ----------------------------------------------------------------------------- - 8185B SW_3W_CMD bits (Offset 0x27C-0x27D, 16bit) ----------------------------------------------------------------------------- -*/ -#define SW_3W_CMD0_HOLD ((1 << 7)) -#define SW_3W_CMD1_RE ((1 << 0)) /* BIT8 */ -#define SW_3W_CMD1_WE ((1 << 1)) /* BIT9 */ -#define SW_3W_CMD1_DONE ((1 << 2)) /* BIT10 */ - -#define BB_HOST_BANG_RW (1 << 3) - -/* ----------------------------------------------------------------------------- - 8185B RATE_FALLBACK_CTL bits (Offset 0xBE, 8bit) ----------------------------------------------------------------------------- -*/ -#define RATE_FALLBACK_CTL_ENABLE ((1 << 7)) -#define RATE_FALLBACK_CTL_ENABLE_RTSCTS ((1 << 6)) -/* Auto rate fallback per 2^n retry. */ -#define RATE_FALLBACK_CTL_AUTO_STEP0 0x00 -#define RATE_FALLBACK_CTL_AUTO_STEP1 0x01 -#define RATE_FALLBACK_CTL_AUTO_STEP2 0x02 -#define RATE_FALLBACK_CTL_AUTO_STEP3 0x03 - - -#define RTL8225z2_ANAPARAM_OFF 0x55480658 -#define RTL8225z2_ANAPARAM2_OFF 0x72003f70 -/* by amy for power save */ -#define RF_CHANGE_BY_HW BIT30 -#define RF_CHANGE_BY_PS BIT29 -#define RF_CHANGE_BY_IPS BIT28 -/* by amy for power save */ -/* by amy for antenna */ -#define EEPROM_SW_REVD_OFFSET 0x3f - -/* BIT[8-9] is for SW Antenna Diversity. - * Only the value EEPROM_SW_AD_ENABLE means enable, other values are disable. - */ -#define EEPROM_SW_AD_MASK 0x0300 -#define EEPROM_SW_AD_ENABLE 0x0100 - -/* BIT[10-11] determine if Antenna 1 is the Default Antenna. - * Only the value EEPROM_DEF_ANT_1 means TRUE, other values are FALSE. - */ -#define EEPROM_DEF_ANT_MASK 0x0C00 -#define EEPROM_DEF_ANT_1 0x0400 -/*by amy for antenna */ -/* {by amy 080312 */ -/* 0x7C, 0x7D Crystal calibration and Tx Power tracking mechanism. Added by Roger. 2007.12.10. */ -#define EEPROM_RSV 0x7C -#define EEPROM_XTAL_CAL_XOUT_MASK 0x0F /* 0x7C[3:0], Crystal calibration for Xout. */ -#define EEPROM_XTAL_CAL_XIN_MASK 0xF0 /* 0x7C[7:4], Crystal calibration for Xin. */ -#define EEPROM_THERMAL_METER_MASK 0x0F00 /* 0x7D[3:0], Thermal meter reference level. */ -#define EEPROM_XTAL_CAL_ENABLE 0x1000 /* 0x7D[4], Crystal calibration enabled/disabled BIT. */ -#define EEPROM_THERMAL_METER_ENABLE 0x2000 /* 0x7D[5], Thermal meter enabled/disabled BIT. */ -#define EN_LPF_CAL 0x238 /* Enable LPF Calibration. */ -#define PWR_METER_EN BIT1 -/* where are false alarm counters in 8185B? */ -#define CCK_FALSE_ALARM 0xD0 -/* by amy 080312} */ - -/* YJ,add for Country IE, 080630 */ -#define EEPROM_COUNTRY_CODE 0x2E -/* YJ,add,080630,end */ - -#endif diff --git a/drivers/staging/rtl8187se/r8180_rtl8225.h b/drivers/staging/rtl8187se/r8180_rtl8225.h deleted file mode 100644 index 7df73927b3c..00000000000 --- a/drivers/staging/rtl8187se/r8180_rtl8225.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * This is part of the rtl8180-sa2400 driver released under the GPL (See file - * COPYING for details). - * - * Copyright (c) 2005 Andrea Merello - * - * This files contains programming code for the rtl8225 radio frontend. - * - * *Many* thanks to Realtek Corp. for their great support! - */ - -#include "r8180.h" - -#define RTL8225_ANAPARAM_ON 0xa0000b59 -#define RTL8225_ANAPARAM_OFF 0xa00beb59 -#define RTL8225_ANAPARAM2_OFF 0x840dec11 -#define RTL8225_ANAPARAM2_ON 0x860dec11 -#define RTL8225_ANAPARAM_SLEEP 0xa00bab59 -#define RTL8225_ANAPARAM2_SLEEP 0x840dec11 - -void rtl8225z2_rf_init(struct net_device *dev); -void rtl8225z2_rf_set_chan(struct net_device *dev, short ch); -void rtl8225z2_rf_close(struct net_device *dev); - -void RF_WriteReg(struct net_device *dev, u8 offset, u16 data); -u16 RF_ReadReg(struct net_device *dev, u8 offset); - -void rtl8180_set_mode(struct net_device *dev, int mode); -void rtl8180_set_mode(struct net_device *dev, int mode); -bool SetZebraRFPowerState8185(struct net_device *dev, - enum rt_rf_power_state eRFPowerState); -void rtl8225z4_rf_sleep(struct net_device *dev); -void rtl8225z4_rf_wakeup(struct net_device *dev); - diff --git a/drivers/staging/rtl8187se/r8180_rtl8225z2.c b/drivers/staging/rtl8187se/r8180_rtl8225z2.c deleted file mode 100644 index 47104fa05c5..00000000000 --- a/drivers/staging/rtl8187se/r8180_rtl8225z2.c +++ /dev/null @@ -1,811 +0,0 @@ -/* - * This is part of the rtl8180-sa2400 driver - * released under the GPL (See file COPYING for details). - * Copyright (c) 2005 Andrea Merello - * - * This files contains programming code for the rtl8225 - * radio frontend. - * - * *Many* thanks to Realtek Corp. for their great support! - */ - -#include "r8180_hw.h" -#include "r8180_rtl8225.h" -#include "r8180_93cx6.h" - -#include "ieee80211/dot11d.h" - -static void write_rtl8225(struct net_device *dev, u8 adr, u16 data) -{ - int i; - u16 out, select; - u8 bit; - u32 bangdata = (data << 4) | (adr & 0xf); - - out = read_nic_word(dev, RFPinsOutput) & 0xfff3; - - write_nic_word(dev, RFPinsEnable, - (read_nic_word(dev, RFPinsEnable) | 0x7)); - - select = read_nic_word(dev, RFPinsSelect); - - write_nic_word(dev, RFPinsSelect, select | 0x7 | - SW_CONTROL_GPIO); - - force_pci_posting(dev); - udelay(10); - - write_nic_word(dev, RFPinsOutput, out | BB_HOST_BANG_EN); - - force_pci_posting(dev); - udelay(2); - - write_nic_word(dev, RFPinsOutput, out); - - force_pci_posting(dev); - udelay(10); - - for (i = 15; i >= 0; i--) { - bit = (bangdata & (1 << i)) >> i; - - write_nic_word(dev, RFPinsOutput, bit | out); - - write_nic_word(dev, RFPinsOutput, bit | out | BB_HOST_BANG_CLK); - write_nic_word(dev, RFPinsOutput, bit | out | BB_HOST_BANG_CLK); - - i--; - bit = (bangdata & (1 << i)) >> i; - - write_nic_word(dev, RFPinsOutput, bit | out | BB_HOST_BANG_CLK); - write_nic_word(dev, RFPinsOutput, bit | out | BB_HOST_BANG_CLK); - - write_nic_word(dev, RFPinsOutput, bit | out); - - } - - write_nic_word(dev, RFPinsOutput, out | BB_HOST_BANG_EN); - - force_pci_posting(dev); - udelay(10); - - write_nic_word(dev, RFPinsOutput, out | BB_HOST_BANG_EN); - - write_nic_word(dev, RFPinsSelect, select | SW_CONTROL_GPIO); - - rtl8185_rf_pins_enable(dev); -} - -static const u8 rtl8225_agc[] = { - 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, - 0x9d, 0x9c, 0x9b, 0x9a, 0x99, 0x98, 0x97, 0x96, - 0x95, 0x94, 0x93, 0x92, 0x91, 0x90, 0x8f, 0x8e, - 0x8d, 0x8c, 0x8b, 0x8a, 0x89, 0x88, 0x87, 0x86, - 0x85, 0x84, 0x83, 0x82, 0x81, 0x80, 0x3f, 0x3e, - 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x37, 0x36, - 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x2f, 0x2e, - 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26, - 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x1f, 0x1e, - 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x17, 0x16, - 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0x0e, - 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, - 0x05, 0x04, 0x03, 0x02, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, -}; - -static const u32 rtl8225_chan[] = { - 0, - 0x0080, 0x0100, 0x0180, 0x0200, 0x0280, 0x0300, 0x0380, - 0x0400, 0x0480, 0x0500, 0x0580, 0x0600, 0x0680, 0x074A, -}; - -static const u8 rtl8225z2_gain_bg[] = { - 0x23, 0x15, 0xa5, /* -82-1dBm */ - 0x23, 0x15, 0xb5, /* -82-2dBm */ - 0x23, 0x15, 0xc5, /* -82-3dBm */ - 0x33, 0x15, 0xc5, /* -78dBm */ - 0x43, 0x15, 0xc5, /* -74dBm */ - 0x53, 0x15, 0xc5, /* -70dBm */ - 0x63, 0x15, 0xc5, /* -66dBm */ -}; - -static const u8 rtl8225z2_gain_a[] = { - 0x13, 0x27, 0x5a, /* -82dBm */ - 0x23, 0x23, 0x58, /* -82dBm */ - 0x33, 0x1f, 0x56, /* -82dBm */ - 0x43, 0x1b, 0x54, /* -78dBm */ - 0x53, 0x17, 0x51, /* -74dBm */ - 0x63, 0x24, 0x4f, /* -70dBm */ - 0x73, 0x0f, 0x4c, /* -66dBm */ -}; - -static const u16 rtl8225z2_rxgain[] = { - 0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0408, 0x0409, - 0x040a, 0x040b, 0x0502, 0x0503, 0x0504, 0x0505, 0x0540, 0x0541, - 0x0542, 0x0543, 0x0544, 0x0545, 0x0580, 0x0581, 0x0582, 0x0583, - 0x0584, 0x0585, 0x0588, 0x0589, 0x058a, 0x058b, 0x0643, 0x0644, - 0x0645, 0x0680, 0x0681, 0x0682, 0x0683, 0x0684, 0x0685, 0x0688, - 0x0689, 0x068a, 0x068b, 0x068c, 0x0742, 0x0743, 0x0744, 0x0745, - 0x0780, 0x0781, 0x0782, 0x0783, 0x0784, 0x0785, 0x0788, 0x0789, - 0x078a, 0x078b, 0x078c, 0x078d, 0x0790, 0x0791, 0x0792, 0x0793, - 0x0794, 0x0795, 0x0798, 0x0799, 0x079a, 0x079b, 0x079c, 0x079d, - 0x07a0, 0x07a1, 0x07a2, 0x07a3, 0x07a4, 0x07a5, 0x07a8, 0x07a9, - 0x03aa, 0x03ab, 0x03ac, 0x03ad, 0x03b0, 0x03b1, 0x03b2, 0x03b3, - 0x03b4, 0x03b5, 0x03b8, 0x03b9, 0x03ba, 0x03bb - -}; - -static void rtl8225z2_set_gain(struct net_device *dev, short gain) -{ - const u8 *rtl8225_gain; - struct r8180_priv *priv = ieee80211_priv(dev); - u8 mode = priv->ieee80211->mode; - - if (mode == IEEE_B || mode == IEEE_G) - rtl8225_gain = rtl8225z2_gain_bg; - else - rtl8225_gain = rtl8225z2_gain_a; - - write_phy_ofdm(dev, 0x0b, rtl8225_gain[gain * 3]); - write_phy_ofdm(dev, 0x1b, rtl8225_gain[gain * 3 + 1]); - write_phy_ofdm(dev, 0x1d, rtl8225_gain[gain * 3 + 2]); - write_phy_ofdm(dev, 0x21, 0x37); -} - -static u32 read_rtl8225(struct net_device *dev, u8 adr) -{ - u32 data2Write = ((u32)(adr & 0x1f)) << 27; - u32 dataRead; - u32 mask; - u16 oval, oval2, oval3, tmp; - int i; - short bit, rw; - u8 wLength = 6; - u8 rLength = 12; - u8 low2high = 0; - - oval = read_nic_word(dev, RFPinsOutput); - oval2 = read_nic_word(dev, RFPinsEnable); - oval3 = read_nic_word(dev, RFPinsSelect); - - write_nic_word(dev, RFPinsEnable, (oval2|0xf)); - write_nic_word(dev, RFPinsSelect, (oval3|0xf)); - - dataRead = 0; - - oval &= ~0xf; - - write_nic_word(dev, RFPinsOutput, oval | BB_HOST_BANG_EN); - udelay(4); - - write_nic_word(dev, RFPinsOutput, oval); - udelay(5); - - rw = 0; - - mask = (low2high) ? 0x01 : (((u32)0x01)<<(32-1)); - - for (i = 0; i < wLength/2; i++) { - bit = ((data2Write&mask) != 0) ? 1 : 0; - write_nic_word(dev, RFPinsOutput, bit | oval | rw); - udelay(1); - - write_nic_word(dev, RFPinsOutput, - bit | oval | BB_HOST_BANG_CLK | rw); - udelay(2); - write_nic_word(dev, RFPinsOutput, - bit | oval | BB_HOST_BANG_CLK | rw); - udelay(2); - - mask = (low2high) ? (mask<<1) : (mask>>1); - - if (i == 2) { - rw = BB_HOST_BANG_RW; - write_nic_word(dev, RFPinsOutput, - bit | oval | BB_HOST_BANG_CLK | rw); - udelay(2); - write_nic_word(dev, RFPinsOutput, bit | oval | rw); - udelay(2); - break; - } - - bit = ((data2Write&mask) != 0) ? 1 : 0; - - write_nic_word(dev, RFPinsOutput, - oval | bit | rw | BB_HOST_BANG_CLK); - udelay(2); - write_nic_word(dev, RFPinsOutput, - oval | bit | rw | BB_HOST_BANG_CLK); - udelay(2); - - write_nic_word(dev, RFPinsOutput, oval | bit | rw); - udelay(1); - - mask = (low2high) ? (mask<<1) : (mask>>1); - } - - write_nic_word(dev, RFPinsOutput, rw|oval); - udelay(2); - mask = (low2high) ? 0x01 : (((u32)0x01) << (12-1)); - - /* - * We must set data pin to HW controlled, otherwise RF can't driver it - * and value RF register won't be able to read back properly. - */ - write_nic_word(dev, RFPinsEnable, (oval2 & (~0x01))); - - for (i = 0; i < rLength; i++) { - write_nic_word(dev, RFPinsOutput, rw|oval); udelay(1); - - write_nic_word(dev, RFPinsOutput, rw|oval|BB_HOST_BANG_CLK); - udelay(2); - write_nic_word(dev, RFPinsOutput, rw|oval|BB_HOST_BANG_CLK); - udelay(2); - write_nic_word(dev, RFPinsOutput, rw|oval|BB_HOST_BANG_CLK); - udelay(2); - tmp = read_nic_word(dev, RFPinsInput); - - dataRead |= (tmp & BB_HOST_BANG_CLK ? mask : 0); - - write_nic_word(dev, RFPinsOutput, (rw|oval)); udelay(2); - - mask = (low2high) ? (mask<<1) : (mask>>1); - } - - write_nic_word(dev, RFPinsOutput, - BB_HOST_BANG_EN | BB_HOST_BANG_RW | oval); - udelay(2); - - write_nic_word(dev, RFPinsEnable, oval2); - write_nic_word(dev, RFPinsSelect, oval3); /* Set To SW Switch */ - write_nic_word(dev, RFPinsOutput, 0x3a0); - - return dataRead; -} - -void rtl8225z2_rf_close(struct net_device *dev) -{ - RF_WriteReg(dev, 0x4, 0x1f); - - force_pci_posting(dev); - mdelay(1); - - rtl8180_set_anaparam(dev, RTL8225z2_ANAPARAM_OFF); - rtl8185_set_anaparam2(dev, RTL8225z2_ANAPARAM2_OFF); -} - -/* - * Map dBm into Tx power index according to current HW model, for example, - * RF and PA, and current wireless mode. - */ -static s8 DbmToTxPwrIdx(struct r8180_priv *priv, - enum wireless_mode mode, s32 PowerInDbm) -{ - bool bUseDefault = true; - s8 TxPwrIdx = 0; - - /* - * OFDM Power in dBm = Index * 0.5 + 0 - * CCK Power in dBm = Index * 0.25 + 13 - */ - s32 tmp = 0; - - if (mode == WIRELESS_MODE_G) { - bUseDefault = false; - tmp = (2 * PowerInDbm); - - if (tmp < 0) - TxPwrIdx = 0; - else if (tmp > 40) /* 40 means 20 dBm. */ - TxPwrIdx = 40; - else - TxPwrIdx = (s8)tmp; - } else if (mode == WIRELESS_MODE_B) { - bUseDefault = false; - tmp = (4 * PowerInDbm) - 52; - - if (tmp < 0) - TxPwrIdx = 0; - else if (tmp > 28) /* 28 means 20 dBm. */ - TxPwrIdx = 28; - else - TxPwrIdx = (s8)tmp; - } - - /* - * TRUE if we want to use a default implementation. - * We shall set it to FALSE when we have exact translation formula - * for target IC. 070622, by rcnjko. - */ - if (bUseDefault) { - if (PowerInDbm < 0) - TxPwrIdx = 0; - else if (PowerInDbm > 35) - TxPwrIdx = 35; - else - TxPwrIdx = (u8)PowerInDbm; - } - - return TxPwrIdx; -} - -void rtl8225z2_SetTXPowerLevel(struct net_device *dev, short ch) -{ - struct r8180_priv *priv = ieee80211_priv(dev); - u8 max_cck_power_level; - u8 max_ofdm_power_level; - u8 min_ofdm_power_level; - char cck_power_level = (char)(0xff & priv->chtxpwr[ch]); - char ofdm_power_level = (char)(0xff & priv->chtxpwr_ofdm[ch]); - - if (IS_DOT11D_ENABLE(priv->ieee80211) && - IS_DOT11D_STATE_DONE(priv->ieee80211)) { - u8 MaxTxPwrInDbm = DOT11D_GetMaxTxPwrInDbm(priv->ieee80211, ch); - u8 CckMaxPwrIdx = DbmToTxPwrIdx(priv, WIRELESS_MODE_B, - MaxTxPwrInDbm); - u8 OfdmMaxPwrIdx = DbmToTxPwrIdx(priv, WIRELESS_MODE_G, - MaxTxPwrInDbm); - - if (cck_power_level > CckMaxPwrIdx) - cck_power_level = CckMaxPwrIdx; - if (ofdm_power_level > OfdmMaxPwrIdx) - ofdm_power_level = OfdmMaxPwrIdx; - } - - max_cck_power_level = 15; - max_ofdm_power_level = 25; - min_ofdm_power_level = 10; - - if (cck_power_level > 35) - cck_power_level = 35; - - write_nic_byte(dev, CCK_TXAGC, cck_power_level); - force_pci_posting(dev); - mdelay(1); - - if (ofdm_power_level > 35) - ofdm_power_level = 35; - - if (priv->up == 0) { - write_phy_ofdm(dev, 2, 0x42); - write_phy_ofdm(dev, 5, 0x00); - write_phy_ofdm(dev, 6, 0x40); - write_phy_ofdm(dev, 7, 0x00); - write_phy_ofdm(dev, 8, 0x40); - } - - write_nic_byte(dev, OFDM_TXAGC, ofdm_power_level); - - if (ofdm_power_level <= 11) { - write_phy_ofdm(dev, 0x07, 0x5c); - write_phy_ofdm(dev, 0x09, 0x5c); - } - - if (ofdm_power_level <= 17) { - write_phy_ofdm(dev, 0x07, 0x54); - write_phy_ofdm(dev, 0x09, 0x54); - } else { - write_phy_ofdm(dev, 0x07, 0x50); - write_phy_ofdm(dev, 0x09, 0x50); - } - - force_pci_posting(dev); - mdelay(1); -} - -void rtl8225z2_rf_set_chan(struct net_device *dev, short ch) -{ - rtl8225z2_SetTXPowerLevel(dev, ch); - - RF_WriteReg(dev, 0x7, rtl8225_chan[ch]); - - if ((RF_ReadReg(dev, 0x7) & 0x0F80) != rtl8225_chan[ch]) - RF_WriteReg(dev, 0x7, rtl8225_chan[ch]); - - mdelay(1); - - force_pci_posting(dev); - mdelay(10); -} - -static void rtl8225_host_pci_init(struct net_device *dev) -{ - write_nic_word(dev, RFPinsOutput, 0x480); - - rtl8185_rf_pins_enable(dev); - - write_nic_word(dev, RFPinsSelect, 0x88 | SW_CONTROL_GPIO); - - write_nic_byte(dev, GP_ENABLE, 0); - - force_pci_posting(dev); - mdelay(200); - - /* bit 6 is for RF on/off detection */ - write_nic_word(dev, GP_ENABLE, 0xff & (~(1 << 6))); -} - -void rtl8225z2_rf_init(struct net_device *dev) -{ - struct r8180_priv *priv = ieee80211_priv(dev); - int i; - short channel = 1; - u16 brsr; - u32 data; - - priv->chan = channel; - - rtl8225_host_pci_init(dev); - - write_nic_dword(dev, RF_TIMING, 0x000a8008); - - brsr = read_nic_word(dev, BRSR); - - write_nic_word(dev, BRSR, 0xffff); - - write_nic_dword(dev, RF_PARA, 0x100044); - - rtl8180_set_mode(dev, EPROM_CMD_CONFIG); - write_nic_byte(dev, CONFIG3, 0x44); - rtl8180_set_mode(dev, EPROM_CMD_NORMAL); - - rtl8185_rf_pins_enable(dev); - - write_rtl8225(dev, 0x0, 0x2bf); mdelay(1); - write_rtl8225(dev, 0x1, 0xee0); mdelay(1); - write_rtl8225(dev, 0x2, 0x44d); mdelay(1); - write_rtl8225(dev, 0x3, 0x441); mdelay(1); - write_rtl8225(dev, 0x4, 0x8c3); mdelay(1); - write_rtl8225(dev, 0x5, 0xc72); mdelay(1); - write_rtl8225(dev, 0x6, 0xe6); mdelay(1); - write_rtl8225(dev, 0x7, rtl8225_chan[channel]); mdelay(1); - write_rtl8225(dev, 0x8, 0x3f); mdelay(1); - write_rtl8225(dev, 0x9, 0x335); mdelay(1); - write_rtl8225(dev, 0xa, 0x9d4); mdelay(1); - write_rtl8225(dev, 0xb, 0x7bb); mdelay(1); - write_rtl8225(dev, 0xc, 0x850); mdelay(1); - write_rtl8225(dev, 0xd, 0xcdf); mdelay(1); - write_rtl8225(dev, 0xe, 0x2b); mdelay(1); - write_rtl8225(dev, 0xf, 0x114); - - mdelay(100); - - write_rtl8225(dev, 0x0, 0x1b7); - - for (i = 0; i < ARRAY_SIZE(rtl8225z2_rxgain); i++) { - write_rtl8225(dev, 0x1, i + 1); - write_rtl8225(dev, 0x2, rtl8225z2_rxgain[i]); - } - - write_rtl8225(dev, 0x3, 0x80); - write_rtl8225(dev, 0x5, 0x4); - - write_rtl8225(dev, 0x0, 0xb7); - - write_rtl8225(dev, 0x2, 0xc4d); - - /* FIXME!! rtl8187 we have to check if calibrarion - * is successful and eventually cal. again (repeat - * the two write on reg 2) - */ - data = read_rtl8225(dev, 6); - if (!(data & 0x00000080)) { - write_rtl8225(dev, 0x02, 0x0c4d); - force_pci_posting(dev); mdelay(200); - write_rtl8225(dev, 0x02, 0x044d); - force_pci_posting(dev); mdelay(100); - data = read_rtl8225(dev, 6); - if (!(data & 0x00000080)) - DMESGW("RF Calibration Failed!!!!\n"); - } - - mdelay(200); - - write_rtl8225(dev, 0x0, 0x2bf); - - for (i = 0; i < ARRAY_SIZE(rtl8225_agc); i++) { - write_phy_ofdm(dev, 0xb, rtl8225_agc[i]); - mdelay(1); - - /* enable writing AGC table */ - write_phy_ofdm(dev, 0xa, i + 0x80); - mdelay(1); - } - - force_pci_posting(dev); - mdelay(1); - - write_phy_ofdm(dev, 0x00, 0x01); mdelay(1); - write_phy_ofdm(dev, 0x01, 0x02); mdelay(1); - write_phy_ofdm(dev, 0x02, 0x62); mdelay(1); - write_phy_ofdm(dev, 0x03, 0x00); mdelay(1); - write_phy_ofdm(dev, 0x04, 0x00); mdelay(1); - write_phy_ofdm(dev, 0x05, 0x00); mdelay(1); - write_phy_ofdm(dev, 0x06, 0x40); mdelay(1); - write_phy_ofdm(dev, 0x07, 0x00); mdelay(1); - write_phy_ofdm(dev, 0x08, 0x40); mdelay(1); - write_phy_ofdm(dev, 0x09, 0xfe); mdelay(1); - write_phy_ofdm(dev, 0x0a, 0x08); mdelay(1); - write_phy_ofdm(dev, 0x0b, 0x80); mdelay(1); - write_phy_ofdm(dev, 0x0c, 0x01); mdelay(1); - write_phy_ofdm(dev, 0x0d, 0x43); - write_phy_ofdm(dev, 0x0e, 0xd3); mdelay(1); - write_phy_ofdm(dev, 0x0f, 0x38); mdelay(1); - write_phy_ofdm(dev, 0x10, 0x84); mdelay(1); - write_phy_ofdm(dev, 0x11, 0x07); mdelay(1); - write_phy_ofdm(dev, 0x12, 0x20); mdelay(1); - write_phy_ofdm(dev, 0x13, 0x20); mdelay(1); - write_phy_ofdm(dev, 0x14, 0x00); mdelay(1); - write_phy_ofdm(dev, 0x15, 0x40); mdelay(1); - write_phy_ofdm(dev, 0x16, 0x00); mdelay(1); - write_phy_ofdm(dev, 0x17, 0x40); mdelay(1); - write_phy_ofdm(dev, 0x18, 0xef); mdelay(1); - write_phy_ofdm(dev, 0x19, 0x19); mdelay(1); - write_phy_ofdm(dev, 0x1a, 0x20); mdelay(1); - write_phy_ofdm(dev, 0x1b, 0x15); mdelay(1); - write_phy_ofdm(dev, 0x1c, 0x04); mdelay(1); - write_phy_ofdm(dev, 0x1d, 0xc5); mdelay(1); - write_phy_ofdm(dev, 0x1e, 0x95); mdelay(1); - write_phy_ofdm(dev, 0x1f, 0x75); mdelay(1); - write_phy_ofdm(dev, 0x20, 0x1f); mdelay(1); - write_phy_ofdm(dev, 0x21, 0x17); mdelay(1); - write_phy_ofdm(dev, 0x22, 0x16); mdelay(1); - write_phy_ofdm(dev, 0x23, 0x80); mdelay(1); /* FIXME maybe not needed */ - write_phy_ofdm(dev, 0x24, 0x46); mdelay(1); - write_phy_ofdm(dev, 0x25, 0x00); mdelay(1); - write_phy_ofdm(dev, 0x26, 0x90); mdelay(1); - write_phy_ofdm(dev, 0x27, 0x88); mdelay(1); - - rtl8225z2_set_gain(dev, 4); - - write_phy_cck(dev, 0x0, 0x98); mdelay(1); - write_phy_cck(dev, 0x3, 0x20); mdelay(1); - write_phy_cck(dev, 0x4, 0x7e); mdelay(1); - write_phy_cck(dev, 0x5, 0x12); mdelay(1); - write_phy_cck(dev, 0x6, 0xfc); mdelay(1); - write_phy_cck(dev, 0x7, 0x78); mdelay(1); - write_phy_cck(dev, 0x8, 0x2e); mdelay(1); - write_phy_cck(dev, 0x10, 0x93); mdelay(1); - write_phy_cck(dev, 0x11, 0x88); mdelay(1); - write_phy_cck(dev, 0x12, 0x47); mdelay(1); - write_phy_cck(dev, 0x13, 0xd0); - write_phy_cck(dev, 0x19, 0x00); - write_phy_cck(dev, 0x1a, 0xa0); - write_phy_cck(dev, 0x1b, 0x08); - write_phy_cck(dev, 0x40, 0x86); /* CCK Carrier Sense Threshold */ - write_phy_cck(dev, 0x41, 0x8d); mdelay(1); - write_phy_cck(dev, 0x42, 0x15); mdelay(1); - write_phy_cck(dev, 0x43, 0x18); mdelay(1); - write_phy_cck(dev, 0x44, 0x36); mdelay(1); - write_phy_cck(dev, 0x45, 0x35); mdelay(1); - write_phy_cck(dev, 0x46, 0x2e); mdelay(1); - write_phy_cck(dev, 0x47, 0x25); mdelay(1); - write_phy_cck(dev, 0x48, 0x1c); mdelay(1); - write_phy_cck(dev, 0x49, 0x12); mdelay(1); - write_phy_cck(dev, 0x4a, 0x09); mdelay(1); - write_phy_cck(dev, 0x4b, 0x04); mdelay(1); - write_phy_cck(dev, 0x4c, 0x05); mdelay(1); - - write_nic_byte(dev, 0x5b, 0x0d); mdelay(1); - - rtl8225z2_SetTXPowerLevel(dev, channel); - - /* RX antenna default to A */ - write_phy_cck(dev, 0x11, 0x9b); mdelay(1); /* B: 0xDB */ - write_phy_ofdm(dev, 0x26, 0x90); mdelay(1); /* B: 0x10 */ - - rtl8185_tx_antenna(dev, 0x03); /* B: 0x00 */ - - /* switch to high-speed 3-wire - * last digit. 2 for both cck and ofdm - */ - write_nic_dword(dev, 0x94, 0x15c00002); - rtl8185_rf_pins_enable(dev); - - rtl8225z2_rf_set_chan(dev, priv->chan); -} - -#define MAX_DOZE_WAITING_TIMES_85B 20 -#define MAX_POLLING_24F_TIMES_87SE 10 -#define LPS_MAX_SLEEP_WAITING_TIMES_87SE 5 - -bool SetZebraRFPowerState8185(struct net_device *dev, - enum rt_rf_power_state eRFPowerState) -{ - struct r8180_priv *priv = ieee80211_priv(dev); - u8 btCR9346, btConfig3; - bool bActionAllowed = true, bTurnOffBB = true; - u8 u1bTmp; - int i; - bool bResult = true; - u8 QueueID; - - if (priv->SetRFPowerStateInProgress == true) - return false; - - priv->SetRFPowerStateInProgress = true; - - btCR9346 = read_nic_byte(dev, CR9346); - write_nic_byte(dev, CR9346, (btCR9346 | 0xC0)); - - btConfig3 = read_nic_byte(dev, CONFIG3); - write_nic_byte(dev, CONFIG3, (btConfig3 | CONFIG3_PARM_En)); - - switch (eRFPowerState) { - case RF_ON: - write_nic_word(dev, 0x37C, 0x00EC); - - /* turn on AFE */ - write_nic_byte(dev, 0x54, 0x00); - write_nic_byte(dev, 0x62, 0x00); - - /* turn on RF */ - RF_WriteReg(dev, 0x0, 0x009f); udelay(500); - RF_WriteReg(dev, 0x4, 0x0972); udelay(500); - - /* turn on RF again */ - RF_WriteReg(dev, 0x0, 0x009f); udelay(500); - RF_WriteReg(dev, 0x4, 0x0972); udelay(500); - - /* turn on BB */ - write_phy_ofdm(dev, 0x10, 0x40); - write_phy_ofdm(dev, 0x12, 0x40); - - /* Avoid power down at init time. */ - write_nic_byte(dev, CONFIG4, priv->RFProgType); - - u1bTmp = read_nic_byte(dev, 0x24E); - write_nic_byte(dev, 0x24E, (u1bTmp & (~(BIT5 | BIT6)))); - break; - case RF_SLEEP: - for (QueueID = 0, i = 0; QueueID < 6;) { - if (get_curr_tx_free_desc(dev, QueueID) == - priv->txringcount) { - QueueID++; - continue; - } else { - priv->TxPollingTimes++; - if (priv->TxPollingTimes >= - LPS_MAX_SLEEP_WAITING_TIMES_87SE) { - bActionAllowed = false; - break; - } else - udelay(10); - } - } - - if (bActionAllowed) { - /* turn off BB RXIQ matrix to cut off rx signal */ - write_phy_ofdm(dev, 0x10, 0x00); - write_phy_ofdm(dev, 0x12, 0x00); - - /* turn off RF */ - RF_WriteReg(dev, 0x4, 0x0000); - RF_WriteReg(dev, 0x0, 0x0000); - - /* turn off AFE except PLL */ - write_nic_byte(dev, 0x62, 0xff); - write_nic_byte(dev, 0x54, 0xec); - - mdelay(1); - - { - int i = 0; - while (true) { - u8 tmp24F = read_nic_byte(dev, 0x24f); - - if ((tmp24F == 0x01) || - (tmp24F == 0x09)) { - bTurnOffBB = true; - break; - } else { - udelay(10); - i++; - priv->TxPollingTimes++; - - if (priv->TxPollingTimes >= LPS_MAX_SLEEP_WAITING_TIMES_87SE) { - bTurnOffBB = false; - break; - } else - udelay(10); - } - } - } - - if (bTurnOffBB) { - /* turn off BB */ - u1bTmp = read_nic_byte(dev, 0x24E); - write_nic_byte(dev, 0x24E, - (u1bTmp | BIT5 | BIT6)); - - /* turn off AFE PLL */ - write_nic_byte(dev, 0x54, 0xFC); - write_nic_word(dev, 0x37C, 0x00FC); - } - } - break; - case RF_OFF: - for (QueueID = 0, i = 0; QueueID < 6;) { - if (get_curr_tx_free_desc(dev, QueueID) == - priv->txringcount) { - QueueID++; - continue; - } else { - udelay(10); - i++; - } - - if (i >= MAX_DOZE_WAITING_TIMES_85B) - break; - } - - /* turn off BB RXIQ matrix to cut off rx signal */ - write_phy_ofdm(dev, 0x10, 0x00); - write_phy_ofdm(dev, 0x12, 0x00); - - /* turn off RF */ - RF_WriteReg(dev, 0x4, 0x0000); - RF_WriteReg(dev, 0x0, 0x0000); - - /* turn off AFE except PLL */ - write_nic_byte(dev, 0x62, 0xff); - write_nic_byte(dev, 0x54, 0xec); - - mdelay(1); - - { - int i = 0; - - while (true) { - u8 tmp24F = read_nic_byte(dev, 0x24f); - - if ((tmp24F == 0x01) || (tmp24F == 0x09)) { - bTurnOffBB = true; - break; - } else { - bTurnOffBB = false; - udelay(10); - i++; - } - - if (i > MAX_POLLING_24F_TIMES_87SE) - break; - } - } - - if (bTurnOffBB) { - /* turn off BB */ - u1bTmp = read_nic_byte(dev, 0x24E); - write_nic_byte(dev, 0x24E, (u1bTmp | BIT5 | BIT6)); - - /* turn off AFE PLL (80M) */ - write_nic_byte(dev, 0x54, 0xFC); - write_nic_word(dev, 0x37C, 0x00FC); - } - break; - } - - btConfig3 &= ~(CONFIG3_PARM_En); - write_nic_byte(dev, CONFIG3, btConfig3); - - btCR9346 &= ~(0xC0); - write_nic_byte(dev, CR9346, btCR9346); - - if (bResult && bActionAllowed) - priv->eRFPowerState = eRFPowerState; - - priv->SetRFPowerStateInProgress = false; - - return bResult && bActionAllowed; -} - -void rtl8225z4_rf_sleep(struct net_device *dev) -{ - MgntActSet_RF_State(dev, RF_SLEEP, RF_CHANGE_BY_PS); -} - -void rtl8225z4_rf_wakeup(struct net_device *dev) -{ - MgntActSet_RF_State(dev, RF_ON, RF_CHANGE_BY_PS); -} diff --git a/drivers/staging/rtl8187se/r8180_wx.c b/drivers/staging/rtl8187se/r8180_wx.c deleted file mode 100644 index b55249170f1..00000000000 --- a/drivers/staging/rtl8187se/r8180_wx.c +++ /dev/null @@ -1,1409 +0,0 @@ -/* - This file contains wireless extension handlers. - - This is part of rtl8180 OpenSource driver. - Copyright (C) Andrea Merello 2004-2005 - Released under the terms of GPL (General Public Licence) - - Parts of this driver are based on the GPL part - of the official realtek driver. - - Parts of this driver are based on the rtl8180 driver skeleton - from Patric Schenke & Andres Salomon. - - Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver. - - We want to thanks the Authors of those projects and the Ndiswrapper - project Authors. -*/ - - -#include "r8180.h" -#include "r8180_hw.h" - -#include -#include "ieee80211/dot11d.h" - -static u32 rtl8180_rates[] = {1000000, 2000000, 5500000, 11000000, - 6000000, 9000000, 12000000, 18000000, 24000000, 36000000, 48000000, 54000000}; - -#define RATE_COUNT ARRAY_SIZE(rtl8180_rates) - -static struct rtl8187se_channel_list default_channel_plan[] = { - {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 36, 40, 44, 48, 52, 56, 60, 64}, 19}, /* FCC */ - {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 11}, /* IC */ - {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 36, 40, 44, 48, 52, 56, 60, 64}, 21}, /* ETSI */ - {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 36, 40, 44, 48, 52, 56, 60, 64}, 21}, /* Spain. Change to ETSI. */ - {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 36, 40, 44, 48, 52, 56, 60, 64}, 21}, /* France. Change to ETSI. */ - {{14, 36, 40, 44, 48, 52, 56, 60, 64}, 9}, /* MKK */ - {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 36, 40, 44, 48, 52, 56, 60, 64}, 22}, /* MKK1 */ - {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 36, 40, 44, 48, 52, 56, 60, 64}, 21}, /* Israel */ - {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 34, 38, 42, 46}, 17}, /* For 11a , TELEC */ - {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}, 14} /* For Global Domain. 1-11:active scan, 12-14 passive scan.*/ /* +YJ, 080626 */ -}; -static int r8180_wx_get_freq(struct net_device *dev, - struct iw_request_info *a, - union iwreq_data *wrqu, char *b) -{ - struct r8180_priv *priv = ieee80211_priv(dev); - - return ieee80211_wx_get_freq(priv->ieee80211, a, wrqu, b); -} - - -static int r8180_wx_set_key(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *key) -{ - struct r8180_priv *priv = ieee80211_priv(dev); - struct iw_point *erq = &(wrqu->encoding); - - if (priv->ieee80211->bHwRadioOff) - return 0; - - if (erq->length > 0) { - u32 *tkey = (u32 *) key; - priv->key0[0] = tkey[0]; - priv->key0[1] = tkey[1]; - priv->key0[2] = tkey[2]; - priv->key0[3] = tkey[3] & 0xff; - DMESG("Setting wep key to %x %x %x %x", - tkey[0], tkey[1], tkey[2], tkey[3]); - rtl8180_set_hw_wep(dev); - } - return 0; -} - - -static int r8180_wx_set_beaconinterval(struct net_device *dev, - struct iw_request_info *aa, - union iwreq_data *wrqu, char *b) -{ - int *parms = (int *)b; - int bi = parms[0]; - - struct r8180_priv *priv = ieee80211_priv(dev); - - if (priv->ieee80211->bHwRadioOff) - return 0; - - down(&priv->wx_sem); - DMESG("setting beacon interval to %x", bi); - - priv->ieee80211->current_network.beacon_interval = bi; - rtl8180_commit(dev); - up(&priv->wx_sem); - - return 0; -} - - - -static int r8180_wx_get_mode(struct net_device *dev, struct iw_request_info *a, - union iwreq_data *wrqu, char *b) -{ - struct r8180_priv *priv = ieee80211_priv(dev); - return ieee80211_wx_get_mode(priv->ieee80211, a, wrqu, b); -} - - - -static int r8180_wx_get_rate(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct r8180_priv *priv = ieee80211_priv(dev); - return ieee80211_wx_get_rate(priv->ieee80211, info, wrqu, extra); -} - - - -static int r8180_wx_set_rate(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - int ret; - struct r8180_priv *priv = ieee80211_priv(dev); - - - if (priv->ieee80211->bHwRadioOff) - return 0; - - down(&priv->wx_sem); - - ret = ieee80211_wx_set_rate(priv->ieee80211, info, wrqu, extra); - - up(&priv->wx_sem); - - return ret; -} - - -static int r8180_wx_set_crcmon(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct r8180_priv *priv = ieee80211_priv(dev); - int *parms = (int *)extra; - int enable = (parms[0] > 0); - short prev = priv->crcmon; - - - if (priv->ieee80211->bHwRadioOff) - return 0; - - down(&priv->wx_sem); - - if (enable) - priv->crcmon = 1; - else - priv->crcmon = 0; - - DMESG("bad CRC in monitor mode are %s", - priv->crcmon ? "accepted" : "rejected"); - - if (prev != priv->crcmon && priv->up) { - rtl8180_down(dev); - rtl8180_up(dev); - } - - up(&priv->wx_sem); - - return 0; -} - - -static int r8180_wx_set_mode(struct net_device *dev, struct iw_request_info *a, - union iwreq_data *wrqu, char *b) -{ - struct r8180_priv *priv = ieee80211_priv(dev); - int ret; - - - if (priv->ieee80211->bHwRadioOff) - return 0; - - down(&priv->wx_sem); - if (priv->bInactivePs) { - if (wrqu->mode == IW_MODE_ADHOC) - IPSLeave(dev); - } - ret = ieee80211_wx_set_mode(priv->ieee80211, a, wrqu, b); - - up(&priv->wx_sem); - return ret; -} - -/* YJ,add,080819,for hidden ap */ -struct iw_range_with_scan_capa { - /* Informative stuff (to choose between different interface) */ - - __u32 throughput; /* To give an idea... */ - - /* In theory this value should be the maximum benchmarked - * TCP/IP throughput, because with most of these devices the - * bit rate is meaningless (overhead an co) to estimate how - * fast the connection will go and pick the fastest one. - * I suggest people to play with Netperf or any benchmark... - */ - - /* NWID (or domain id) */ - __u32 min_nwid; /* Minimal NWID we are able to set */ - __u32 max_nwid; /* Maximal NWID we are able to set */ - - /* Old Frequency (backward compat - moved lower ) */ - __u16 old_num_channels; - __u8 old_num_frequency; - - /* Scan capabilities */ - __u8 scan_capa; -}; -/* YJ,add,080819,for hidden ap */ - - -static int rtl8180_wx_get_range(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct iw_range *range = (struct iw_range *)extra; - struct r8180_priv *priv = ieee80211_priv(dev); - u16 val; - int i; - - wrqu->data.length = sizeof(*range); - memset(range, 0, sizeof(*range)); - - /* Let's try to keep this struct in the same order as in - * linux/include/wireless.h - */ - - /* TODO: See what values we can set, and remove the ones we can't - * set, or fill them with some default data. - */ - - /* ~5 Mb/s real (802.11b) */ - range->throughput = 5 * 1000 * 1000; - - /* TODO: Not used in 802.11b? */ -/* range->min_nwid; */ /* Minimal NWID we are able to set */ - /* TODO: Not used in 802.11b? */ -/* range->max_nwid; */ /* Maximal NWID we are able to set */ - - /* Old Frequency (backward compat - moved lower ) */ -/* range->old_num_channels; */ -/* range->old_num_frequency; */ -/* range->old_freq[6]; */ /* Filler to keep "version" at the same offset */ - if (priv->rf_set_sens != NULL) - range->sensitivity = priv->max_sens; /* signal level threshold range */ - - range->max_qual.qual = 100; - /* TODO: Find real max RSSI and stick here */ - range->max_qual.level = 0; - range->max_qual.noise = -98; - range->max_qual.updated = 7; /* Updated all three */ - - range->avg_qual.qual = 92; /* > 8% missed beacons is 'bad' */ - /* TODO: Find real 'good' to 'bad' threshold value for RSSI */ - range->avg_qual.level = 20 + -98; - range->avg_qual.noise = 0; - range->avg_qual.updated = 7; /* Updated all three */ - - range->num_bitrates = RATE_COUNT; - - for (i = 0; i < RATE_COUNT && i < IW_MAX_BITRATES; i++) - range->bitrate[i] = rtl8180_rates[i]; - - range->min_frag = MIN_FRAG_THRESHOLD; - range->max_frag = MAX_FRAG_THRESHOLD; - - range->pm_capa = 0; - - range->we_version_compiled = WIRELESS_EXT; - range->we_version_source = 16; - - range->num_channels = 14; - - for (i = 0, val = 0; i < 14; i++) { - - /* Include only legal frequencies for some countries */ - if ((GET_DOT11D_INFO(priv->ieee80211)->channel_map)[i+1]) { - range->freq[val].i = i + 1; - range->freq[val].m = ieee80211_wlan_frequencies[i] * 100000; - range->freq[val].e = 1; - val++; - } else { - /* FIXME: do we need to set anything for channels */ - /* we don't use ? */ - } - - if (val == IW_MAX_FREQUENCIES) - break; - } - - range->num_frequency = val; - range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | - IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; - - return 0; -} - - -static int r8180_wx_set_scan(struct net_device *dev, struct iw_request_info *a, - union iwreq_data *wrqu, char *b) -{ - struct r8180_priv *priv = ieee80211_priv(dev); - int ret; - struct ieee80211_device *ieee = priv->ieee80211; - - - if (priv->ieee80211->bHwRadioOff) - return 0; - - if (wrqu->data.flags & IW_SCAN_THIS_ESSID) { - struct iw_scan_req *req = (struct iw_scan_req *)b; - if (req->essid_len) { - ieee->current_network.ssid_len = req->essid_len; - memcpy(ieee->current_network.ssid, req->essid, req->essid_len); - } - } - - down(&priv->wx_sem); - if (priv->up) { - priv->ieee80211->actscanning = true; - if (priv->bInactivePs && (priv->ieee80211->state != IEEE80211_LINKED)) { - IPSLeave(dev); - ieee80211_softmac_ips_scan_syncro(priv->ieee80211); - ret = 0; - } else { - /* prevent scan in BusyTraffic */ - /* FIXME: Need to consider last scan time */ - if ((priv->link_detect.b_busy_traffic) && (true)) { - ret = 0; - printk("Now traffic is busy, please try later!\n"); - } else - /* prevent scan in BusyTraffic,end */ - ret = ieee80211_wx_set_scan(priv->ieee80211, a, wrqu, b); - } - } else - ret = -1; - - up(&priv->wx_sem); - - return ret; -} - - -static int r8180_wx_get_scan(struct net_device *dev, struct iw_request_info *a, - union iwreq_data *wrqu, char *b) -{ - - int ret; - struct r8180_priv *priv = ieee80211_priv(dev); - - down(&priv->wx_sem); - if (priv->up) - ret = ieee80211_wx_get_scan(priv->ieee80211, a, wrqu, b); - else - ret = -1; - - up(&priv->wx_sem); - return ret; -} - - -static int r8180_wx_set_essid(struct net_device *dev, - struct iw_request_info *a, - union iwreq_data *wrqu, char *b) -{ - struct r8180_priv *priv = ieee80211_priv(dev); - - int ret; - - if (priv->ieee80211->bHwRadioOff) - return 0; - - down(&priv->wx_sem); - if (priv->bInactivePs) - IPSLeave(dev); - - ret = ieee80211_wx_set_essid(priv->ieee80211, a, wrqu, b); - - up(&priv->wx_sem); - return ret; -} - - -static int r8180_wx_get_essid(struct net_device *dev, - struct iw_request_info *a, - union iwreq_data *wrqu, char *b) -{ - int ret; - struct r8180_priv *priv = ieee80211_priv(dev); - - down(&priv->wx_sem); - - ret = ieee80211_wx_get_essid(priv->ieee80211, a, wrqu, b); - - up(&priv->wx_sem); - - return ret; -} - - -static int r8180_wx_set_freq(struct net_device *dev, struct iw_request_info *a, - union iwreq_data *wrqu, char *b) -{ - int ret; - struct r8180_priv *priv = ieee80211_priv(dev); - - - if (priv->ieee80211->bHwRadioOff) - return 0; - - down(&priv->wx_sem); - - ret = ieee80211_wx_set_freq(priv->ieee80211, a, wrqu, b); - - up(&priv->wx_sem); - return ret; -} - - -static int r8180_wx_get_name(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct r8180_priv *priv = ieee80211_priv(dev); - return ieee80211_wx_get_name(priv->ieee80211, info, wrqu, extra); -} - -static int r8180_wx_set_frag(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct r8180_priv *priv = ieee80211_priv(dev); - - if (priv->ieee80211->bHwRadioOff) - return 0; - - if (wrqu->frag.disabled) - priv->ieee80211->fts = DEFAULT_FRAG_THRESHOLD; - else { - if (wrqu->frag.value < MIN_FRAG_THRESHOLD || - wrqu->frag.value > MAX_FRAG_THRESHOLD) - return -EINVAL; - - priv->ieee80211->fts = wrqu->frag.value & ~0x1; - } - - return 0; -} - - -static int r8180_wx_get_frag(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct r8180_priv *priv = ieee80211_priv(dev); - - wrqu->frag.value = priv->ieee80211->fts; - wrqu->frag.fixed = 0; /* no auto select */ - wrqu->frag.disabled = (wrqu->frag.value == DEFAULT_FRAG_THRESHOLD); - - return 0; -} - - -static int r8180_wx_set_wap(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *awrq, char *extra) -{ - int ret; - struct r8180_priv *priv = ieee80211_priv(dev); - - if (priv->ieee80211->bHwRadioOff) - return 0; - - down(&priv->wx_sem); - - ret = ieee80211_wx_set_wap(priv->ieee80211, info, awrq, extra); - - up(&priv->wx_sem); - return ret; - -} - - -static int r8180_wx_get_wap(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct r8180_priv *priv = ieee80211_priv(dev); - - return ieee80211_wx_get_wap(priv->ieee80211, info, wrqu, extra); -} - - -static int r8180_wx_set_enc(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *key) -{ - struct r8180_priv *priv = ieee80211_priv(dev); - int ret; - - if (priv->ieee80211->bHwRadioOff) - return 0; - - - down(&priv->wx_sem); - - if (priv->hw_wep) - ret = r8180_wx_set_key(dev, info, wrqu, key); - else { - DMESG("Setting SW wep key"); - ret = ieee80211_wx_set_encode(priv->ieee80211, info, wrqu, key); - } - - up(&priv->wx_sem); - return ret; -} - - -static int r8180_wx_get_enc(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *key) -{ - struct r8180_priv *priv = ieee80211_priv(dev); - - return ieee80211_wx_get_encode(priv->ieee80211, info, wrqu, key); -} - - -static int r8180_wx_set_scan_type(struct net_device *dev, - struct iw_request_info *aa, - union iwreq_data *wrqu, char *p) -{ - - struct r8180_priv *priv = ieee80211_priv(dev); - int *parms = (int *)p; - int mode = parms[0]; - - if (priv->ieee80211->bHwRadioOff) - return 0; - - priv->ieee80211->active_scan = mode; - - return 1; -} - -static int r8180_wx_set_retry(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct r8180_priv *priv = ieee80211_priv(dev); - int err = 0; - - if (priv->ieee80211->bHwRadioOff) - return 0; - - down(&priv->wx_sem); - - if (wrqu->retry.flags & IW_RETRY_LIFETIME || - wrqu->retry.disabled) { - err = -EINVAL; - goto exit; - } - if (!(wrqu->retry.flags & IW_RETRY_LIMIT)) { - err = -EINVAL; - goto exit; - } - - if (wrqu->retry.value > R8180_MAX_RETRY) { - err = -EINVAL; - goto exit; - } - if (wrqu->retry.flags & IW_RETRY_MAX) { - priv->retry_rts = wrqu->retry.value; - DMESG("Setting retry for RTS/CTS data to %d", wrqu->retry.value); - - } else { - priv->retry_data = wrqu->retry.value; - DMESG("Setting retry for non RTS/CTS data to %d", wrqu->retry.value); - } - - /* FIXME ! - * We might try to write directly the TX config register - * or to restart just the (R)TX process. - * I'm unsure if whole reset is really needed - */ - - rtl8180_commit(dev); -exit: - up(&priv->wx_sem); - - return err; -} - -static int r8180_wx_get_retry(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct r8180_priv *priv = ieee80211_priv(dev); - - - wrqu->retry.disabled = 0; /* can't be disabled */ - - if ((wrqu->retry.flags & IW_RETRY_TYPE) == - IW_RETRY_LIFETIME) - return -EINVAL; - - if (wrqu->retry.flags & IW_RETRY_MAX) { - wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MAX; - wrqu->retry.value = priv->retry_rts; - } else { - wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MIN; - wrqu->retry.value = priv->retry_data; - } - - return 0; -} - -static int r8180_wx_get_sens(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct r8180_priv *priv = ieee80211_priv(dev); - if (priv->rf_set_sens == NULL) - return -1; /* we have not this support for this radio */ - wrqu->sens.value = priv->sens; - return 0; -} - - -static int r8180_wx_set_sens(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - - struct r8180_priv *priv = ieee80211_priv(dev); - - short err = 0; - - if (priv->ieee80211->bHwRadioOff) - return 0; - - down(&priv->wx_sem); - if (priv->rf_set_sens == NULL) { - err = -1; /* we have not this support for this radio */ - goto exit; - } - if (priv->rf_set_sens(dev, wrqu->sens.value) == 0) - priv->sens = wrqu->sens.value; - else - err = -EINVAL; - -exit: - up(&priv->wx_sem); - - return err; -} - - -static int r8180_wx_set_rawtx(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct r8180_priv *priv = ieee80211_priv(dev); - int ret; - - if (priv->ieee80211->bHwRadioOff) - return 0; - - down(&priv->wx_sem); - - ret = ieee80211_wx_set_rawtx(priv->ieee80211, info, wrqu, extra); - - up(&priv->wx_sem); - - return ret; - -} - -static int r8180_wx_get_power(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - int ret; - struct r8180_priv *priv = ieee80211_priv(dev); - - down(&priv->wx_sem); - - ret = ieee80211_wx_get_power(priv->ieee80211, info, wrqu, extra); - - up(&priv->wx_sem); - - return ret; -} - -static int r8180_wx_set_power(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - int ret; - struct r8180_priv *priv = ieee80211_priv(dev); - - - if (priv->ieee80211->bHwRadioOff) - return 0; - - down(&priv->wx_sem); - printk("=>>>>>>>>>>=============================>set power:%d, %d!\n", wrqu->power.disabled, wrqu->power.flags); - if (wrqu->power.disabled == 0) { - wrqu->power.flags |= IW_POWER_ALL_R; - wrqu->power.flags |= IW_POWER_TIMEOUT; - wrqu->power.value = 1000; - } - - ret = ieee80211_wx_set_power(priv->ieee80211, info, wrqu, extra); - - up(&priv->wx_sem); - - return ret; -} - -static int r8180_wx_set_rts(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct r8180_priv *priv = ieee80211_priv(dev); - - - if (priv->ieee80211->bHwRadioOff) - return 0; - - if (wrqu->rts.disabled) - priv->rts = DEFAULT_RTS_THRESHOLD; - else { - if (wrqu->rts.value < MIN_RTS_THRESHOLD || - wrqu->rts.value > MAX_RTS_THRESHOLD) - return -EINVAL; - - priv->rts = wrqu->rts.value; - } - - return 0; -} -static int r8180_wx_get_rts(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct r8180_priv *priv = ieee80211_priv(dev); - - - - wrqu->rts.value = priv->rts; - wrqu->rts.fixed = 0; /* no auto select */ - wrqu->rts.disabled = (wrqu->rts.value == 0); - - return 0; -} -static int dummy(struct net_device *dev, struct iw_request_info *a, - union iwreq_data *wrqu, char *b) -{ - return -1; -} - -static int r8180_wx_get_iwmode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct r8180_priv *priv = ieee80211_priv(dev); - struct ieee80211_device *ieee; - int ret = 0; - - - - down(&priv->wx_sem); - - ieee = priv->ieee80211; - - strcpy(extra, "802.11"); - if (ieee->modulation & IEEE80211_CCK_MODULATION) { - strcat(extra, "b"); - if (ieee->modulation & IEEE80211_OFDM_MODULATION) - strcat(extra, "/g"); - } else if (ieee->modulation & IEEE80211_OFDM_MODULATION) - strcat(extra, "g"); - - up(&priv->wx_sem); - - return ret; -} -static int r8180_wx_set_iwmode(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct r8180_priv *priv = ieee80211_priv(dev); - struct ieee80211_device *ieee = priv->ieee80211; - int *param = (int *)extra; - int ret = 0; - int modulation = 0, mode = 0; - - - if (priv->ieee80211->bHwRadioOff) - return 0; - - down(&priv->wx_sem); - - if (*param == 1) { - modulation |= IEEE80211_CCK_MODULATION; - mode = IEEE_B; - printk(KERN_INFO "B mode!\n"); - } else if (*param == 2) { - modulation |= IEEE80211_OFDM_MODULATION; - mode = IEEE_G; - printk(KERN_INFO "G mode!\n"); - } else if (*param == 3) { - modulation |= IEEE80211_CCK_MODULATION; - modulation |= IEEE80211_OFDM_MODULATION; - mode = IEEE_B|IEEE_G; - printk(KERN_INFO "B/G mode!\n"); - } - - if (ieee->proto_started) { - ieee80211_stop_protocol(ieee); - ieee->mode = mode; - ieee->modulation = modulation; - ieee80211_start_protocol(ieee); - } else { - ieee->mode = mode; - ieee->modulation = modulation; - } - - up(&priv->wx_sem); - - return ret; -} -static int r8180_wx_get_preamble(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct r8180_priv *priv = ieee80211_priv(dev); - - - - down(&priv->wx_sem); - - - - *extra = (char) priv->plcp_preamble_mode; /* 0:auto 1:short 2:long */ - up(&priv->wx_sem); - - return 0; -} -static int r8180_wx_set_preamble(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct r8180_priv *priv = ieee80211_priv(dev); - int ret = 0; - - - if (priv->ieee80211->bHwRadioOff) - return 0; - - down(&priv->wx_sem); - if (*extra < 0 || *extra > 2) - ret = -1; - else - priv->plcp_preamble_mode = *((short *)extra); - - - - up(&priv->wx_sem); - - return ret; -} -static int r8180_wx_get_siglevel(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct r8180_priv *priv = ieee80211_priv(dev); - int ret = 0; - - - - down(&priv->wx_sem); - /* Modify by hikaru 6.5 */ - *((int *)extra) = priv->wstats.qual.level;/*for interface test ,it should be the priv->wstats.qual.level; */ - - - - up(&priv->wx_sem); - - return ret; -} -static int r8180_wx_get_sigqual(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct r8180_priv *priv = ieee80211_priv(dev); - int ret = 0; - - - - down(&priv->wx_sem); - /* Modify by hikaru 6.5 */ - *((int *)extra) = priv->wstats.qual.qual;/* for interface test ,it should be the priv->wstats.qual.qual; */ - - - - up(&priv->wx_sem); - - return ret; -} -static int r8180_wx_reset_stats(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct r8180_priv *priv = ieee80211_priv(dev); - down(&priv->wx_sem); - - priv->stats.txrdu = 0; - priv->stats.rxrdu = 0; - priv->stats.rxnolast = 0; - priv->stats.rxnodata = 0; - priv->stats.rxnopointer = 0; - priv->stats.txnperr = 0; - priv->stats.txresumed = 0; - priv->stats.rxerr = 0; - priv->stats.rxoverflow = 0; - priv->stats.rxint = 0; - - priv->stats.txnpokint = 0; - priv->stats.txhpokint = 0; - priv->stats.txhperr = 0; - priv->stats.ints = 0; - priv->stats.shints = 0; - priv->stats.txoverflow = 0; - priv->stats.rxdmafail = 0; - priv->stats.txbeacon = 0; - priv->stats.txbeaconerr = 0; - priv->stats.txlpokint = 0; - priv->stats.txlperr = 0; - priv->stats.txretry = 0;/* 20060601 */ - priv->stats.rxcrcerrmin = 0 ; - priv->stats.rxcrcerrmid = 0; - priv->stats.rxcrcerrmax = 0; - priv->stats.rxicverr = 0; - - up(&priv->wx_sem); - - return 0; - -} -static int r8180_wx_radio_on(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct r8180_priv *priv = ieee80211_priv(dev); - - if (priv->ieee80211->bHwRadioOff) - return 0; - - - down(&priv->wx_sem); - priv->rf_wakeup(dev); - - up(&priv->wx_sem); - - return 0; - -} - -static int r8180_wx_radio_off(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct r8180_priv *priv = ieee80211_priv(dev); - - if (priv->ieee80211->bHwRadioOff) - return 0; - - - down(&priv->wx_sem); - priv->rf_sleep(dev); - - up(&priv->wx_sem); - - return 0; - -} -static int r8180_wx_get_channelplan(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct r8180_priv *priv = ieee80211_priv(dev); - - - - down(&priv->wx_sem); - *extra = priv->channel_plan; - - - - up(&priv->wx_sem); - - return 0; -} -static int r8180_wx_set_channelplan(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct r8180_priv *priv = ieee80211_priv(dev); - int *val = (int *)extra; - int i; - printk("-----in fun %s\n", __func__); - - if (priv->ieee80211->bHwRadioOff) - return 0; - - /* unsigned long flags; */ - down(&priv->wx_sem); - if (default_channel_plan[*val].len != 0) { - priv->channel_plan = *val; - /* Clear old channel map 8 */ - for (i = 1; i <= MAX_CHANNEL_NUMBER; i++) - GET_DOT11D_INFO(priv->ieee80211)->channel_map[i] = 0; - - /* Set new channel map */ - for (i = 1; i <= default_channel_plan[*val].len; i++) - GET_DOT11D_INFO(priv->ieee80211)->channel_map[default_channel_plan[*val].channel[i-1]] = 1; - - } - up(&priv->wx_sem); - - return 0; -} - -static int r8180_wx_get_version(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct r8180_priv *priv = ieee80211_priv(dev); - /* struct ieee80211_device *ieee; */ - - down(&priv->wx_sem); - strcpy(extra, "1020.0808"); - up(&priv->wx_sem); - - return 0; -} - -/* added by amy 080818 */ -/*receive datarate from user typing valid rate is from 2 to 108 (1 - 54M), if input 0, return to normal rate adaptive. */ -static int r8180_wx_set_forcerate(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct r8180_priv *priv = ieee80211_priv(dev); - u8 forcerate = *extra; - - down(&priv->wx_sem); - - printk("==============>%s(): forcerate is %d\n", __func__, forcerate); - if ((forcerate == 2) || (forcerate == 4) || (forcerate == 11) || (forcerate == 22) || (forcerate == 12) || - (forcerate == 18) || (forcerate == 24) || (forcerate == 36) || (forcerate == 48) || (forcerate == 72) || - (forcerate == 96) || (forcerate == 108)) { - priv->ForcedDataRate = 1; - priv->ieee80211->rate = forcerate * 5; - } else if (forcerate == 0) { - priv->ForcedDataRate = 0; - printk("OK! return rate adaptive\n"); - } else - printk("ERR: wrong rate\n"); - up(&priv->wx_sem); - return 0; -} - -static int r8180_wx_set_enc_ext(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - - struct r8180_priv *priv = ieee80211_priv(dev); - - int ret = 0; - - if (priv->ieee80211->bHwRadioOff) - return 0; - - down(&priv->wx_sem); - ret = ieee80211_wx_set_encode_ext(priv->ieee80211, info, wrqu, extra); - up(&priv->wx_sem); - return ret; - -} -static int r8180_wx_set_auth(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct r8180_priv *priv = ieee80211_priv(dev); - int ret = 0; - - if (priv->ieee80211->bHwRadioOff) - return 0; - - down(&priv->wx_sem); - ret = ieee80211_wx_set_auth(priv->ieee80211, info, &wrqu->param, extra); - up(&priv->wx_sem); - return ret; -} - -static int r8180_wx_set_mlme(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - int ret = 0; - struct r8180_priv *priv = ieee80211_priv(dev); - - - if (priv->ieee80211->bHwRadioOff) - return 0; - - - down(&priv->wx_sem); -#if 1 - ret = ieee80211_wx_set_mlme(priv->ieee80211, info, wrqu, extra); -#endif - up(&priv->wx_sem); - return ret; -} -static int r8180_wx_set_gen_ie(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - int ret = 0; - struct r8180_priv *priv = ieee80211_priv(dev); - - - if (priv->ieee80211->bHwRadioOff) - return 0; - - down(&priv->wx_sem); -#if 1 - ret = ieee80211_wx_set_gen_ie(priv->ieee80211, extra, wrqu->data.length); -#endif - up(&priv->wx_sem); - return ret; - - -} - -static const iw_handler r8180_wx_handlers[] = { - IW_HANDLER(SIOCGIWNAME, r8180_wx_get_name), - IW_HANDLER(SIOCSIWNWID, dummy), - IW_HANDLER(SIOCGIWNWID, dummy), - IW_HANDLER(SIOCSIWFREQ, r8180_wx_set_freq), - IW_HANDLER(SIOCGIWFREQ, r8180_wx_get_freq), - IW_HANDLER(SIOCSIWMODE, r8180_wx_set_mode), - IW_HANDLER(SIOCGIWMODE, r8180_wx_get_mode), - IW_HANDLER(SIOCSIWSENS, r8180_wx_set_sens), - IW_HANDLER(SIOCGIWSENS, r8180_wx_get_sens), - IW_HANDLER(SIOCGIWRANGE, rtl8180_wx_get_range), - IW_HANDLER(SIOCSIWSPY, dummy), - IW_HANDLER(SIOCGIWSPY, dummy), - IW_HANDLER(SIOCSIWAP, r8180_wx_set_wap), - IW_HANDLER(SIOCGIWAP, r8180_wx_get_wap), - IW_HANDLER(SIOCSIWMLME, r8180_wx_set_mlme), - IW_HANDLER(SIOCGIWAPLIST, dummy), /* deprecated */ - IW_HANDLER(SIOCSIWSCAN, r8180_wx_set_scan), - IW_HANDLER(SIOCGIWSCAN, r8180_wx_get_scan), - IW_HANDLER(SIOCSIWESSID, r8180_wx_set_essid), - IW_HANDLER(SIOCGIWESSID, r8180_wx_get_essid), - IW_HANDLER(SIOCSIWNICKN, dummy), - IW_HANDLER(SIOCGIWNICKN, dummy), - IW_HANDLER(SIOCSIWRATE, r8180_wx_set_rate), - IW_HANDLER(SIOCGIWRATE, r8180_wx_get_rate), - IW_HANDLER(SIOCSIWRTS, r8180_wx_set_rts), - IW_HANDLER(SIOCGIWRTS, r8180_wx_get_rts), - IW_HANDLER(SIOCSIWFRAG, r8180_wx_set_frag), - IW_HANDLER(SIOCGIWFRAG, r8180_wx_get_frag), - IW_HANDLER(SIOCSIWTXPOW, dummy), - IW_HANDLER(SIOCGIWTXPOW, dummy), - IW_HANDLER(SIOCSIWRETRY, r8180_wx_set_retry), - IW_HANDLER(SIOCGIWRETRY, r8180_wx_get_retry), - IW_HANDLER(SIOCSIWENCODE, r8180_wx_set_enc), - IW_HANDLER(SIOCGIWENCODE, r8180_wx_get_enc), - IW_HANDLER(SIOCSIWPOWER, r8180_wx_set_power), - IW_HANDLER(SIOCGIWPOWER, r8180_wx_get_power), - IW_HANDLER(SIOCSIWGENIE, r8180_wx_set_gen_ie), - IW_HANDLER(SIOCSIWAUTH, r8180_wx_set_auth), - IW_HANDLER(SIOCSIWENCODEEXT, r8180_wx_set_enc_ext), -}; - -static const struct iw_priv_args r8180_private_args[] = { - { - SIOCIWFIRSTPRIV + 0x0, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "badcrc" - }, - { SIOCIWFIRSTPRIV + 0x1, - 0, 0, "dummy" - - }, - { - SIOCIWFIRSTPRIV + 0x2, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "beaconint" - }, - { SIOCIWFIRSTPRIV + 0x3, - 0, 0, "dummy" - - }, - { - SIOCIWFIRSTPRIV + 0x4, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "activescan" - - }, - { SIOCIWFIRSTPRIV + 0x5, - 0, 0, "dummy" - - }, - { - SIOCIWFIRSTPRIV + 0x6, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "rawtx" - - }, - { SIOCIWFIRSTPRIV + 0x7, - 0, 0, "dummy" - - }, - { - SIOCIWFIRSTPRIV + 0x8, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "setiwmode" - }, - { - SIOCIWFIRSTPRIV + 0x9, - 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 32, "getiwmode" - }, - { - SIOCIWFIRSTPRIV + 0xA, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "setpreamble" - }, - { - SIOCIWFIRSTPRIV + 0xB, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getpreamble" - }, - { SIOCIWFIRSTPRIV + 0xC, - 0, 0, "dummy" - }, - { - SIOCIWFIRSTPRIV + 0xD, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getrssi" - }, - { SIOCIWFIRSTPRIV + 0xE, - 0, 0, "dummy" - }, - { - SIOCIWFIRSTPRIV + 0xF, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getlinkqual" - }, - { - SIOCIWFIRSTPRIV + 0x10, - 0, 0, "resetstats" - }, - { - SIOCIWFIRSTPRIV + 0x11, - 0, 0, "dummy" - }, - { - SIOCIWFIRSTPRIV + 0x12, - 0, 0, "radioon" - }, - { - SIOCIWFIRSTPRIV + 0x13, - 0, 0, "radiooff" - }, - { - SIOCIWFIRSTPRIV + 0x14, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "setchannel" - }, - { - SIOCIWFIRSTPRIV + 0x15, - 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getchannel" - }, - { - SIOCIWFIRSTPRIV + 0x16, - 0, 0, "dummy" - }, - { - SIOCIWFIRSTPRIV + 0x17, - 0, IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 32, "getversion" - }, - { - SIOCIWFIRSTPRIV + 0x18, - IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "setrate" - }, -}; - - -static iw_handler r8180_private_handler[] = { - r8180_wx_set_crcmon, /*SIOCIWSECONDPRIV*/ - dummy, - r8180_wx_set_beaconinterval, - dummy, - /* r8180_wx_set_monitor_type, */ - r8180_wx_set_scan_type, - dummy, - r8180_wx_set_rawtx, - dummy, - r8180_wx_set_iwmode, - r8180_wx_get_iwmode, - r8180_wx_set_preamble, - r8180_wx_get_preamble, - dummy, - r8180_wx_get_siglevel, - dummy, - r8180_wx_get_sigqual, - r8180_wx_reset_stats, - dummy,/* r8180_wx_get_stats */ - r8180_wx_radio_on, - r8180_wx_radio_off, - r8180_wx_set_channelplan, - r8180_wx_get_channelplan, - dummy, - r8180_wx_get_version, - r8180_wx_set_forcerate, -}; - -static inline int is_same_network(struct ieee80211_network *src, - struct ieee80211_network *dst, - struct ieee80211_device *ieee) -{ - /* A network is only a duplicate if the channel, BSSID, ESSID - * and the capability field (in particular IBSS and BSS) all match. - * We treat all with the same BSSID and channel - * as one network - */ - if (src->channel != dst->channel) - return 0; - - if (memcmp(src->bssid, dst->bssid, ETH_ALEN) != 0) - return 0; - - if (ieee->iw_mode != IW_MODE_INFRA) { - if (src->ssid_len != dst->ssid_len) - return 0; - if (memcmp(src->ssid, dst->ssid, src->ssid_len) != 0) - return 0; - } - - if ((src->capability & WLAN_CAPABILITY_IBSS) != - (dst->capability & WLAN_CAPABILITY_IBSS)) - return 0; - if ((src->capability & WLAN_CAPABILITY_BSS) != - (dst->capability & WLAN_CAPABILITY_BSS)) - return 0; - - return 1; -} - -/* WB modified to show signal to GUI on 18-01-2008 */ -static struct iw_statistics *r8180_get_wireless_stats(struct net_device *dev) -{ - struct r8180_priv *priv = ieee80211_priv(dev); - struct ieee80211_device *ieee = priv->ieee80211; - struct iw_statistics *wstats = &priv->wstats; - int tmp_level = 0; - int tmp_qual = 0; - int tmp_noise = 0; - - if (ieee->state < IEEE80211_LINKED) { - wstats->qual.qual = 0; - wstats->qual.level = 0; - wstats->qual.noise = 0; - wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; - return wstats; - } - - tmp_level = (&ieee->current_network)->stats.signal; - tmp_qual = (&ieee->current_network)->stats.signalstrength; - tmp_noise = (&ieee->current_network)->stats.noise; - - wstats->qual.level = tmp_level; - wstats->qual.qual = tmp_qual; - wstats->qual.noise = tmp_noise; - wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; - return wstats; -} - -struct iw_handler_def r8180_wx_handlers_def = { - .standard = r8180_wx_handlers, - .num_standard = ARRAY_SIZE(r8180_wx_handlers), - .private = r8180_private_handler, - .num_private = ARRAY_SIZE(r8180_private_handler), - .num_private_args = sizeof(r8180_private_args) / sizeof(struct iw_priv_args), - .get_wireless_stats = r8180_get_wireless_stats, - .private_args = (struct iw_priv_args *)r8180_private_args, -}; - - diff --git a/drivers/staging/rtl8187se/r8180_wx.h b/drivers/staging/rtl8187se/r8180_wx.h deleted file mode 100644 index d471520ac77..00000000000 --- a/drivers/staging/rtl8187se/r8180_wx.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - This is part of rtl8180 OpenSource driver - v 0.3 - Copyright (C) Andrea Merello 2004 - Released under the terms of GPL (General Public Licence) - - Parts of this driver are based on the GPL part of the official realtek driver - Parts of this driver are based on the rtl8180 driver skeleton from Patric Schenke & Andres Salomon - Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver - - We want to thanks the Authors of such projects and the Ndiswrapper project Authors. -*/ - -/* this file (will) contains wireless extension handlers*/ - -#ifndef R8180_WX_H -#define R8180_WX_H -#include -#include "ieee80211/ieee80211.h" -extern struct iw_handler_def r8180_wx_handlers_def; - -#endif diff --git a/drivers/staging/rtl8187se/r8185b_init.c b/drivers/staging/rtl8187se/r8185b_init.c deleted file mode 100644 index cc6f100814f..00000000000 --- a/drivers/staging/rtl8187se/r8185b_init.c +++ /dev/null @@ -1,1464 +0,0 @@ -/* - * Copyright (c) Realtek Semiconductor Corp. All rights reserved. - * - * Module Name: - * r8185b_init.c - * - * Abstract: - * Hardware Initialization and Hardware IO for RTL8185B - * - * Major Change History: - * When Who What - * ---------- --------------- ------------------------------- - * 2006-11-15 Xiong Created - * - * Notes: - * This file is ported from RTL8185B Windows driver. - * - * - */ - -/*--------------------------Include File------------------------------------*/ -#include -#include "r8180_hw.h" -#include "r8180.h" -#include "r8180_rtl8225.h" /* RTL8225 Radio frontend */ -#include "r8180_93cx6.h" /* Card EEPROM */ -#include "r8180_wx.h" -#include "ieee80211/dot11d.h" -/* #define CONFIG_RTL8180_IO_MAP */ -#define TC_3W_POLL_MAX_TRY_CNT 5 - -static u8 MAC_REG_TABLE[][2] = { - /* - * PAGE 0: - * 0x34(BRSR), 0xBE(RATE_FALLBACK_CTL), 0x1E0(ARFR) would set in - * HwConfigureRTL8185() - * 0x272(RFSW_CTRL), 0x1CE(AESMSK_QC) set in InitializeAdapter8185(). - * 0x1F0~0x1F8 set in MacConfig_85BASIC() - */ - {0x08, 0xae}, {0x0a, 0x72}, {0x5b, 0x42}, - {0x84, 0x88}, {0x85, 0x24}, {0x88, 0x54}, {0x8b, 0xb8}, {0x8c, 0x03}, - {0x8d, 0x40}, {0x8e, 0x00}, {0x8f, 0x00}, {0x5b, 0x18}, {0x91, 0x03}, - {0x94, 0x0F}, {0x95, 0x32}, - {0x96, 0x00}, {0x97, 0x07}, {0xb4, 0x22}, {0xdb, 0x00}, - {0xf0, 0x32}, {0xf1, 0x32}, {0xf2, 0x00}, {0xf3, 0x00}, {0xf4, 0x32}, - {0xf5, 0x43}, {0xf6, 0x00}, {0xf7, 0x00}, {0xf8, 0x46}, {0xf9, 0xa4}, - {0xfa, 0x00}, {0xfb, 0x00}, {0xfc, 0x96}, {0xfd, 0xa4}, {0xfe, 0x00}, - {0xff, 0x00}, - - /* - * PAGE 1: - * For Flextronics system Logo PCIHCT failure: - * 0x1C4~0x1CD set no-zero value to avoid PCI configuration - * space 0x45[7]=1 - */ - {0x5e, 0x01}, - {0x58, 0x00}, {0x59, 0x00}, {0x5a, 0x04}, {0x5b, 0x00}, {0x60, 0x24}, - {0x61, 0x97}, {0x62, 0xF0}, {0x63, 0x09}, {0x80, 0x0F}, {0x81, 0xFF}, - {0x82, 0xFF}, {0x83, 0x03}, - /* lzm add 080826 */ - {0xC4, 0x22}, {0xC5, 0x22}, {0xC6, 0x22}, {0xC7, 0x22}, {0xC8, 0x22}, - /* lzm add 080826 */ - {0xC9, 0x22}, {0xCA, 0x22}, {0xCB, 0x22}, {0xCC, 0x22}, {0xCD, 0x22}, - {0xe2, 0x00}, - - - /* PAGE 2: */ - {0x5e, 0x02}, - {0x0c, 0x04}, {0x4c, 0x30}, {0x4d, 0x08}, {0x50, 0x05}, {0x51, 0xf5}, - {0x52, 0x04}, {0x53, 0xa0}, {0x54, 0xff}, {0x55, 0xff}, {0x56, 0xff}, - {0x57, 0xff}, {0x58, 0x08}, {0x59, 0x08}, {0x5a, 0x08}, {0x5b, 0x08}, - {0x60, 0x08}, {0x61, 0x08}, {0x62, 0x08}, {0x63, 0x08}, {0x64, 0x2f}, - {0x8c, 0x3f}, {0x8d, 0x3f}, {0x8e, 0x3f}, - {0x8f, 0x3f}, {0xc4, 0xff}, {0xc5, 0xff}, {0xc6, 0xff}, {0xc7, 0xff}, - {0xc8, 0x00}, {0xc9, 0x00}, {0xca, 0x80}, {0xcb, 0x00}, - - /* PAGE 0: */ - {0x5e, 0x00}, {0x9f, 0x03} - }; - - -static u8 ZEBRA_AGC[] = { - 0, - 0x7E, 0x7E, 0x7E, 0x7E, 0x7D, 0x7C, 0x7B, 0x7A, 0x79, 0x78, 0x77, 0x76, - 0x75, 0x74, 0x73, 0x72, 0x71, 0x70, 0x6F, 0x6E, 0x6D, 0x6C, 0x6B, 0x6A, - 0x69, 0x68, 0x67, 0x66, 0x65, 0x64, 0x63, 0x62, 0x48, 0x47, 0x46, 0x45, - 0x44, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x08, 0x07, - 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, - 0x0f, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x15, 0x16, 0x17, 0x17, 0x18, 0x18, - 0x19, 0x1a, 0x1a, 0x1b, 0x1b, 0x1c, 0x1c, 0x1d, 0x1d, 0x1d, 0x1e, 0x1e, - 0x1f, 0x1f, 0x1f, 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x21, 0x22, 0x22, - 0x22, 0x23, 0x23, 0x24, 0x24, 0x25, 0x25, 0x25, 0x26, 0x26, 0x27, 0x27, - 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F, 0x2F - }; - -static u32 ZEBRA_RF_RX_GAIN_TABLE[] = { - 0x0096, 0x0076, 0x0056, 0x0036, 0x0016, 0x01f6, 0x01d6, 0x01b6, - 0x0196, 0x0176, 0x00F7, 0x00D7, 0x00B7, 0x0097, 0x0077, 0x0057, - 0x0037, 0x00FB, 0x00DB, 0x00BB, 0x00FF, 0x00E3, 0x00C3, 0x00A3, - 0x0083, 0x0063, 0x0043, 0x0023, 0x0003, 0x01E3, 0x01C3, 0x01A3, - 0x0183, 0x0163, 0x0143, 0x0123, 0x0103 - }; - -static u8 OFDM_CONFIG[] = { - /* OFDM reg0x06[7:0]=0xFF: Enable power saving mode in RX */ - /* OFDM reg0x3C[4]=1'b1: Enable RX power saving mode */ - /* ofdm 0x3a = 0x7b ,(original : 0xfb) For ECS shielding room TP test */ - /* 0x00 */ - 0x10, 0x0F, 0x0A, 0x0C, 0x14, 0xFA, 0xFF, 0x50, - 0x00, 0x50, 0x00, 0x00, 0x00, 0x5C, 0x00, 0x00, - /* 0x10 */ - 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, 0xA8, 0x26, - 0x32, 0x33, 0x06, 0xA5, 0x6F, 0x55, 0xC8, 0xBB, - /* 0x20 */ - 0x0A, 0xE1, 0x2C, 0x4A, 0x86, 0x83, 0x34, 0x00, - 0x4F, 0x24, 0x6F, 0xC2, 0x03, 0x40, 0x80, 0x00, - /* 0x30 */ - 0xC0, 0xC1, 0x58, 0xF1, 0x00, 0xC4, 0x90, 0x3e, - 0xD8, 0x3C, 0x7B, 0x10, 0x10 - }; - - /*--------------------------------------------------------------- - * Hardware IO - * the code is ported from Windows source code - *--------------------------------------------------------------- - */ - -static u8 PlatformIORead1Byte(struct net_device *dev, u32 offset) -{ - return read_nic_byte(dev, offset); -} - -static void PlatformIOWrite1Byte(struct net_device *dev, u32 offset, u8 data) -{ - write_nic_byte(dev, offset, data); - /* - * To make sure write operation is completed, - * 2005.11.09, by rcnjko. - */ - read_nic_byte(dev, offset); -} - -static void PlatformIOWrite2Byte(struct net_device *dev, u32 offset, u16 data) -{ - write_nic_word(dev, offset, data); - /* - * To make sure write operation is completed, - * 2005.11.09, by rcnjko. - */ - read_nic_word(dev, offset); -} - -static void PlatformIOWrite4Byte(struct net_device *dev, u32 offset, u32 data) -{ - if (offset == PhyAddr) { - /* For Base Band configuration. */ - unsigned char cmdByte; - unsigned long dataBytes; - unsigned char idx; - u8 u1bTmp; - - cmdByte = (u8)(data & 0x000000ff); - dataBytes = data>>8; - - /* - * 071010, rcnjko: - * The critical section is only BB read/write race - * condition. Assumption: - * 1. We assume NO one will access BB at DIRQL, otherwise, - * system will crash for - * acquiring the spinlock in such context. - * 2. PlatformIOWrite4Byte() MUST NOT be recursive. - */ - /* NdisAcquireSpinLock( &(pDevice->IoSpinLock) ); */ - - for (idx = 0; idx < 30; idx++) { - /* Make sure command bit is clear before access it. */ - u1bTmp = PlatformIORead1Byte(dev, PhyAddr); - if ((u1bTmp & BIT7) == 0) - break; - else - mdelay(10); - } - - for (idx = 0; idx < 3; idx++) - PlatformIOWrite1Byte(dev, offset+1+idx, - ((u8 *)&dataBytes)[idx]); - - write_nic_byte(dev, offset, cmdByte); - - /* NdisReleaseSpinLock( &(pDevice->IoSpinLock) ); */ - } else { - write_nic_dword(dev, offset, data); - /* - * To make sure write operation is completed, 2005.11.09, - * by rcnjko. - */ - read_nic_dword(dev, offset); - } -} - -static void SetOutputEnableOfRfPins(struct net_device *dev) -{ - write_nic_word(dev, RFPinsEnable, 0x1bff); -} - -static bool HwHSSIThreeWire(struct net_device *dev, - u8 *pDataBuf, - bool write) -{ - u8 TryCnt; - u8 u1bTmp; - - /* Check if WE and RE are cleared. */ - for (TryCnt = 0; TryCnt < TC_3W_POLL_MAX_TRY_CNT; TryCnt++) { - u1bTmp = read_nic_byte(dev, SW_3W_CMD1); - if ((u1bTmp & (SW_3W_CMD1_RE|SW_3W_CMD1_WE)) == 0) - break; - - udelay(10); - } - if (TryCnt == TC_3W_POLL_MAX_TRY_CNT) { - netdev_err(dev, - "HwThreeWire(): CmdReg: %#X RE|WE bits are not clear!!\n", - u1bTmp); - return false; - } - - /* RTL8187S HSSI Read/Write Function */ - u1bTmp = read_nic_byte(dev, RF_SW_CONFIG); - u1bTmp |= RF_SW_CFG_SI; /* reg08[1]=1 Serial Interface(SI) */ - write_nic_byte(dev, RF_SW_CONFIG, u1bTmp); - - /* jong: HW SI read must set reg84[3]=0. */ - u1bTmp = read_nic_byte(dev, RFPinsSelect); - u1bTmp &= ~BIT3; - write_nic_byte(dev, RFPinsSelect, u1bTmp); - /* Fill up data buffer for write operation. */ - - /* SI - reg274[3:0] : RF register's Address */ - if (write) - write_nic_word(dev, SW_3W_DB0, *((u16 *)pDataBuf)); - else - write_nic_word(dev, SW_3W_DB0, *((u16 *)pDataBuf)); - - /* Set up command: WE or RE. */ - if (write) - write_nic_byte(dev, SW_3W_CMD1, SW_3W_CMD1_WE); - else - write_nic_byte(dev, SW_3W_CMD1, SW_3W_CMD1_RE); - - - /* Check if DONE is set. */ - for (TryCnt = 0; TryCnt < TC_3W_POLL_MAX_TRY_CNT; TryCnt++) { - u1bTmp = read_nic_byte(dev, SW_3W_CMD1); - if (u1bTmp & SW_3W_CMD1_DONE) - break; - - udelay(10); - } - - write_nic_byte(dev, SW_3W_CMD1, 0); - - /* Read back data for read operation. */ - if (!write) { - /* Serial Interface : reg363_362[11:0] */ - *((u16 *)pDataBuf) = read_nic_word(dev, SI_DATA_READ); - *((u16 *)pDataBuf) &= 0x0FFF; - } - - return true; -} - -void RF_WriteReg(struct net_device *dev, u8 offset, u16 data) -{ - u16 reg = (data << 4) | (offset & 0x0f); - HwHSSIThreeWire(dev, (u8 *)®, true); -} - -u16 RF_ReadReg(struct net_device *dev, u8 offset) -{ - u16 reg = offset & 0x0f; - HwHSSIThreeWire(dev, (u8 *)®, false); - return reg; -} - -static u8 ReadBBPortUchar(struct net_device *dev, u32 addr) -{ - PlatformIOWrite4Byte(dev, PhyAddr, addr & 0xffffff7f); - return PlatformIORead1Byte(dev, PhyDataR); -} - -/* by Owen on 04/07/14 for writing BB register successfully */ -static void WriteBBPortUchar(struct net_device *dev, u32 Data) -{ - PlatformIOWrite4Byte(dev, PhyAddr, Data); - ReadBBPortUchar(dev, Data); -} - -/* - * Description: - * Perform Antenna settings with antenna diversity on 87SE. - * Created by Roger, 2008.01.25. - */ -bool SetAntennaConfig87SE(struct net_device *dev, - u8 DefaultAnt, /* 0: Main, 1: Aux. */ - bool bAntDiversity) /* 1:Enable, 0: Disable. */ -{ - struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); - bool bAntennaSwitched = true; - /* 0x00 = disabled, 0x80 = enabled */ - u8 ant_diversity_offset = 0x00; - - /* - * printk("SetAntennaConfig87SE(): DefaultAnt(%d), bAntDiversity(%d)\n", - * DefaultAnt, bAntDiversity); - */ - - /* Threshold for antenna diversity. */ - write_phy_cck(dev, 0x0c, 0x09); /* Reg0c : 09 */ - - if (bAntDiversity) /* Enable Antenna Diversity. */ - ant_diversity_offset = 0x80; - - if (DefaultAnt == 1) { /* aux Antenna */ - /* Mac register, aux antenna */ - write_nic_byte(dev, ANTSEL, 0x00); - - /* Config CCK RX antenna. */ - write_phy_cck(dev, 0x11, 0xbb); /* Reg11 : bb */ - - /* Reg01 : 47 | ant_diversity_offset */ - write_phy_cck(dev, 0x01, 0x47|ant_diversity_offset); - - /* Config OFDM RX antenna. */ - write_phy_ofdm(dev, 0x0D, 0x54); /* Reg0d : 54 */ - /* Reg18 : 32 */ - write_phy_ofdm(dev, 0x18, 0x32|ant_diversity_offset); - } else { /* main Antenna */ - /* Mac register, main antenna */ - write_nic_byte(dev, ANTSEL, 0x03); - - /* Config CCK RX antenna. */ - write_phy_cck(dev, 0x11, 0x9b); /* Reg11 : 9b */ - /* Reg01 : 47 */ - write_phy_cck(dev, 0x01, 0x47|ant_diversity_offset); - - /* Config OFDM RX antenna. */ - write_phy_ofdm(dev, 0x0D, 0x5c); /* Reg0d : 5c */ - /*Reg18 : 32 */ - write_phy_ofdm(dev, 0x18, 0x32|ant_diversity_offset); - } - priv->CurrAntennaIndex = DefaultAnt; /* Update default settings. */ - return bAntennaSwitched; -} -/* - *-------------------------------------------------------------- - * Hardware Initialization. - * the code is ported from Windows source code - *-------------------------------------------------------------- - */ - -static void ZEBRA_Config_85BASIC_HardCode(struct net_device *dev) -{ - - struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); - u32 i; - u32 addr, data; - u32 u4bRegOffset, u4bRegValue; - u16 u4bRF23, u4bRF24; - u8 u1b24E; - int d_cut = 0; - - -/* - *=========================================================================== - * 87S_PCIE :: RADIOCFG.TXT - *=========================================================================== - */ - - - /* Page1 : reg16-reg30 */ - RF_WriteReg(dev, 0x00, 0x013f); mdelay(1); /* switch to page1 */ - u4bRF23 = RF_ReadReg(dev, 0x08); mdelay(1); - u4bRF24 = RF_ReadReg(dev, 0x09); mdelay(1); - - if (u4bRF23 == 0x818 && u4bRF24 == 0x70C) { - d_cut = 1; - netdev_info(dev, "card type changed from C- to D-cut\n"); - } - - /* Page0 : reg0-reg15 */ - - RF_WriteReg(dev, 0x00, 0x009f); mdelay(1);/* 1 */ - RF_WriteReg(dev, 0x01, 0x06e0); mdelay(1); - RF_WriteReg(dev, 0x02, 0x004d); mdelay(1);/* 2 */ - RF_WriteReg(dev, 0x03, 0x07f1); mdelay(1);/* 3 */ - RF_WriteReg(dev, 0x04, 0x0975); mdelay(1); - RF_WriteReg(dev, 0x05, 0x0c72); mdelay(1); - RF_WriteReg(dev, 0x06, 0x0ae6); mdelay(1); - RF_WriteReg(dev, 0x07, 0x00ca); mdelay(1); - RF_WriteReg(dev, 0x08, 0x0e1c); mdelay(1); - RF_WriteReg(dev, 0x09, 0x02f0); mdelay(1); - RF_WriteReg(dev, 0x0a, 0x09d0); mdelay(1); - RF_WriteReg(dev, 0x0b, 0x01ba); mdelay(1); - RF_WriteReg(dev, 0x0c, 0x0640); mdelay(1); - RF_WriteReg(dev, 0x0d, 0x08df); mdelay(1); - RF_WriteReg(dev, 0x0e, 0x0020); mdelay(1); - RF_WriteReg(dev, 0x0f, 0x0990); mdelay(1); - - /* Page1 : reg16-reg30 */ - RF_WriteReg(dev, 0x00, 0x013f); mdelay(1); - RF_WriteReg(dev, 0x03, 0x0806); mdelay(1); - RF_WriteReg(dev, 0x04, 0x03a7); mdelay(1); - RF_WriteReg(dev, 0x05, 0x059b); mdelay(1); - RF_WriteReg(dev, 0x06, 0x0081); mdelay(1); - RF_WriteReg(dev, 0x07, 0x01A0); mdelay(1); -/* - * Don't write RF23/RF24 to make a difference between 87S C cut and D cut. - * asked by SD3 stevenl. - */ - RF_WriteReg(dev, 0x0a, 0x0001); mdelay(1); - RF_WriteReg(dev, 0x0b, 0x0418); mdelay(1); - - if (d_cut) { - RF_WriteReg(dev, 0x0c, 0x0fbe); mdelay(1); - RF_WriteReg(dev, 0x0d, 0x0008); mdelay(1); - /* RX LO buffer */ - RF_WriteReg(dev, 0x0e, 0x0807); mdelay(1); - } else { - RF_WriteReg(dev, 0x0c, 0x0fbe); mdelay(1); - RF_WriteReg(dev, 0x0d, 0x0008); mdelay(1); - /* RX LO buffer */ - RF_WriteReg(dev, 0x0e, 0x0806); mdelay(1); - } - - RF_WriteReg(dev, 0x0f, 0x0acc); mdelay(1); - RF_WriteReg(dev, 0x00, 0x01d7); mdelay(1); /* 6 */ - RF_WriteReg(dev, 0x03, 0x0e00); mdelay(1); - RF_WriteReg(dev, 0x04, 0x0e50); mdelay(1); - - for (i = 0; i <= 36; i++) { - RF_WriteReg(dev, 0x01, i); mdelay(1); - RF_WriteReg(dev, 0x02, ZEBRA_RF_RX_GAIN_TABLE[i]); mdelay(1); - } - - RF_WriteReg(dev, 0x05, 0x0203); mdelay(1); /* 203, 343 */ - RF_WriteReg(dev, 0x06, 0x0200); mdelay(1); /* 400 */ - /* switch to reg16-reg30, and HSSI disable 137 */ - RF_WriteReg(dev, 0x00, 0x0137); mdelay(1); - mdelay(10); /* Deay 10 ms. */ /* 0xfd */ - - /* Z4 synthesizer loop filter setting, 392 */ - RF_WriteReg(dev, 0x0d, 0x0008); mdelay(1); - mdelay(10); /* Deay 10 ms. */ /* 0xfd */ - - /* switch to reg0-reg15, and HSSI disable */ - RF_WriteReg(dev, 0x00, 0x0037); mdelay(1); - mdelay(10); /* Deay 10 ms. */ /* 0xfd */ - - /* CBC on, Tx Rx disable, High gain */ - RF_WriteReg(dev, 0x04, 0x0160); mdelay(1); - mdelay(10); /* Deay 10 ms. */ /* 0xfd */ - - /* Z4 setted channel 1 */ - RF_WriteReg(dev, 0x07, 0x0080); mdelay(1); - mdelay(10); /* Deay 10 ms. */ /* 0xfd */ - - RF_WriteReg(dev, 0x02, 0x088D); mdelay(1); /* LC calibration */ - mdelay(200); /* Deay 200 ms. */ /* 0xfd */ - mdelay(10); /* Deay 10 ms. */ /* 0xfd */ - mdelay(10); /* Deay 10 ms. */ /* 0xfd */ - - /* switch to reg16-reg30 137, and HSSI disable 137 */ - RF_WriteReg(dev, 0x00, 0x0137); mdelay(1); - mdelay(10); /* Deay 10 ms. */ /* 0xfd */ - - RF_WriteReg(dev, 0x07, 0x0000); mdelay(1); - RF_WriteReg(dev, 0x07, 0x0180); mdelay(1); - RF_WriteReg(dev, 0x07, 0x0220); mdelay(1); - RF_WriteReg(dev, 0x07, 0x03E0); mdelay(1); - - /* DAC calibration off 20070702 */ - RF_WriteReg(dev, 0x06, 0x00c1); mdelay(1); - RF_WriteReg(dev, 0x0a, 0x0001); mdelay(1); - /* For crystal calibration, added by Roger, 2007.12.11. */ - if (priv->bXtalCalibration) { /* reg 30. */ - /* - * enable crystal calibration. - * RF Reg[30], (1)Xin:[12:9], Xout:[8:5], addr[4:0]. - * (2)PA Pwr delay timer[15:14], default: 2.4us, - * set BIT15=0 - * (3)RF signal on/off when calibration[13], default: on, - * set BIT13=0. - * So we should minus 4 BITs offset. - */ - RF_WriteReg(dev, 0x0f, (priv->XtalCal_Xin<<5) | - (priv->XtalCal_Xout<<1) | BIT11 | BIT9); mdelay(1); - netdev_info(dev, "ZEBRA_Config_85BASIC_HardCode(): (%02x)\n", - (priv->XtalCal_Xin<<5) | (priv->XtalCal_Xout<<1) | - BIT11 | BIT9); - } else { - /* using default value. Xin=6, Xout=6. */ - RF_WriteReg(dev, 0x0f, 0x0acc); mdelay(1); - } - /* switch to reg0-reg15, and HSSI enable */ - RF_WriteReg(dev, 0x00, 0x00bf); mdelay(1); - /* Rx BB start calibration, 00c//+edward */ - RF_WriteReg(dev, 0x0d, 0x08df); mdelay(1); - /* temperature meter off */ - RF_WriteReg(dev, 0x02, 0x004d); mdelay(1); - RF_WriteReg(dev, 0x04, 0x0975); mdelay(1); /* Rx mode */ - mdelay(10); /* Deay 10 ms.*/ /* 0xfe */ - mdelay(10); /* Deay 10 ms.*/ /* 0xfe */ - mdelay(10); /* Deay 10 ms.*/ /* 0xfe */ - /* Rx mode*/ /*+edward */ - RF_WriteReg(dev, 0x00, 0x0197); mdelay(1); - /* Rx mode*/ /*+edward */ - RF_WriteReg(dev, 0x05, 0x05ab); mdelay(1); - /* Rx mode*/ /*+edward */ - RF_WriteReg(dev, 0x00, 0x009f); mdelay(1); - /* Rx mode*/ /*+edward */ - RF_WriteReg(dev, 0x01, 0x0000); mdelay(1); - /* Rx mode*/ /*+edward */ - RF_WriteReg(dev, 0x02, 0x0000); mdelay(1); - /* power save parameters. */ - u1b24E = read_nic_byte(dev, 0x24E); - write_nic_byte(dev, 0x24E, (u1b24E & (~(BIT5|BIT6)))); - - /*====================================================================== - * - *====================================================================== - * CCKCONF.TXT - *====================================================================== - * - * [POWER SAVE] Power Saving Parameters by jong. 2007-11-27 - * CCK reg0x00[7]=1'b1 :power saving for TX (default) - * CCK reg0x00[6]=1'b1: power saving for RX (default) - * CCK reg0x06[4]=1'b1: turn off channel estimation related - * circuits if not doing channel estimation. - * CCK reg0x06[3]=1'b1: turn off unused circuits before cca = 1 - * CCK reg0x06[2]=1'b1: turn off cck's circuit if macrst =0 - */ - - write_phy_cck(dev, 0x00, 0xc8); - write_phy_cck(dev, 0x06, 0x1c); - write_phy_cck(dev, 0x10, 0x78); - write_phy_cck(dev, 0x2e, 0xd0); - write_phy_cck(dev, 0x2f, 0x06); - write_phy_cck(dev, 0x01, 0x46); - - /* power control */ - write_nic_byte(dev, CCK_TXAGC, 0x10); - write_nic_byte(dev, OFDM_TXAGC, 0x1B); - write_nic_byte(dev, ANTSEL, 0x03); - - - - /* - *====================================================================== - * AGC.txt - *====================================================================== - */ - - write_phy_ofdm(dev, 0x00, 0x12); - - for (i = 0; i < 128; i++) { - - data = ZEBRA_AGC[i+1]; - data = data << 8; - data = data | 0x0000008F; - - addr = i + 0x80; /* enable writing AGC table */ - addr = addr << 8; - addr = addr | 0x0000008E; - - WriteBBPortUchar(dev, data); - WriteBBPortUchar(dev, addr); - WriteBBPortUchar(dev, 0x0000008E); - } - - PlatformIOWrite4Byte(dev, PhyAddr, 0x00001080); /* Annie, 2006-05-05 */ - - /* - *====================================================================== - * - *====================================================================== - * OFDMCONF.TXT - *====================================================================== - */ - - for (i = 0; i < 60; i++) { - u4bRegOffset = i; - u4bRegValue = OFDM_CONFIG[i]; - - WriteBBPortUchar(dev, - (0x00000080 | - (u4bRegOffset & 0x7f) | - ((u4bRegValue & 0xff) << 8))); - } - - /* - *====================================================================== - * by amy for antenna - *====================================================================== - */ - /* - * Config Sw/Hw Combinational Antenna Diversity. Added by Roger, - * 2008.02.26. - */ - SetAntennaConfig87SE(dev, priv->bDefaultAntenna1, - priv->bSwAntennaDiverity); -} - - -void UpdateInitialGain(struct net_device *dev) -{ - struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); - - /* lzm add 080826 */ - if (priv->eRFPowerState != RF_ON) { - /* Don't access BB/RF under disable PLL situation. - * RT_TRACE(COMP_DIG, DBG_LOUD, ("UpdateInitialGain - - * pHalData->eRFPowerState!=RF_ON\n")); - * Back to the original state - */ - priv->InitialGain = priv->InitialGainBackUp; - return; - } - - switch (priv->InitialGain) { - case 1: /* m861dBm */ - write_phy_ofdm(dev, 0x17, 0x26); mdelay(1); - write_phy_ofdm(dev, 0x24, 0x86); mdelay(1); - write_phy_ofdm(dev, 0x05, 0xfa); mdelay(1); - break; - - case 2: /* m862dBm */ - write_phy_ofdm(dev, 0x17, 0x36); mdelay(1); - write_phy_ofdm(dev, 0x24, 0x86); mdelay(1); - write_phy_ofdm(dev, 0x05, 0xfa); mdelay(1); - break; - - case 3: /* m863dBm */ - write_phy_ofdm(dev, 0x17, 0x36); mdelay(1); - write_phy_ofdm(dev, 0x24, 0x86); mdelay(1); - write_phy_ofdm(dev, 0x05, 0xfb); mdelay(1); - break; - - case 4: /* m864dBm */ - write_phy_ofdm(dev, 0x17, 0x46); mdelay(1); - write_phy_ofdm(dev, 0x24, 0x86); mdelay(1); - write_phy_ofdm(dev, 0x05, 0xfb); mdelay(1); - break; - - case 5: /* m82dBm */ - write_phy_ofdm(dev, 0x17, 0x46); mdelay(1); - write_phy_ofdm(dev, 0x24, 0x96); mdelay(1); - write_phy_ofdm(dev, 0x05, 0xfb); mdelay(1); - break; - - case 6: /* m78dBm */ - write_phy_ofdm(dev, 0x17, 0x56); mdelay(1); - write_phy_ofdm(dev, 0x24, 0x96); mdelay(1); - write_phy_ofdm(dev, 0x05, 0xfc); mdelay(1); - break; - - case 7: /* m74dBm */ - write_phy_ofdm(dev, 0x17, 0x56); mdelay(1); - write_phy_ofdm(dev, 0x24, 0xa6); mdelay(1); - write_phy_ofdm(dev, 0x05, 0xfc); mdelay(1); - break; - - case 8: - write_phy_ofdm(dev, 0x17, 0x66); mdelay(1); - write_phy_ofdm(dev, 0x24, 0xb6); mdelay(1); - write_phy_ofdm(dev, 0x05, 0xfc); mdelay(1); - break; - - default: /* MP */ - write_phy_ofdm(dev, 0x17, 0x26); mdelay(1); - write_phy_ofdm(dev, 0x24, 0x86); mdelay(1); - write_phy_ofdm(dev, 0x05, 0xfa); mdelay(1); - break; - } -} -/* - * Description: - * Tx Power tracking mechanism routine on 87SE. - * Created by Roger, 2007.12.11. - */ -static void InitTxPwrTracking87SE(struct net_device *dev) -{ - u32 u4bRfReg; - - u4bRfReg = RF_ReadReg(dev, 0x02); - - /* Enable Thermal meter indication. */ - RF_WriteReg(dev, 0x02, u4bRfReg|PWR_METER_EN); mdelay(1); -} - -static void PhyConfig8185(struct net_device *dev) -{ - struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); - write_nic_dword(dev, RCR, priv->ReceiveConfig); - priv->RFProgType = read_nic_byte(dev, CONFIG4) & 0x03; - /* RF config */ - ZEBRA_Config_85BASIC_HardCode(dev); - /* Set default initial gain state to 4, approved by SD3 DZ, by Bruce, - * 2007-06-06. - */ - if (priv->bDigMechanism) { - if (priv->InitialGain == 0) - priv->InitialGain = 4; - } - - /* - * Enable thermal meter indication to implement TxPower tracking - * on 87SE. We initialize thermal meter here to avoid unsuccessful - * configuration. Added by Roger, 2007.12.11. - */ - if (priv->bTxPowerTrack) - InitTxPwrTracking87SE(dev); - - priv->InitialGainBackUp = priv->InitialGain; - UpdateInitialGain(dev); - - return; -} - -static void HwConfigureRTL8185(struct net_device *dev) -{ - /* - * RTL8185_TODO: Determine Retrylimit, TxAGC, - * AutoRateFallback control. - */ - u8 bUNIVERSAL_CONTROL_RL = 0; - u8 bUNIVERSAL_CONTROL_AGC = 1; - u8 bUNIVERSAL_CONTROL_ANT = 1; - u8 bAUTO_RATE_FALLBACK_CTL = 1; - u8 val8; - write_nic_word(dev, BRSR, 0x0fff); - /* Retry limit */ - val8 = read_nic_byte(dev, CW_CONF); - - if (bUNIVERSAL_CONTROL_RL) - val8 = val8 & 0xfd; - else - val8 = val8 | 0x02; - - write_nic_byte(dev, CW_CONF, val8); - - /* Tx AGC */ - val8 = read_nic_byte(dev, TXAGC_CTL); - if (bUNIVERSAL_CONTROL_AGC) { - write_nic_byte(dev, CCK_TXAGC, 128); - write_nic_byte(dev, OFDM_TXAGC, 128); - val8 = val8 & 0xfe; - } else { - val8 = val8 | 0x01; - } - - - write_nic_byte(dev, TXAGC_CTL, val8); - - /* Tx Antenna including Feedback control */ - val8 = read_nic_byte(dev, TXAGC_CTL); - - if (bUNIVERSAL_CONTROL_ANT) { - write_nic_byte(dev, ANTSEL, 0x00); - val8 = val8 & 0xfd; - } else { - val8 = val8 & (val8|0x02); /* xiong-2006-11-15 */ - } - - write_nic_byte(dev, TXAGC_CTL, val8); - - /* Auto Rate fallback control */ - val8 = read_nic_byte(dev, RATE_FALLBACK); - val8 &= 0x7c; - if (bAUTO_RATE_FALLBACK_CTL) { - val8 |= RATE_FALLBACK_CTL_ENABLE | RATE_FALLBACK_CTL_AUTO_STEP1; - - /* We shall set up the ARFR according - * to user's setting. - */ - PlatformIOWrite2Byte(dev, ARFR, 0x0fff); /* set 1M ~ 54Mbps. */ - } - write_nic_byte(dev, RATE_FALLBACK, val8); -} - -static void MacConfig_85BASIC_HardCode(struct net_device *dev) -{ - /* - *====================================================================== - * MACREG.TXT - *====================================================================== - */ - int nLinesRead = 0; - u32 u4bRegOffset, u4bRegValue, u4bPageIndex = 0; - int i; - - nLinesRead = sizeof(MAC_REG_TABLE)/2; - - for (i = 0; i < nLinesRead; i++) { /* nLinesRead=101 */ - u4bRegOffset = MAC_REG_TABLE[i][0]; - u4bRegValue = MAC_REG_TABLE[i][1]; - - if (u4bRegOffset == 0x5e) - u4bPageIndex = u4bRegValue; - else - u4bRegOffset |= (u4bPageIndex << 8); - - write_nic_byte(dev, u4bRegOffset, (u8)u4bRegValue); - } - /* ================================================================= */ -} - -static void MacConfig_85BASIC(struct net_device *dev) -{ - - u8 u1DA; - MacConfig_85BASIC_HardCode(dev); - - /* ================================================================= */ - - /* Follow TID_AC_MAP of WMac. */ - write_nic_word(dev, TID_AC_MAP, 0xfa50); - - /* Interrupt Migration, Jong suggested we use set 0x0000 first, - * 2005.12.14, by rcnjko. - */ - write_nic_word(dev, IntMig, 0x0000); - - /* Prevent TPC to cause CRC error. Added by Annie, 2006-06-10. */ - PlatformIOWrite4Byte(dev, 0x1F0, 0x00000000); - PlatformIOWrite4Byte(dev, 0x1F4, 0x00000000); - PlatformIOWrite1Byte(dev, 0x1F8, 0x00); - - /* Asked for by SD3 CM Lin, 2006.06.27, by rcnjko. */ - - /* - * power save parameter based on - * "87SE power save parameters 20071127.doc", as follow. - */ - - /* Enable DA10 TX power saving */ - u1DA = read_nic_byte(dev, PHYPR); - write_nic_byte(dev, PHYPR, (u1DA | BIT2)); - - /* POWER: */ - write_nic_word(dev, 0x360, 0x1000); - write_nic_word(dev, 0x362, 0x1000); - - /* AFE. */ - write_nic_word(dev, 0x370, 0x0560); - write_nic_word(dev, 0x372, 0x0560); - write_nic_word(dev, 0x374, 0x0DA4); - write_nic_word(dev, 0x376, 0x0DA4); - write_nic_word(dev, 0x378, 0x0560); - write_nic_word(dev, 0x37A, 0x0560); - write_nic_word(dev, 0x37C, 0x00EC); - write_nic_word(dev, 0x37E, 0x00EC); /* +edward */ - write_nic_byte(dev, 0x24E, 0x01); -} - -static u8 GetSupportedWirelessMode8185(struct net_device *dev) -{ - return WIRELESS_MODE_B | WIRELESS_MODE_G; -} - -static void -ActUpdateChannelAccessSetting(struct net_device *dev, - enum wireless_mode mode, - struct chnl_access_setting *chnl_access_setting) -{ - AC_CODING eACI; - - /* - * - * TODO: We still don't know how to set up these registers, - * just follow WMAC to verify 8185B FPAG. - * - * - * Jong said CWmin/CWmax register are not functional in 8185B, - * so we shall fill channel access realted register into AC - * parameter registers, - * even in nQBss. - */ - - /* Suggested by Jong, 2005.12.08. */ - chnl_access_setting->sifs_timer = 0x22; - chnl_access_setting->difs_timer = 0x1C; /* 2006.06.02, by rcnjko. */ - chnl_access_setting->slot_time_timer = 9; /* 2006.06.02, by rcnjko. */ - /* - * Suggested by wcchu, it is the default value of EIFS register, - * 2005.12.08. - */ - chnl_access_setting->eifs_timer = 0x5B; - chnl_access_setting->cwmin_index = 3; /* 2006.06.02, by rcnjko. */ - chnl_access_setting->cwmax_index = 7; /* 2006.06.02, by rcnjko. */ - - write_nic_byte(dev, SIFS, chnl_access_setting->sifs_timer); - /* - * Rewrited from directly use PlatformEFIOWrite1Byte(), - * by Annie, 2006-03-29. - */ - write_nic_byte(dev, SLOT, chnl_access_setting->slot_time_timer); - - write_nic_byte(dev, EIFS, chnl_access_setting->eifs_timer); - - /* - * Suggested by wcchu, it is the default value of EIFS - * register, 2005.12.08. - */ - write_nic_byte(dev, AckTimeOutReg, 0x5B); - - for (eACI = 0; eACI < AC_MAX; eACI++) - write_nic_byte(dev, ACM_CONTROL, 0); -} - -static void ActSetWirelessMode8185(struct net_device *dev, u8 btWirelessMode) -{ - struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); - struct ieee80211_device *ieee = priv->ieee80211; - u8 btSupportedWirelessMode = GetSupportedWirelessMode8185(dev); - - if ((btWirelessMode & btSupportedWirelessMode) == 0) { - /* - * Don't switch to unsupported wireless mode, 2006.02.15, - * by rcnjko. - */ - DMESGW("ActSetWirelessMode8185(): WirelessMode(%d) is not supported (%d)!\n", - btWirelessMode, btSupportedWirelessMode); - return; - } - - /* 1. Assign wireless mode to switch if necessary. */ - if (btWirelessMode == WIRELESS_MODE_AUTO) { - if ((btSupportedWirelessMode & WIRELESS_MODE_A)) { - btWirelessMode = WIRELESS_MODE_A; - } else if (btSupportedWirelessMode & WIRELESS_MODE_G) { - btWirelessMode = WIRELESS_MODE_G; - - } else if ((btSupportedWirelessMode & WIRELESS_MODE_B)) { - btWirelessMode = WIRELESS_MODE_B; - } else { - DMESGW("ActSetWirelessMode8185(): No valid wireless mode supported, btSupportedWirelessMode(%x)!!!\n", - btSupportedWirelessMode); - btWirelessMode = WIRELESS_MODE_B; - } - } - - /* - * 2. Swtich band: RF or BB specific actions, - * for example, refresh tables in omc8255, or change initial gain if - * necessary. Nothing to do for Zebra to switch band. Update current - * wireless mode if we switch to specified band successfully. - */ - - ieee->mode = (enum wireless_mode)btWirelessMode; - - /* 3. Change related setting. */ - if (ieee->mode == WIRELESS_MODE_A) - DMESG("WIRELESS_MODE_A\n"); - else if (ieee->mode == WIRELESS_MODE_B) - DMESG("WIRELESS_MODE_B\n"); - else if (ieee->mode == WIRELESS_MODE_G) - DMESG("WIRELESS_MODE_G\n"); - - ActUpdateChannelAccessSetting(dev, ieee->mode, - &priv->ChannelAccessSetting); -} - -void rtl8185b_irq_enable(struct net_device *dev) -{ - struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); - - priv->irq_enabled = 1; - write_nic_dword(dev, IMR, priv->IntrMask); -} - -static void MgntDisconnectIBSS(struct net_device *dev) -{ - struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); - u8 i; - - for (i = 0; i < 6; i++) - priv->ieee80211->current_network.bssid[i] = 0x55; - - - - priv->ieee80211->state = IEEE80211_NOLINK; - /* - * Stop Beacon. - * - * Vista add a Adhoc profile, HW radio off until - * OID_DOT11_RESET_REQUEST Driver would set MSR=NO_LINK, - * then HW Radio ON, MgntQueue Stuck. Because Bcn DMA isn't - * complete, mgnt queue would stuck until Bcn packet send. - * - * Disable Beacon Queue Own bit, suggested by jong - */ - ieee80211_stop_send_beacons(priv->ieee80211); - - priv->ieee80211->link_change(dev); - notify_wx_assoc_event(priv->ieee80211); -} - -static void MlmeDisassociateRequest(struct net_device *dev, u8 *asSta, u8 asRsn) -{ - struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); - u8 i; - - SendDisassociation(priv->ieee80211, asSta, asRsn); - - if (memcmp(priv->ieee80211->current_network.bssid, asSta, 6) == 0) { - /* ShuChen TODO: change media status. */ - - for (i = 0; i < 6; i++) - priv->ieee80211->current_network.bssid[i] = 0x22; - - ieee80211_disassociate(priv->ieee80211); - } -} - -static void MgntDisconnectAP(struct net_device *dev, u8 asRsn) -{ - struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); - - /* - * Commented out by rcnjko, 2005.01.27: - * I move SecClearAllKeys() to MgntActSet_802_11_DISASSOCIATE(). - * - * 2004/09/15, kcwu, the key should be cleared, or the new - * handshaking will not success - * - * In WPA WPA2 need to Clear all key ... because new key will set - * after new handshaking. 2004.10.11, by rcnjko. - */ - MlmeDisassociateRequest(dev, priv->ieee80211->current_network.bssid, - asRsn); - - priv->ieee80211->state = IEEE80211_NOLINK; -} - -static bool MgntDisconnect(struct net_device *dev, u8 asRsn) -{ - struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); - /* - * Schedule an workitem to wake up for ps mode, 070109, by rcnjko. - */ - - if (IS_DOT11D_ENABLE(priv->ieee80211)) - Dot11d_Reset(priv->ieee80211); - /* In adhoc mode, update beacon frame. */ - if (priv->ieee80211->state == IEEE80211_LINKED) { - if (priv->ieee80211->iw_mode == IW_MODE_ADHOC) - MgntDisconnectIBSS(dev); - - if (priv->ieee80211->iw_mode == IW_MODE_INFRA) { - /* - * We clear key here instead of MgntDisconnectAP() - * because that MgntActSet_802_11_DISASSOCIATE() - * is an interface called by OS, e.g. - * OID_802_11_DISASSOCIATE in Windows while as - * MgntDisconnectAP() is used to handle - * disassociation related things to AP, e.g. send - * Disassoc frame to AP. 2005.01.27, by rcnjko. - */ - MgntDisconnectAP(dev, asRsn); - } - /* Indicate Disconnect, 2005.02.23, by rcnjko. */ - } - return true; -} -/* - * Description: - * Chang RF Power State. - * Note that, only MgntActSet_RF_State() is allowed to set - * HW_VAR_RF_STATE. - * - * Assumption: - * PASSIVE LEVEL. - */ -static bool SetRFPowerState(struct net_device *dev, - enum rt_rf_power_state eRFPowerState) -{ - struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); - bool bResult = false; - - if (eRFPowerState == priv->eRFPowerState) - return bResult; - - bResult = SetZebraRFPowerState8185(dev, eRFPowerState); - - return bResult; -} - -bool MgntActSet_RF_State(struct net_device *dev, enum rt_rf_power_state StateToSet, - u32 ChangeSource) -{ - struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); - bool bActionAllowed = false; - bool bConnectBySSID = false; - enum rt_rf_power_state rtState; - u16 RFWaitCounter = 0; - unsigned long flag; - /* - * Prevent the race condition of RF state change. By Bruce, - * 2007-11-28. Only one thread can change the RF state at one time, - * and others should wait to be executed. - */ - while (true) { - spin_lock_irqsave(&priv->rf_ps_lock, flag); - if (priv->RFChangeInProgress) { - spin_unlock_irqrestore(&priv->rf_ps_lock, flag); - /* Set RF after the previous action is done. */ - while (priv->RFChangeInProgress) { - RFWaitCounter++; - udelay(1000); /* 1 ms */ - - /* - * Wait too long, return FALSE to avoid - * to be stuck here. - */ - if (RFWaitCounter > 1000) { /* 1sec */ - netdev_info(dev, "MgntActSet_RF_State(): Wait too long to set RF\n"); - /* TODO: Reset RF state? */ - return false; - } - } - } else { - priv->RFChangeInProgress = true; - spin_unlock_irqrestore(&priv->rf_ps_lock, flag); - break; - } - } - rtState = priv->eRFPowerState; - - switch (StateToSet) { - case RF_ON: - /* - * Turn On RF no matter the IPS setting because we need to - * update the RF state to Ndis under Vista, or the Windows - * does not allow the driver to perform site survey any - * more. By Bruce, 2007-10-02. - */ - priv->RfOffReason &= (~ChangeSource); - - if (!priv->RfOffReason) { - priv->RfOffReason = 0; - bActionAllowed = true; - - if (rtState == RF_OFF && - ChangeSource >= RF_CHANGE_BY_HW) - bConnectBySSID = true; - } - break; - - case RF_OFF: - /* 070125, rcnjko: we always keep connected in AP mode. */ - - if (priv->RfOffReason > RF_CHANGE_BY_IPS) { - /* - * 060808, Annie: - * Disconnect to current BSS when radio off. - * Asked by QuanTa. - * - * Calling MgntDisconnect() instead of - * MgntActSet_802_11_DISASSOCIATE(), because - * we do NOT need to set ssid to dummy ones. - */ - MgntDisconnect(dev, disas_lv_ss); - /* - * Clear content of bssDesc[] and bssDesc4Query[] - * to avoid reporting old bss to UI. - */ - } - - priv->RfOffReason |= ChangeSource; - bActionAllowed = true; - break; - case RF_SLEEP: - priv->RfOffReason |= ChangeSource; - bActionAllowed = true; - break; - default: - break; - } - - if (bActionAllowed) { - /* Config HW to the specified mode. */ - SetRFPowerState(dev, StateToSet); - } - - /* Release RF spinlock */ - spin_lock_irqsave(&priv->rf_ps_lock, flag); - priv->RFChangeInProgress = false; - spin_unlock_irqrestore(&priv->rf_ps_lock, flag); - return bActionAllowed; -} - -static void InactivePowerSave(struct net_device *dev) -{ - struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); - /* - * This flag "bSwRfProcessing", indicates the status of IPS - * procedure, should be set if the IPS workitem is really - * scheduled. The old code, sets this flag before scheduling the - * IPS workitem and however, at the same time the previous IPS - * workitem did not end yet, fails to schedule the current - * workitem. Thus, bSwRfProcessing blocks the IPS procedure of - * switching RF. - */ - priv->bSwRfProcessing = true; - - MgntActSet_RF_State(dev, priv->eInactivePowerState, RF_CHANGE_BY_IPS); - - /* - * To solve CAM values miss in RF OFF, rewrite CAM values after - * RF ON. By Bruce, 2007-09-20. - */ - - priv->bSwRfProcessing = false; -} - -/* - * Description: - * Enter the inactive power save mode. RF will be off - */ -void IPSEnter(struct net_device *dev) -{ - struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); - enum rt_rf_power_state rtState; - if (priv->bInactivePs) { - rtState = priv->eRFPowerState; - - /* - * Do not enter IPS in the following conditions: - * (1) RF is already OFF or - * Sleep (2) bSwRfProcessing (indicates the IPS is still - * under going) (3) Connected (only disconnected can - * trigger IPS)(4) IBSS (send Beacon) - * (5) AP mode (send Beacon) - */ - if (rtState == RF_ON && !priv->bSwRfProcessing - && (priv->ieee80211->state != IEEE80211_LINKED)) { - priv->eInactivePowerState = RF_OFF; - InactivePowerSave(dev); - } - } -} -void IPSLeave(struct net_device *dev) -{ - struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); - enum rt_rf_power_state rtState; - if (priv->bInactivePs) { - rtState = priv->eRFPowerState; - if ((rtState == RF_OFF || rtState == RF_SLEEP) && - !priv->bSwRfProcessing - && priv->RfOffReason <= RF_CHANGE_BY_IPS) { - priv->eInactivePowerState = RF_ON; - InactivePowerSave(dev); - } - } -} - -void rtl8185b_adapter_start(struct net_device *dev) -{ - struct r8180_priv *priv = ieee80211_priv(dev); - struct ieee80211_device *ieee = priv->ieee80211; - - u8 SupportedWirelessMode; - u8 InitWirelessMode; - u8 bInvalidWirelessMode = 0; - u8 tmpu8; - u8 btCR9346; - u8 TmpU1b; - u8 btPSR; - - write_nic_byte(dev, 0x24e, (BIT5|BIT6|BIT0)); - rtl8180_reset(dev); - - priv->dma_poll_mask = 0; - priv->dma_poll_stop_mask = 0; - - HwConfigureRTL8185(dev); - write_nic_dword(dev, MAC0, ((u32 *)dev->dev_addr)[0]); - write_nic_word(dev, MAC4, ((u32 *)dev->dev_addr)[1] & 0xffff); - /* default network type to 'No Link' */ - write_nic_byte(dev, MSR, read_nic_byte(dev, MSR) & 0xf3); - write_nic_word(dev, BcnItv, 100); - write_nic_word(dev, AtimWnd, 2); - PlatformIOWrite2Byte(dev, FEMR, 0xFFFF); - write_nic_byte(dev, WPA_CONFIG, 0); - MacConfig_85BASIC(dev); - /* Override the RFSW_CTRL (MAC offset 0x272-0x273), 2006.06.07, - * by rcnjko. - */ - /* BT_DEMO_BOARD type */ - PlatformIOWrite2Byte(dev, RFSW_CTRL, 0x569a); - - /* - *--------------------------------------------------------------------- - * Set up PHY related. - *--------------------------------------------------------------------- - */ - /* Enable Config3.PARAM_En to revise AnaaParm. */ - write_nic_byte(dev, CR9346, 0xc0); /* enable config register write */ - tmpu8 = read_nic_byte(dev, CONFIG3); - write_nic_byte(dev, CONFIG3, (tmpu8 | CONFIG3_PARM_En)); - /* Turn on Analog power. */ - /* Asked for by William, otherwise, MAC 3-wire can't work, - * 2006.06.27, by rcnjko. - */ - write_nic_dword(dev, ANAPARAM2, ANAPARM2_ASIC_ON); - write_nic_dword(dev, ANAPARAM, ANAPARM_ASIC_ON); - write_nic_word(dev, ANAPARAM3, 0x0010); - - write_nic_byte(dev, CONFIG3, tmpu8); - write_nic_byte(dev, CR9346, 0x00); - /* enable EEM0 and EEM1 in 9346CR */ - btCR9346 = read_nic_byte(dev, CR9346); - write_nic_byte(dev, CR9346, (btCR9346 | 0xC0)); - - /* B cut use LED1 to control HW RF on/off */ - TmpU1b = read_nic_byte(dev, CONFIG5); - TmpU1b = TmpU1b & ~BIT3; - write_nic_byte(dev, CONFIG5, TmpU1b); - - /* disable EEM0 and EEM1 in 9346CR */ - btCR9346 &= ~(0xC0); - write_nic_byte(dev, CR9346, btCR9346); - - /* Enable Led (suggested by Jong) */ - /* B-cut RF Radio on/off 5e[3]=0 */ - btPSR = read_nic_byte(dev, PSR); - write_nic_byte(dev, PSR, (btPSR | BIT3)); - /* setup initial timing for RFE. */ - write_nic_word(dev, RFPinsOutput, 0x0480); - SetOutputEnableOfRfPins(dev); - write_nic_word(dev, RFPinsSelect, 0x2488); - - /* PHY config. */ - PhyConfig8185(dev); - - /* - * We assume RegWirelessMode has already been initialized before, - * however, we has to validate the wireless mode here and provide a - * reasonable initialized value if necessary. 2005.01.13, - * by rcnjko. - */ - SupportedWirelessMode = GetSupportedWirelessMode8185(dev); - if ((ieee->mode != WIRELESS_MODE_B) && - (ieee->mode != WIRELESS_MODE_G) && - (ieee->mode != WIRELESS_MODE_A) && - (ieee->mode != WIRELESS_MODE_AUTO)) { - /* It should be one of B, G, A, or AUTO. */ - bInvalidWirelessMode = 1; - } else { - /* One of B, G, A, or AUTO. */ - /* Check if the wireless mode is supported by RF. */ - if ((ieee->mode != WIRELESS_MODE_AUTO) && - (ieee->mode & SupportedWirelessMode) == 0) { - bInvalidWirelessMode = 1; - } - } - - if (bInvalidWirelessMode || ieee->mode == WIRELESS_MODE_AUTO) { - /* Auto or other invalid value. */ - /* Assigne a wireless mode to initialize. */ - if ((SupportedWirelessMode & WIRELESS_MODE_A)) { - InitWirelessMode = WIRELESS_MODE_A; - } else if ((SupportedWirelessMode & WIRELESS_MODE_G)) { - InitWirelessMode = WIRELESS_MODE_G; - } else if ((SupportedWirelessMode & WIRELESS_MODE_B)) { - InitWirelessMode = WIRELESS_MODE_B; - } else { - DMESGW("InitializeAdapter8185(): No valid wireless mode supported, SupportedWirelessMode(%x)!!!\n", - SupportedWirelessMode); - InitWirelessMode = WIRELESS_MODE_B; - } - - /* Initialize RegWirelessMode if it is not a valid one. */ - if (bInvalidWirelessMode) - ieee->mode = (enum wireless_mode)InitWirelessMode; - - } else { - /* One of B, G, A. */ - InitWirelessMode = ieee->mode; - } - priv->eRFPowerState = RF_OFF; - priv->RfOffReason = 0; - { - MgntActSet_RF_State(dev, RF_ON, 0); - } - /* - * If inactive power mode is enabled, disable rf while in - * disconnected state. - */ - if (priv->bInactivePs) - MgntActSet_RF_State(dev , RF_OFF, RF_CHANGE_BY_IPS); - - ActSetWirelessMode8185(dev, (u8)(InitWirelessMode)); - - /* ----------------------------------------------------------------- */ - - rtl8185b_irq_enable(dev); - - netif_start_queue(dev); -} - -void rtl8185b_rx_enable(struct net_device *dev) -{ - u8 cmd; - /* for now we accept data, management & ctl frame*/ - struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); - - - if (dev->flags & IFF_PROMISC) - DMESG("NIC in promisc mode"); - - if (priv->ieee80211->iw_mode == IW_MODE_MONITOR || dev->flags & - IFF_PROMISC) { - priv->ReceiveConfig = priv->ReceiveConfig & (~RCR_APM); - priv->ReceiveConfig = priv->ReceiveConfig | RCR_AAP; - } - - if (priv->ieee80211->iw_mode == IW_MODE_MONITOR) - priv->ReceiveConfig = priv->ReceiveConfig | RCR_ACF | - RCR_APWRMGT | RCR_AICV; - - - if (priv->crcmon == 1 && priv->ieee80211->iw_mode == IW_MODE_MONITOR) - priv->ReceiveConfig = priv->ReceiveConfig | RCR_ACRC32; - - write_nic_dword(dev, RCR, priv->ReceiveConfig); - - fix_rx_fifo(dev); - - cmd = read_nic_byte(dev, CMD); - write_nic_byte(dev, CMD, cmd | (1<TransmitConfig); - byte = read_nic_byte(dev, MSR); - byte |= MSR_LINK_ENEDCA; - write_nic_byte(dev, MSR, byte); - - fix_tx_fifo(dev); - - cmd = read_nic_byte(dev, CMD); - write_nic_byte(dev, CMD, cmd | (1< Date: Tue, 15 Apr 2014 15:50:20 +0200 Subject: net: mvneta: properly configure the MAC <-> PHY connection in all situations Commit 5445eaf309ff ('mvneta: Try to fix mvneta when compiled as module') fixed the mvneta driver to make it work properly when loaded as a module in SGMII configuration, which was tested successful by the author on the Armada XP OpenBlocks AX3, which uses SGMII. However, some other platforms, namely the Armada XP GP don't use SGMII, but a QSGMII connection between the MAC and the PHY, and this case was not supported by the mvneta driver, which was relying on configuration put in place by the bootloader. While this works when the mvneta driver is built-in (because clocks are not gated), it breaks when mvneta is built as a module, because the clock is gated (all configuration is lost) and then re-enabled when the mvneta driver is loaded. In order to support all of RGMII, SGMII and QSGMII, this commit reworks how the PHY interface configuration is done, and simplifies it: it removes the mvneta_port_sgmii_config() and mvneta_gmac_rgmii_set() functions, which were strange because mvneta_gmac_rgmii_set() was called in all cases, even for SGMII configurations. Also, the mvneta_gmac_rgmii_set() function was taking a boolean as argument, which was always true. Instead, all the PHY interface configuration logic is moved into the mvneta_port_power_up() function, in a much simpler 'switch' construct, with four cases: - QSGMII: the RGMIIEn bit, the PCSEn bit in GMAC_CTRL_2 are set, and the SERDES is configured in QSGMII. Technically speaking, configuring the SERDES of the first port would be sufficient, but it is simpler to do it on all ports. - SGMII: the RGMIIEn bit, the PCSEn bit in GMAC_CTRL_2 are set, and the SERDES is configured as SGMII. - RGMII: the RGMIIEn bit in GMAC_CTRL_2 is set. The PCSEn bit is kept cleared, and no SERDES configuration is done, because RGMII is not using SERDES lanes. - other: an error is returned. For this reason, the mvneta_port_power_up() now returns an int instead of nothing, and the return value is checked by mvneta_probe(). This has been successfully tested on: * Armada XP DB, which has two RGMII and two SGMII connections * Armada XP GP, which uses QSGMII for its four interfaces * Armada 370 Mirabox, which has two RGMII connections Signed-off-by: Thomas Petazzoni Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvneta.c | 73 ++++++++++++++++------------------- 1 file changed, 34 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index b248bcbdae6..14786c8bf99 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -89,8 +89,9 @@ #define MVNETA_TX_IN_PRGRS BIT(1) #define MVNETA_TX_FIFO_EMPTY BIT(8) #define MVNETA_RX_MIN_FRAME_SIZE 0x247c -#define MVNETA_SGMII_SERDES_CFG 0x24A0 +#define MVNETA_SERDES_CFG 0x24A0 #define MVNETA_SGMII_SERDES_PROTO 0x0cc7 +#define MVNETA_QSGMII_SERDES_PROTO 0x0667 #define MVNETA_TYPE_PRIO 0x24bc #define MVNETA_FORCE_UNI BIT(21) #define MVNETA_TXQ_CMD_1 0x24e4 @@ -711,35 +712,6 @@ static void mvneta_rxq_bm_disable(struct mvneta_port *pp, mvreg_write(pp, MVNETA_RXQ_CONFIG_REG(rxq->id), val); } - - -/* Sets the RGMII Enable bit (RGMIIEn) in port MAC control register */ -static void mvneta_gmac_rgmii_set(struct mvneta_port *pp, int enable) -{ - u32 val; - - val = mvreg_read(pp, MVNETA_GMAC_CTRL_2); - - if (enable) - val |= MVNETA_GMAC2_PORT_RGMII; - else - val &= ~MVNETA_GMAC2_PORT_RGMII; - - mvreg_write(pp, MVNETA_GMAC_CTRL_2, val); -} - -/* Config SGMII port */ -static void mvneta_port_sgmii_config(struct mvneta_port *pp) -{ - u32 val; - - val = mvreg_read(pp, MVNETA_GMAC_CTRL_2); - val |= MVNETA_GMAC2_PCS_ENABLE; - mvreg_write(pp, MVNETA_GMAC_CTRL_2, val); - - mvreg_write(pp, MVNETA_SGMII_SERDES_CFG, MVNETA_SGMII_SERDES_PROTO); -} - /* Start the Ethernet port RX and TX activity */ static void mvneta_port_up(struct mvneta_port *pp) { @@ -2749,26 +2721,44 @@ static void mvneta_conf_mbus_windows(struct mvneta_port *pp, } /* Power up the port */ -static void mvneta_port_power_up(struct mvneta_port *pp, int phy_mode) +static int mvneta_port_power_up(struct mvneta_port *pp, int phy_mode) { - u32 val; + u32 ctrl; /* MAC Cause register should be cleared */ mvreg_write(pp, MVNETA_UNIT_INTR_CAUSE, 0); - if (phy_mode == PHY_INTERFACE_MODE_SGMII) - mvneta_port_sgmii_config(pp); + ctrl = mvreg_read(pp, MVNETA_GMAC_CTRL_2); - mvneta_gmac_rgmii_set(pp, 1); + /* Even though it might look weird, when we're configured in + * SGMII or QSGMII mode, the RGMII bit needs to be set. + */ + switch(phy_mode) { + case PHY_INTERFACE_MODE_QSGMII: + mvreg_write(pp, MVNETA_SERDES_CFG, MVNETA_QSGMII_SERDES_PROTO); + ctrl |= MVNETA_GMAC2_PCS_ENABLE | MVNETA_GMAC2_PORT_RGMII; + break; + case PHY_INTERFACE_MODE_SGMII: + mvreg_write(pp, MVNETA_SERDES_CFG, MVNETA_SGMII_SERDES_PROTO); + ctrl |= MVNETA_GMAC2_PCS_ENABLE | MVNETA_GMAC2_PORT_RGMII; + break; + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_ID: + ctrl |= MVNETA_GMAC2_PORT_RGMII; + break; + default: + return -EINVAL; + } /* Cancel Port Reset */ - val = mvreg_read(pp, MVNETA_GMAC_CTRL_2); - val &= ~MVNETA_GMAC2_PORT_RESET; - mvreg_write(pp, MVNETA_GMAC_CTRL_2, val); + ctrl &= ~MVNETA_GMAC2_PORT_RESET; + mvreg_write(pp, MVNETA_GMAC_CTRL_2, ctrl); while ((mvreg_read(pp, MVNETA_GMAC_CTRL_2) & MVNETA_GMAC2_PORT_RESET) != 0) continue; + + return 0; } /* Device initialization routine */ @@ -2879,7 +2869,12 @@ static int mvneta_probe(struct platform_device *pdev) dev_err(&pdev->dev, "can't init eth hal\n"); goto err_free_stats; } - mvneta_port_power_up(pp, phy_mode); + + err = mvneta_port_power_up(pp, phy_mode); + if (err < 0) { + dev_err(&pdev->dev, "can't power up port\n"); + goto err_deinit; + } dram_target_info = mv_mbus_dram_info(); if (dram_target_info) -- cgit v1.2.3-70-g09d2 From ff8ebe6448e98df59a8c7e7e93876f8f3d6a8b19 Mon Sep 17 00:00:00 2001 From: Tuomas Tynkkynen Date: Tue, 8 Apr 2014 09:15:22 +0300 Subject: staging: goldfish: Call free_irq in error path If misc_register failed in goldfish_audio_probe, the already requested IRQ wouldn't get freed. Add a call to free_irq() like there is in goldfish_audio_remove(). Signed-off-by: Tuomas Tynkkynen Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/staging/goldfish/goldfish_audio.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/staging/goldfish/goldfish_audio.c b/drivers/staging/goldfish/goldfish_audio.c index f96dcec740a..7ac2602242f 100644 --- a/drivers/staging/goldfish/goldfish_audio.c +++ b/drivers/staging/goldfish/goldfish_audio.c @@ -334,6 +334,7 @@ static int goldfish_audio_probe(struct platform_device *pdev) return 0; err_misc_register_failed: + free_irq(data->irq, data); err_request_irq_failed: dma_free_coherent(&pdev->dev, COMBINED_BUFFER_SIZE, data->buffer_virt, data->buffer_phys); -- cgit v1.2.3-70-g09d2 From ef35a4f44bdc6f8c9f99a561fd1fd318305a4d98 Mon Sep 17 00:00:00 2001 From: Daeseok Youn Date: Wed, 9 Apr 2014 19:45:46 +0900 Subject: staging: speakup: fix misuse of kstrtol() in handle_goto() A string of goto_buf has a number followed by x or y. e.g. "3x" means move 3 lines down. The kstrtol() returns an error(-EINVAL) with this string so go_pos has unsigned a value of that error. And also "*cp" has not expected value. And fix sparse warnings: drivers/staging/speakup/main.c:1901 handle_goto() warn: unsigned '(speakup_console[vc->vc_num]->go_pos)' is never less than zero. drivers/staging/speakup/main.c:1911 handle_goto() warn: unsigned '(speakup_console[vc->vc_num]->go_pos)' is never less than zero. Signed-off-by: Daeseok Youn Reviewed-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman --- drivers/staging/speakup/main.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/speakup/main.c b/drivers/staging/speakup/main.c index ef5933b9359..3b6e5358c72 100644 --- a/drivers/staging/speakup/main.c +++ b/drivers/staging/speakup/main.c @@ -1855,8 +1855,9 @@ static int handle_goto(struct vc_data *vc, u_char type, u_char ch, u_short key) { static u_char goto_buf[8]; static int num; - int maxlen, go_pos; + int maxlen; char *cp; + if (type == KT_SPKUP && ch == SPEAKUP_GOTO) goto do_goto; if (type == KT_LATIN && ch == '\n') @@ -1891,25 +1892,24 @@ oops: spk_special_handler = NULL; return 1; } - go_pos = kstrtol(goto_buf, 10, (long *)&cp); - goto_pos = (u_long) go_pos; + + goto_pos = simple_strtoul(goto_buf, &cp, 10); + if (*cp == 'x') { if (*goto_buf < '0') goto_pos += spk_x; - else + else if (goto_pos > 0) goto_pos--; - if (goto_pos < 0) - goto_pos = 0; + if (goto_pos >= vc->vc_cols) goto_pos = vc->vc_cols - 1; goto_x = 1; } else { if (*goto_buf < '0') goto_pos += spk_y; - else + else if (goto_pos > 0) goto_pos--; - if (goto_pos < 0) - goto_pos = 0; + if (goto_pos >= vc->vc_rows) goto_pos = vc->vc_rows - 1; goto_x = 0; -- cgit v1.2.3-70-g09d2 From d21bb45081484b95fb0c80f1afa492a7275689c2 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 10 Apr 2014 12:36:13 +0300 Subject: staging: unisys: use after free in error messages We dereference "bus" when we report the error so we have to move the kfree() down a couple lines. Signed-off-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman --- drivers/staging/unisys/uislib/uislib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/unisys/uislib/uislib.c b/drivers/staging/unisys/uislib/uislib.c index 8ea9c46e56a..3152a2180c4 100644 --- a/drivers/staging/unisys/uislib/uislib.c +++ b/drivers/staging/unisys/uislib/uislib.c @@ -381,17 +381,17 @@ create_bus(CONTROLVM_MESSAGE *msg, char *buf) cmd.add_vbus.busTypeGuid = msg->cmd.createBus.busDataTypeGuid; cmd.add_vbus.busInstGuid = msg->cmd.createBus.busInstGuid; if (!VirtControlChanFunc) { - kfree(bus); LOGERR("CONTROLVM_BUS_CREATE Failed: virtpci callback not registered."); POSTCODE_LINUX_3(BUS_CREATE_FAILURE_PC, bus->busNo, POSTCODE_SEVERITY_ERR); + kfree(bus); return CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_FAILURE; } if (!VirtControlChanFunc(&cmd)) { - kfree(bus); LOGERR("CONTROLVM_BUS_CREATE Failed: virtpci GUEST_ADD_VBUS returned error."); POSTCODE_LINUX_3(BUS_CREATE_FAILURE_PC, bus->busNo, POSTCODE_SEVERITY_ERR); + kfree(bus); return CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_CALLBACK_ERROR; } -- cgit v1.2.3-70-g09d2 From e6b1ea773e0a6dd611278d0d6f81ea6ff9d6938b Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 10 Apr 2014 12:45:45 +0300 Subject: Staging: unisys: use after free in list_for_each() These should be using the _safe version of list_for_each() because we free the current element and it leads to a use after free bug. Signed-off-by: Dan Carpenter Signed-off-by: Greg Kroah-Hartman --- drivers/staging/unisys/visorchipset/visorchipset.h | 4 ++-- drivers/staging/unisys/visorchipset/visorchipset_main.c | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/unisys/visorchipset/visorchipset.h b/drivers/staging/unisys/visorchipset/visorchipset.h index d4bf203cdfd..d95825dc541 100644 --- a/drivers/staging/unisys/visorchipset/visorchipset.h +++ b/drivers/staging/unisys/visorchipset/visorchipset.h @@ -104,9 +104,9 @@ finddevice(struct list_head *list, U32 busNo, U32 devNo) static inline void delbusdevices(struct list_head *list, U32 busNo) { - VISORCHIPSET_DEVICE_INFO *p; + VISORCHIPSET_DEVICE_INFO *p, *tmp; - list_for_each_entry(p, list, entry) { + list_for_each_entry_safe(p, tmp, list, entry) { if (p->busNo == busNo) { list_del(&p->entry); kfree(p); diff --git a/drivers/staging/unisys/visorchipset/visorchipset_main.c b/drivers/staging/unisys/visorchipset/visorchipset_main.c index 257c6e59b46..c475e256e34 100644 --- a/drivers/staging/unisys/visorchipset/visorchipset_main.c +++ b/drivers/staging/unisys/visorchipset/visorchipset_main.c @@ -605,16 +605,16 @@ EXPORT_SYMBOL_GPL(visorchipset_register_busdev_client); static void cleanup_controlvm_structures(void) { - VISORCHIPSET_BUS_INFO *bi; - VISORCHIPSET_DEVICE_INFO *di; + VISORCHIPSET_BUS_INFO *bi, *tmp_bi; + VISORCHIPSET_DEVICE_INFO *di, *tmp_di; - list_for_each_entry(bi, &BusInfoList, entry) { + list_for_each_entry_safe(bi, tmp_bi, &BusInfoList, entry) { busInfo_clear(bi); list_del(&bi->entry); kfree(bi); } - list_for_each_entry(di, &DevInfoList, entry) { + list_for_each_entry_safe(di, tmp_di, &DevInfoList, entry) { devInfo_clear(di); list_del(&di->entry); kfree(di); -- cgit v1.2.3-70-g09d2 From 2c33d7cc3875e75311d24a3bfe8d40ca201da2da Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 10 Apr 2014 19:46:56 +0200 Subject: staging: r8723au: Add missing initialization of change_inx in sort algorithm MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/staging/rtl8723au/core/rtw_wlan_util.c: In function ‘WMMOnAssocRsp23a’: drivers/staging/rtl8723au/core/rtw_wlan_util.c:684: warning: ‘change_inx’ may be used uninitialized in this function Depending on the uninitialized data on the stack, the array may not be sorted correctly. Signed-off-by: Geert Uytterhoeven Acked-by: Larry Finger Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8723au/core/rtw_wlan_util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8723au/core/rtw_wlan_util.c b/drivers/staging/rtl8723au/core/rtw_wlan_util.c index e743b053b8a..99d81e612e7 100644 --- a/drivers/staging/rtl8723au/core/rtw_wlan_util.c +++ b/drivers/staging/rtl8723au/core/rtw_wlan_util.c @@ -681,7 +681,7 @@ void WMMOnAssocRsp23a(struct rtw_adapter *padapter) inx[0] = 0; inx[1] = 1; inx[2] = 2; inx[3] = 3; if (pregpriv->wifi_spec == 1) { - u32 j, tmp, change_inx; + u32 j, tmp, change_inx = false; /* entry indx: 0->vo, 1->vi, 2->be, 3->bk. */ for (i = 0; i < 4; i++) { -- cgit v1.2.3-70-g09d2 From b34aa86f12e8848ba453215602c8c50fa63c4cb3 Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Thu, 10 Apr 2014 19:41:57 +0100 Subject: staging: comedi: fix circular locking dependency in comedi_mmap() Mmapping a comedi data buffer with lockdep checking enabled produced the following kernel debug messages: ====================================================== [ INFO: possible circular locking dependency detected ] 3.5.0-rc3-ija1+ #9 Tainted: G C ------------------------------------------------------- comedi_test/4160 is trying to acquire lock: (&dev->mutex#2){+.+.+.}, at: [] comedi_mmap+0x57/0x1d9 [comedi] but task is already holding lock: (&mm->mmap_sem){++++++}, at: [] vm_mmap_pgoff+0x41/0x76 which lock already depends on the new lock. the existing dependency chain (in reverse order) is: -> #1 (&mm->mmap_sem){++++++}: [] lock_acquire+0x97/0x105 [] might_fault+0x6d/0x90 [] do_devinfo_ioctl.isra.7+0x11e/0x14c [comedi] [] comedi_unlocked_ioctl+0x256/0xe48 [comedi] [] vfs_ioctl+0x18/0x34 [] do_vfs_ioctl+0x382/0x43c [] sys_ioctl+0x42/0x65 [] system_call_fastpath+0x16/0x1b -> #0 (&dev->mutex#2){+.+.+.}: [] __lock_acquire+0x101d/0x1591 [] lock_acquire+0x97/0x105 [] mutex_lock_nested+0x46/0x2a4 [] comedi_mmap+0x57/0x1d9 [comedi] [] mmap_region+0x281/0x492 [] do_mmap_pgoff+0x26b/0x2a7 [] vm_mmap_pgoff+0x5d/0x76 [] sys_mmap_pgoff+0xc7/0x10d [] sys_mmap+0x16/0x20 [] system_call_fastpath+0x16/0x1b other info that might help us debug this: Possible unsafe locking scenario: CPU0 CPU1 ---- ---- lock(&mm->mmap_sem); lock(&dev->mutex#2); lock(&mm->mmap_sem); lock(&dev->mutex#2); *** DEADLOCK *** To avoid the circular dependency, just try to get the lock in `comedi_mmap()` instead of blocking. Since the comedi device's main mutex is heavily used, do a down-read of its `attach_lock` rwsemaphore instead. Trying to down-read `attach_lock` should only fail if some task has down-write locked it, and that is only done while the comedi device is being attached to or detached from a low-level hardware device. Unfortunately, acquiring the `attach_lock` doesn't prevent another task replacing the comedi data buffer we are trying to mmap. The details of the buffer are held in a `struct comedi_buf_map` and pointed to by `s->async->buf_map` where `s` is the comedi subdevice whose buffer we are trying to map. The `struct comedi_buf_map` is already reference counted with a `struct kref`, so we can stop it being freed prematurely. Modify `comedi_mmap()` to call new function `comedi_buf_map_from_subdev_get()` to read the subdevice's current buffer map pointer and increment its reference instead of accessing `async->buf_map` directly. Call `comedi_buf_map_put()` to decrement the reference once the buffer map structure has been dealt with. (Note that `comedi_buf_map_put()` does nothing if passed a NULL pointer.) `comedi_buf_map_from_subdev_get()` checks the subdevice's buffer map pointer has been set and the buffer map has been initialized enough for `comedi_mmap()` to deal with it (specifically, check the `n_pages` member has been set to a non-zero value). If all is well, the buffer map's reference is incremented and a pointer to it is returned. The comedi subdevice's spin-lock is used to protect the checks. Also use the spin-lock in `__comedi_buf_alloc()` and `__comedi_buf_free()` to protect changes to the subdevice's buffer map structure pointer and the buffer map structure's `n_pages` member. (This checking of `n_pages` is a bit clunky and I [Ian Abbott] plan to deal with it in the future.) Signed-off-by: Ian Abbott Cc: # 3.14.x, 3.15.x Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/comedi_buf.c | 37 ++++++++++++++++++++++++++++++-- drivers/staging/comedi/comedi_fops.c | 18 ++++++++++++---- drivers/staging/comedi/comedi_internal.h | 2 ++ 3 files changed, 51 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/comedi/comedi_buf.c b/drivers/staging/comedi/comedi_buf.c index 924fce97798..25759501616 100644 --- a/drivers/staging/comedi/comedi_buf.c +++ b/drivers/staging/comedi/comedi_buf.c @@ -61,6 +61,8 @@ static void __comedi_buf_free(struct comedi_device *dev, struct comedi_subdevice *s) { struct comedi_async *async = s->async; + struct comedi_buf_map *bm; + unsigned long flags; if (async->prealloc_buf) { vunmap(async->prealloc_buf); @@ -68,8 +70,11 @@ static void __comedi_buf_free(struct comedi_device *dev, async->prealloc_bufsz = 0; } - comedi_buf_map_put(async->buf_map); + spin_lock_irqsave(&s->spin_lock, flags); + bm = async->buf_map; async->buf_map = NULL; + spin_unlock_irqrestore(&s->spin_lock, flags); + comedi_buf_map_put(bm); } static void __comedi_buf_alloc(struct comedi_device *dev, @@ -80,6 +85,7 @@ static void __comedi_buf_alloc(struct comedi_device *dev, struct page **pages = NULL; struct comedi_buf_map *bm; struct comedi_buf_page *buf; + unsigned long flags; unsigned i; if (!IS_ENABLED(CONFIG_HAS_DMA) && s->async_dma_dir != DMA_NONE) { @@ -92,8 +98,10 @@ static void __comedi_buf_alloc(struct comedi_device *dev, if (!bm) return; - async->buf_map = bm; kref_init(&bm->refcount); + spin_lock_irqsave(&s->spin_lock, flags); + async->buf_map = bm; + spin_unlock_irqrestore(&s->spin_lock, flags); bm->dma_dir = s->async_dma_dir; if (bm->dma_dir != DMA_NONE) /* Need ref to hardware device to free buffer later. */ @@ -127,7 +135,9 @@ static void __comedi_buf_alloc(struct comedi_device *dev, pages[i] = virt_to_page(buf->virt_addr); } + spin_lock_irqsave(&s->spin_lock, flags); bm->n_pages = i; + spin_unlock_irqrestore(&s->spin_lock, flags); /* vmap the prealloc_buf if all the pages were allocated */ if (i == n_pages) @@ -150,6 +160,29 @@ int comedi_buf_map_put(struct comedi_buf_map *bm) return 1; } +/* returns s->async->buf_map and increments its kref refcount */ +struct comedi_buf_map * +comedi_buf_map_from_subdev_get(struct comedi_subdevice *s) +{ + struct comedi_async *async = s->async; + struct comedi_buf_map *bm = NULL; + unsigned long flags; + + if (!async) + return NULL; + + spin_lock_irqsave(&s->spin_lock, flags); + bm = async->buf_map; + /* only want it if buffer pages allocated */ + if (bm && bm->n_pages) + comedi_buf_map_get(bm); + else + bm = NULL; + spin_unlock_irqrestore(&s->spin_lock, flags); + + return bm; +} + bool comedi_buf_is_mmapped(struct comedi_async *async) { struct comedi_buf_map *bm = async->buf_map; diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c index ea6dc36d753..acc80197e35 100644 --- a/drivers/staging/comedi/comedi_fops.c +++ b/drivers/staging/comedi/comedi_fops.c @@ -1926,14 +1926,21 @@ static int comedi_mmap(struct file *file, struct vm_area_struct *vma) struct comedi_device *dev = file->private_data; struct comedi_subdevice *s; struct comedi_async *async; - struct comedi_buf_map *bm; + struct comedi_buf_map *bm = NULL; unsigned long start = vma->vm_start; unsigned long size; int n_pages; int i; int retval; - mutex_lock(&dev->mutex); + /* + * 'trylock' avoids circular dependency with current->mm->mmap_sem + * and down-reading &dev->attach_lock should normally succeed without + * contention unless the device is in the process of being attached + * or detached. + */ + if (!down_read_trylock(&dev->attach_lock)) + return -EAGAIN; if (!dev->attached) { dev_dbg(dev->class_dev, "no driver attached\n"); @@ -1973,7 +1980,9 @@ static int comedi_mmap(struct file *file, struct vm_area_struct *vma) } n_pages = size >> PAGE_SHIFT; - bm = async->buf_map; + + /* get reference to current buf map (if any) */ + bm = comedi_buf_map_from_subdev_get(s); if (!bm || n_pages > bm->n_pages) { retval = -EINVAL; goto done; @@ -1997,7 +2006,8 @@ static int comedi_mmap(struct file *file, struct vm_area_struct *vma) retval = 0; done: - mutex_unlock(&dev->mutex); + up_read(&dev->attach_lock); + comedi_buf_map_put(bm); /* put reference to buf map - okay if NULL */ return retval; } diff --git a/drivers/staging/comedi/comedi_internal.h b/drivers/staging/comedi/comedi_internal.h index 9a746570f16..a492f2d2436 100644 --- a/drivers/staging/comedi/comedi_internal.h +++ b/drivers/staging/comedi/comedi_internal.h @@ -19,6 +19,8 @@ void comedi_buf_reset(struct comedi_async *async); bool comedi_buf_is_mmapped(struct comedi_async *async); void comedi_buf_map_get(struct comedi_buf_map *bm); int comedi_buf_map_put(struct comedi_buf_map *bm); +struct comedi_buf_map *comedi_buf_map_from_subdev_get( + struct comedi_subdevice *s); unsigned int comedi_buf_write_n_allocated(struct comedi_async *async); void comedi_device_cancel_all(struct comedi_device *dev); -- cgit v1.2.3-70-g09d2 From 9452bf560273e4de2395ffdd79024debfb0c1290 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Wed, 9 Apr 2014 11:12:58 -0500 Subject: staging: r8188eu: Calling rtw_get_stainfo() with a NULL sta_addr will return NULL This makes the follow-on check for psta != NULL pointless and makes the whole exercise rather pointless. This is another case of why blindly zero-initializing variables when they are declared is bad. Reported-by: Jes Sorensen Signed-off-by: Larry Finger Cc: Stable Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8188eu/core/rtw_recv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8188eu/core/rtw_recv.c b/drivers/staging/rtl8188eu/core/rtw_recv.c index 636ec553ae8..01fcabcc8e5 100644 --- a/drivers/staging/rtl8188eu/core/rtw_recv.c +++ b/drivers/staging/rtl8188eu/core/rtw_recv.c @@ -545,7 +545,7 @@ static struct recv_frame *decryptor(struct adapter *padapter, static struct recv_frame *portctrl(struct adapter *adapter, struct recv_frame *precv_frame) { - u8 *psta_addr = NULL, *ptr; + u8 *psta_addr, *ptr; uint auth_alg; struct recv_frame *pfhdr; struct sta_info *psta; @@ -558,7 +558,6 @@ static struct recv_frame *portctrl(struct adapter *adapter, pstapriv = &adapter->stapriv; - psta = rtw_get_stainfo(pstapriv, psta_addr); auth_alg = adapter->securitypriv.dot11AuthAlgrthm; @@ -566,6 +565,7 @@ static struct recv_frame *portctrl(struct adapter *adapter, pfhdr = precv_frame; pattrib = &pfhdr->attrib; psta_addr = pattrib->ta; + psta = rtw_get_stainfo(pstapriv, psta_addr); prtnframe = NULL; -- cgit v1.2.3-70-g09d2 From 33ac1257ff0dee2e9c7f009b1c1914b7990217b2 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 10 Jan 2014 08:57:31 -0500 Subject: sysfs, driver-core: remove unused {sysfs|device}_schedule_callback_owner() All device_schedule_callback_owner() users are converted to use device_remove_file_self(). Remove now unused {sysfs|device}_schedule_callback_owner(). Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- drivers/base/core.c | 33 ------------------ fs/sysfs/file.c | 92 -------------------------------------------------- include/linux/device.h | 11 +----- include/linux/sysfs.h | 9 ----- 4 files changed, 1 insertion(+), 144 deletions(-) (limited to 'drivers') diff --git a/drivers/base/core.c b/drivers/base/core.c index 0dd65281cc6..20da3ad1696 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -614,39 +614,6 @@ void device_remove_bin_file(struct device *dev, } EXPORT_SYMBOL_GPL(device_remove_bin_file); -/** - * device_schedule_callback_owner - helper to schedule a callback for a device - * @dev: device. - * @func: callback function to invoke later. - * @owner: module owning the callback routine - * - * Attribute methods must not unregister themselves or their parent device - * (which would amount to the same thing). Attempts to do so will deadlock, - * since unregistration is mutually exclusive with driver callbacks. - * - * Instead methods can call this routine, which will attempt to allocate - * and schedule a workqueue request to call back @func with @dev as its - * argument in the workqueue's process context. @dev will be pinned until - * @func returns. - * - * This routine is usually called via the inline device_schedule_callback(), - * which automatically sets @owner to THIS_MODULE. - * - * Returns 0 if the request was submitted, -ENOMEM if storage could not - * be allocated, -ENODEV if a reference to @owner isn't available. - * - * NOTE: This routine won't work if CONFIG_SYSFS isn't set! It uses an - * underlying sysfs routine (since it is intended for use by attribute - * methods), and if sysfs isn't available you'll get nothing but -ENOSYS. - */ -int device_schedule_callback_owner(struct device *dev, - void (*func)(struct device *), struct module *owner) -{ - return sysfs_schedule_callback(&dev->kobj, - (void (*)(void *)) func, dev, owner); -} -EXPORT_SYMBOL_GPL(device_schedule_callback_owner); - static void klist_children_get(struct klist_node *n) { struct device_private *p = to_device_private_parent(n); diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index 1b8b91b67fd..28cc1acd543 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -453,95 +453,3 @@ void sysfs_remove_bin_file(struct kobject *kobj, kernfs_remove_by_name(kobj->sd, attr->attr.name); } EXPORT_SYMBOL_GPL(sysfs_remove_bin_file); - -struct sysfs_schedule_callback_struct { - struct list_head workq_list; - struct kobject *kobj; - void (*func)(void *); - void *data; - struct module *owner; - struct work_struct work; -}; - -static struct workqueue_struct *sysfs_workqueue; -static DEFINE_MUTEX(sysfs_workq_mutex); -static LIST_HEAD(sysfs_workq); -static void sysfs_schedule_callback_work(struct work_struct *work) -{ - struct sysfs_schedule_callback_struct *ss = container_of(work, - struct sysfs_schedule_callback_struct, work); - - (ss->func)(ss->data); - kobject_put(ss->kobj); - module_put(ss->owner); - mutex_lock(&sysfs_workq_mutex); - list_del(&ss->workq_list); - mutex_unlock(&sysfs_workq_mutex); - kfree(ss); -} - -/** - * sysfs_schedule_callback - helper to schedule a callback for a kobject - * @kobj: object we're acting for. - * @func: callback function to invoke later. - * @data: argument to pass to @func. - * @owner: module owning the callback code - * - * sysfs attribute methods must not unregister themselves or their parent - * kobject (which would amount to the same thing). Attempts to do so will - * deadlock, since unregistration is mutually exclusive with driver - * callbacks. - * - * Instead methods can call this routine, which will attempt to allocate - * and schedule a workqueue request to call back @func with @data as its - * argument in the workqueue's process context. @kobj will be pinned - * until @func returns. - * - * Returns 0 if the request was submitted, -ENOMEM if storage could not - * be allocated, -ENODEV if a reference to @owner isn't available, - * -EAGAIN if a callback has already been scheduled for @kobj. - */ -int sysfs_schedule_callback(struct kobject *kobj, void (*func)(void *), - void *data, struct module *owner) -{ - struct sysfs_schedule_callback_struct *ss, *tmp; - - if (!try_module_get(owner)) - return -ENODEV; - - mutex_lock(&sysfs_workq_mutex); - list_for_each_entry_safe(ss, tmp, &sysfs_workq, workq_list) - if (ss->kobj == kobj) { - module_put(owner); - mutex_unlock(&sysfs_workq_mutex); - return -EAGAIN; - } - mutex_unlock(&sysfs_workq_mutex); - - if (sysfs_workqueue == NULL) { - sysfs_workqueue = create_singlethread_workqueue("sysfsd"); - if (sysfs_workqueue == NULL) { - module_put(owner); - return -ENOMEM; - } - } - - ss = kmalloc(sizeof(*ss), GFP_KERNEL); - if (!ss) { - module_put(owner); - return -ENOMEM; - } - kobject_get(kobj); - ss->kobj = kobj; - ss->func = func; - ss->data = data; - ss->owner = owner; - INIT_WORK(&ss->work, sysfs_schedule_callback_work); - INIT_LIST_HEAD(&ss->workq_list); - mutex_lock(&sysfs_workq_mutex); - list_add_tail(&ss->workq_list, &sysfs_workq); - mutex_unlock(&sysfs_workq_mutex); - queue_work(sysfs_workqueue, &ss->work); - return 0; -} -EXPORT_SYMBOL_GPL(sysfs_schedule_callback); diff --git a/include/linux/device.h b/include/linux/device.h index 233bbbeb768..d1d1c055b48 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -566,12 +566,6 @@ extern int __must_check device_create_bin_file(struct device *dev, const struct bin_attribute *attr); extern void device_remove_bin_file(struct device *dev, const struct bin_attribute *attr); -extern int device_schedule_callback_owner(struct device *dev, - void (*func)(struct device *dev), struct module *owner); - -/* This is a macro to avoid include problems with THIS_MODULE */ -#define device_schedule_callback(dev, func) \ - device_schedule_callback_owner(dev, func, THIS_MODULE) /* device resource management */ typedef void (*dr_release_t)(struct device *dev, void *res); @@ -932,10 +926,7 @@ extern int device_online(struct device *dev); extern struct device *__root_device_register(const char *name, struct module *owner); -/* - * This is a macro to avoid include problems with THIS_MODULE, - * just as per what is done for device_schedule_callback() above. - */ +/* This is a macro to avoid include problems with THIS_MODULE */ #define root_device_register(name) \ __root_device_register(name, THIS_MODULE) diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h index 084354b0e81..5ffaa344371 100644 --- a/include/linux/sysfs.h +++ b/include/linux/sysfs.h @@ -179,9 +179,6 @@ struct sysfs_ops { #ifdef CONFIG_SYSFS -int sysfs_schedule_callback(struct kobject *kobj, void (*func)(void *), - void *data, struct module *owner); - int __must_check sysfs_create_dir_ns(struct kobject *kobj, const void *ns); void sysfs_remove_dir(struct kobject *kobj); int __must_check sysfs_rename_dir_ns(struct kobject *kobj, const char *new_name, @@ -255,12 +252,6 @@ static inline void sysfs_enable_ns(struct kernfs_node *kn) #else /* CONFIG_SYSFS */ -static inline int sysfs_schedule_callback(struct kobject *kobj, - void (*func)(void *), void *data, struct module *owner) -{ - return -ENOSYS; -} - static inline int sysfs_create_dir_ns(struct kobject *kobj, const void *ns) { return 0; -- cgit v1.2.3-70-g09d2 From c98235cb8584a72e95786e17d695a8e5fafcd766 Mon Sep 17 00:00:00 2001 From: Chris Mason Date: Tue, 15 Apr 2014 18:09:24 -0400 Subject: mlx4_en: don't use napi_synchronize inside mlx4_en_netpoll The mlx4 driver is triggering schedules while atomic inside mlx4_en_netpoll: spin_lock_irqsave(&cq->lock, flags); napi_synchronize(&cq->napi); ^^^^^ msleep here mlx4_en_process_rx_cq(dev, cq, 0); spin_unlock_irqrestore(&cq->lock, flags); This was part of a patch by Alexander Guller from Mellanox in 2011, but it still isn't upstream. Signed-off-by: Chris Mason cc: stable@vger.kernel.org Acked-By: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/en_cq.c | 1 - drivers/net/ethernet/mellanox/mlx4/en_netdev.c | 6 +----- drivers/net/ethernet/mellanox/mlx4/mlx4_en.h | 1 - 3 files changed, 1 insertion(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx4/en_cq.c b/drivers/net/ethernet/mellanox/mlx4/en_cq.c index 70e95324a97..c2cd8d31bca 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_cq.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_cq.c @@ -66,7 +66,6 @@ int mlx4_en_create_cq(struct mlx4_en_priv *priv, cq->ring = ring; cq->is_tx = mode; - spin_lock_init(&cq->lock); /* Allocate HW buffers on provided NUMA node. * dev->numa_node is used in mtt range allocation flow. diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index f085c2df5e6..7e4b1720c3d 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -1304,15 +1304,11 @@ static void mlx4_en_netpoll(struct net_device *dev) { struct mlx4_en_priv *priv = netdev_priv(dev); struct mlx4_en_cq *cq; - unsigned long flags; int i; for (i = 0; i < priv->rx_ring_num; i++) { cq = priv->rx_cq[i]; - spin_lock_irqsave(&cq->lock, flags); - napi_synchronize(&cq->napi); - mlx4_en_process_rx_cq(dev, cq, 0); - spin_unlock_irqrestore(&cq->lock, flags); + napi_schedule(&cq->napi); } } #endif diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h index 7a733c28774..04d9b6fe3e8 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h @@ -319,7 +319,6 @@ struct mlx4_en_cq { struct mlx4_cq mcq; struct mlx4_hwq_resources wqres; int ring; - spinlock_t lock; struct net_device *dev; struct napi_struct napi; int size; -- cgit v1.2.3-70-g09d2 From 78cdb079685cd8365acaf9fce896137e7d60e1c1 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 15 Apr 2014 19:16:40 -0700 Subject: net: mdio-gpio: Use devm_ functions where possible This simplifies error path and deinit/removal functions. Signed-off-by: Guenter Roeck Tested-by: Chris Healy Signed-off-by: David S. Miller --- drivers/net/phy/mdio-gpio.c | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/mdio-gpio.c b/drivers/net/phy/mdio-gpio.c index e701433bf52..e853066c805 100644 --- a/drivers/net/phy/mdio-gpio.c +++ b/drivers/net/phy/mdio-gpio.c @@ -110,7 +110,7 @@ static struct mii_bus *mdio_gpio_bus_init(struct device *dev, struct mdio_gpio_info *bitbang; int i; - bitbang = kzalloc(sizeof(*bitbang), GFP_KERNEL); + bitbang = devm_kzalloc(dev, sizeof(*bitbang), GFP_KERNEL); if (!bitbang) goto out; @@ -121,7 +121,7 @@ static struct mii_bus *mdio_gpio_bus_init(struct device *dev, new_bus = alloc_mdio_bitbang(&bitbang->ctrl); if (!new_bus) - goto out_free_bitbang; + goto out; new_bus->name = "GPIO Bitbanged MDIO", @@ -138,11 +138,11 @@ static struct mii_bus *mdio_gpio_bus_init(struct device *dev, snprintf(new_bus->id, MII_BUS_ID_SIZE, "gpio-%x", bus_id); - if (gpio_request(bitbang->mdc, "mdc")) + if (devm_gpio_request(dev, bitbang->mdc, "mdc")) goto out_free_bus; - if (gpio_request(bitbang->mdio, "mdio")) - goto out_free_mdc; + if (devm_gpio_request(dev, bitbang->mdio, "mdio")) + goto out_free_bus; gpio_direction_output(bitbang->mdc, 0); @@ -150,12 +150,8 @@ static struct mii_bus *mdio_gpio_bus_init(struct device *dev, return new_bus; -out_free_mdc: - gpio_free(bitbang->mdc); out_free_bus: free_mdio_bitbang(new_bus); -out_free_bitbang: - kfree(bitbang); out: return NULL; } @@ -163,13 +159,8 @@ out: static void mdio_gpio_bus_deinit(struct device *dev) { struct mii_bus *bus = dev_get_drvdata(dev); - struct mdio_gpio_info *bitbang = bus->priv; - dev_set_drvdata(dev, NULL); - gpio_free(bitbang->mdio); - gpio_free(bitbang->mdc); free_mdio_bitbang(bus); - kfree(bitbang); } static void mdio_gpio_bus_destroy(struct device *dev) -- cgit v1.2.3-70-g09d2 From 1d2514818a2c3d94dd250e6027cb928a4e192548 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 15 Apr 2014 19:16:41 -0700 Subject: net: mdio-gpio: Add support for active low gpio pins Some systems using mdio-gpio may use active-low gpio pins (eg with inverters or FETs connected to all or some of the gpio pins). Signed-off-by: Guenter Roeck Signed-off-by: David S. Miller --- drivers/net/phy/mdio-gpio.c | 19 +++++++++++++------ include/linux/mdio-gpio.h | 3 +++ 2 files changed, 16 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/mdio-gpio.c b/drivers/net/phy/mdio-gpio.c index e853066c805..fac211a5001 100644 --- a/drivers/net/phy/mdio-gpio.c +++ b/drivers/net/phy/mdio-gpio.c @@ -33,28 +33,32 @@ struct mdio_gpio_info { struct mdiobb_ctrl ctrl; int mdc, mdio; + int mdc_active_low, mdio_active_low; }; static void *mdio_gpio_of_get_data(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; struct mdio_gpio_platform_data *pdata; + enum of_gpio_flags flags; int ret; pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) return NULL; - ret = of_get_gpio(np, 0); + ret = of_get_gpio_flags(np, 0, &flags); if (ret < 0) return NULL; pdata->mdc = ret; + pdata->mdc_active_low = flags & OF_GPIO_ACTIVE_LOW; - ret = of_get_gpio(np, 1); + ret = of_get_gpio_flags(np, 1, &flags); if (ret < 0) return NULL; pdata->mdio = ret; + pdata->mdio_active_low = flags & OF_GPIO_ACTIVE_LOW; return pdata; } @@ -65,7 +69,8 @@ static void mdio_dir(struct mdiobb_ctrl *ctrl, int dir) container_of(ctrl, struct mdio_gpio_info, ctrl); if (dir) - gpio_direction_output(bitbang->mdio, 1); + gpio_direction_output(bitbang->mdio, + 1 ^ bitbang->mdio_active_low); else gpio_direction_input(bitbang->mdio); } @@ -75,7 +80,7 @@ static int mdio_get(struct mdiobb_ctrl *ctrl) struct mdio_gpio_info *bitbang = container_of(ctrl, struct mdio_gpio_info, ctrl); - return gpio_get_value(bitbang->mdio); + return gpio_get_value(bitbang->mdio) ^ bitbang->mdio_active_low; } static void mdio_set(struct mdiobb_ctrl *ctrl, int what) @@ -83,7 +88,7 @@ static void mdio_set(struct mdiobb_ctrl *ctrl, int what) struct mdio_gpio_info *bitbang = container_of(ctrl, struct mdio_gpio_info, ctrl); - gpio_set_value(bitbang->mdio, what); + gpio_set_value(bitbang->mdio, what ^ bitbang->mdio_active_low); } static void mdc_set(struct mdiobb_ctrl *ctrl, int what) @@ -91,7 +96,7 @@ static void mdc_set(struct mdiobb_ctrl *ctrl, int what) struct mdio_gpio_info *bitbang = container_of(ctrl, struct mdio_gpio_info, ctrl); - gpio_set_value(bitbang->mdc, what); + gpio_set_value(bitbang->mdc, what ^ bitbang->mdc_active_low); } static struct mdiobb_ops mdio_gpio_ops = { @@ -117,7 +122,9 @@ static struct mii_bus *mdio_gpio_bus_init(struct device *dev, bitbang->ctrl.ops = &mdio_gpio_ops; bitbang->ctrl.reset = pdata->reset; bitbang->mdc = pdata->mdc; + bitbang->mdc_active_low = pdata->mdc_active_low; bitbang->mdio = pdata->mdio; + bitbang->mdio_active_low = pdata->mdio_active_low; new_bus = alloc_mdio_bitbang(&bitbang->ctrl); if (!new_bus) diff --git a/include/linux/mdio-gpio.h b/include/linux/mdio-gpio.h index 7c9fe3c2be7..57e57fe6055 100644 --- a/include/linux/mdio-gpio.h +++ b/include/linux/mdio-gpio.h @@ -18,6 +18,9 @@ struct mdio_gpio_platform_data { unsigned int mdc; unsigned int mdio; + bool mdc_active_low; + bool mdio_active_low; + unsigned int phy_mask; int irqs[PHY_MAX_ADDR]; /* reset callback */ -- cgit v1.2.3-70-g09d2 From f1d54c47502f42f5c4b89dacbe845ecd87ca002e Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 15 Apr 2014 19:16:42 -0700 Subject: net: mdio-gpio: Add support for separate MDI and MDO gpio pins This is for a system with fixed assignments of input and output pins (various variants of Kontron COMe). Signed-off-by: Guenter Roeck Signed-off-by: David S. Miller --- drivers/net/phy/mdio-gpio.c | 34 +++++++++++++++++++++++++++++++--- include/linux/mdio-gpio.h | 2 ++ 2 files changed, 33 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/mdio-gpio.c b/drivers/net/phy/mdio-gpio.c index fac211a5001..9c4defdec67 100644 --- a/drivers/net/phy/mdio-gpio.c +++ b/drivers/net/phy/mdio-gpio.c @@ -32,8 +32,8 @@ struct mdio_gpio_info { struct mdiobb_ctrl ctrl; - int mdc, mdio; - int mdc_active_low, mdio_active_low; + int mdc, mdio, mdo; + int mdc_active_low, mdio_active_low, mdo_active_low; }; static void *mdio_gpio_of_get_data(struct platform_device *pdev) @@ -60,6 +60,12 @@ static void *mdio_gpio_of_get_data(struct platform_device *pdev) pdata->mdio = ret; pdata->mdio_active_low = flags & OF_GPIO_ACTIVE_LOW; + ret = of_get_gpio_flags(np, 2, &flags); + if (ret > 0) { + pdata->mdo = ret; + pdata->mdo_active_low = flags & OF_GPIO_ACTIVE_LOW; + } + return pdata; } @@ -68,6 +74,16 @@ static void mdio_dir(struct mdiobb_ctrl *ctrl, int dir) struct mdio_gpio_info *bitbang = container_of(ctrl, struct mdio_gpio_info, ctrl); + if (bitbang->mdo) { + /* Separate output pin. Always set its value to high + * when changing direction. If direction is input, + * assume the pin serves as pull-up. If direction is + * output, the default value is high. + */ + gpio_set_value(bitbang->mdo, 1 ^ bitbang->mdo_active_low); + return; + } + if (dir) gpio_direction_output(bitbang->mdio, 1 ^ bitbang->mdio_active_low); @@ -88,7 +104,10 @@ static void mdio_set(struct mdiobb_ctrl *ctrl, int what) struct mdio_gpio_info *bitbang = container_of(ctrl, struct mdio_gpio_info, ctrl); - gpio_set_value(bitbang->mdio, what ^ bitbang->mdio_active_low); + if (bitbang->mdo) + gpio_set_value(bitbang->mdo, what ^ bitbang->mdo_active_low); + else + gpio_set_value(bitbang->mdio, what ^ bitbang->mdio_active_low); } static void mdc_set(struct mdiobb_ctrl *ctrl, int what) @@ -125,6 +144,8 @@ static struct mii_bus *mdio_gpio_bus_init(struct device *dev, bitbang->mdc_active_low = pdata->mdc_active_low; bitbang->mdio = pdata->mdio; bitbang->mdio_active_low = pdata->mdio_active_low; + bitbang->mdo = pdata->mdo; + bitbang->mdo_active_low = pdata->mdo_active_low; new_bus = alloc_mdio_bitbang(&bitbang->ctrl); if (!new_bus) @@ -151,6 +172,13 @@ static struct mii_bus *mdio_gpio_bus_init(struct device *dev, if (devm_gpio_request(dev, bitbang->mdio, "mdio")) goto out_free_bus; + if (bitbang->mdo) { + if (devm_gpio_request(dev, bitbang->mdo, "mdo")) + goto out_free_bus; + gpio_direction_output(bitbang->mdo, 1); + gpio_direction_input(bitbang->mdio); + } + gpio_direction_output(bitbang->mdc, 0); dev_set_drvdata(dev, new_bus); diff --git a/include/linux/mdio-gpio.h b/include/linux/mdio-gpio.h index 57e57fe6055..66c30a763b1 100644 --- a/include/linux/mdio-gpio.h +++ b/include/linux/mdio-gpio.h @@ -17,9 +17,11 @@ struct mdio_gpio_platform_data { /* GPIO numbers for bus pins */ unsigned int mdc; unsigned int mdio; + unsigned int mdo; bool mdc_active_low; bool mdio_active_low; + bool mdo_active_low; unsigned int phy_mask; int irqs[PHY_MAX_ADDR]; -- cgit v1.2.3-70-g09d2 From 5c5e0589038537848849fc827f5234a31a10f899 Mon Sep 17 00:00:00 2001 From: Frank Haverkamp Date: Thu, 20 Mar 2014 15:11:02 +0100 Subject: GenWQE: Enable access to VPD flash area In addition to the two flash partitions we used so far, there is a 3rd one which is enabled for usage by this fix. Signed-off-by: Frank Haverkamp Signed-off-by: Greg Kroah-Hartman --- drivers/misc/genwqe/card_dev.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/misc/genwqe/card_dev.c b/drivers/misc/genwqe/card_dev.c index 2c2c9cc7523..0d05ca77c45 100644 --- a/drivers/misc/genwqe/card_dev.c +++ b/drivers/misc/genwqe/card_dev.c @@ -531,7 +531,9 @@ static int do_flash_update(struct genwqe_file *cfile, case '1': cmdopts = 0x1C; break; /* download/erase_first/part_1 */ - case 'v': /* cmdopts = 0x0c (VPD) */ + case 'v': + cmdopts = 0x0C; + break; /* download/erase_first/vpd */ default: return -EINVAL; } @@ -665,6 +667,8 @@ static int do_flash_read(struct genwqe_file *cfile, cmdopts = 0x1A; break; /* upload/part_1 */ case 'v': + cmdopts = 0x0A; + break; /* upload/vpd */ default: return -EINVAL; } -- cgit v1.2.3-70-g09d2 From 68fe8acc204c7fbefd4c01b8929fedb244ec283d Mon Sep 17 00:00:00 2001 From: Frank Haverkamp Date: Thu, 20 Mar 2014 15:11:03 +0100 Subject: GenWQE: Add wmb before DDCB is started Needed to add wmb() before we send the DDCB for execution. Without the syncronizing it failed on System p. Signed-off-by: Frank Haverkamp Signed-off-by: Greg Kroah-Hartman --- drivers/misc/genwqe/card_ddcb.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/misc/genwqe/card_ddcb.c b/drivers/misc/genwqe/card_ddcb.c index 6f1acc0ccf8..29a1a28be02 100644 --- a/drivers/misc/genwqe/card_ddcb.c +++ b/drivers/misc/genwqe/card_ddcb.c @@ -305,6 +305,8 @@ static int enqueue_ddcb(struct genwqe_dev *cd, struct ddcb_queue *queue, break; new = (old | DDCB_NEXT_BE32); + + wmb(); icrc_hsi_shi = cmpxchg(&prev_ddcb->icrc_hsi_shi_32, old, new); if (icrc_hsi_shi == old) @@ -314,6 +316,8 @@ static int enqueue_ddcb(struct genwqe_dev *cd, struct ddcb_queue *queue, /* Queue must be re-started by updating QUEUE_OFFSET */ ddcb_mark_tapped(pddcb); num = (u64)ddcb_no << 8; + + wmb(); __genwqe_writeq(cd, queue->IO_QUEUE_OFFSET, num); /* start queue */ return RET_DDCB_TAPPED; -- cgit v1.2.3-70-g09d2 From ebb2c96bb9214ba38c7fe35d5d725f6e7cb3bbc8 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 20 Mar 2014 15:11:04 +0100 Subject: GenWQE: Ensure rc is not returning an uninitialized value rc is not initialized, so genwqe_finish_queue() either returns -EIO or garbage. Fortunately the return is not being checked by any callers, so this has not yet caused any problems. Even so, it makes sense to fix this small bug in case is is checked in future. Signed-off-by: Colin Ian King Signed-off-by: Frank Haverkamp Signed-off-by: Greg Kroah-Hartman --- drivers/misc/genwqe/card_ddcb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/misc/genwqe/card_ddcb.c b/drivers/misc/genwqe/card_ddcb.c index 29a1a28be02..c8046db2d5a 100644 --- a/drivers/misc/genwqe/card_ddcb.c +++ b/drivers/misc/genwqe/card_ddcb.c @@ -1310,7 +1310,7 @@ static int queue_wake_up_all(struct genwqe_dev *cd) */ int genwqe_finish_queue(struct genwqe_dev *cd) { - int i, rc, in_flight; + int i, rc = 0, in_flight; int waitmax = genwqe_ddcb_software_timeout; struct pci_dev *pci_dev = cd->pci_dev; struct ddcb_queue *queue = &cd->queue; -- cgit v1.2.3-70-g09d2 From 718f762efc454796d02f172a929d051f2d6ec01a Mon Sep 17 00:00:00 2001 From: Frank Haverkamp Date: Thu, 20 Mar 2014 15:11:05 +0100 Subject: GenWQE: Fix multithreading problems When being used in a multithreaded application there were problems with memory pages/cachelines accessed by multiple threads/cpus at the same time, while doing DMA transfers to/from those. To avoid such situations this fix is creating a copy of the first and the last page if it is not fully used. The data is copied from user-space into those pages and results are copied back when the DDCB-request is successfully finished. Signed-off-by: Frank Haverkamp Signed-off-by: Greg Kroah-Hartman --- drivers/misc/genwqe/card_base.h | 58 ++++++++----- drivers/misc/genwqe/card_dev.c | 38 +++------ drivers/misc/genwqe/card_utils.c | 170 ++++++++++++++++++++++++++++++--------- 3 files changed, 180 insertions(+), 86 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/genwqe/card_base.h b/drivers/misc/genwqe/card_base.h index 5e4dbd21f89..0e608a28860 100644 --- a/drivers/misc/genwqe/card_base.h +++ b/drivers/misc/genwqe/card_base.h @@ -336,6 +336,44 @@ enum genwqe_requ_state { GENWQE_REQU_STATE_MAX, }; +/** + * struct genwqe_sgl - Scatter gather list describing user-space memory + * @sgl: scatter gather list needs to be 128 byte aligned + * @sgl_dma_addr: dma address of sgl + * @sgl_size: size of area used for sgl + * @user_addr: user-space address of memory area + * @user_size: size of user-space memory area + * @page: buffer for partial pages if needed + * @page_dma_addr: dma address partial pages + */ +struct genwqe_sgl { + dma_addr_t sgl_dma_addr; + struct sg_entry *sgl; + size_t sgl_size; /* size of sgl */ + + void __user *user_addr; /* user-space base-address */ + size_t user_size; /* size of memory area */ + + unsigned long nr_pages; + unsigned long fpage_offs; + size_t fpage_size; + size_t lpage_size; + + void *fpage; + dma_addr_t fpage_dma_addr; + + void *lpage; + dma_addr_t lpage_dma_addr; +}; + +int genwqe_alloc_sync_sgl(struct genwqe_dev *cd, struct genwqe_sgl *sgl, + void __user *user_addr, size_t user_size); + +int genwqe_setup_sgl(struct genwqe_dev *cd, struct genwqe_sgl *sgl, + dma_addr_t *dma_list); + +int genwqe_free_sync_sgl(struct genwqe_dev *cd, struct genwqe_sgl *sgl); + /** * struct ddcb_requ - Kernel internal representation of the DDCB request * @cmd: User space representation of the DDCB execution request @@ -347,9 +385,7 @@ struct ddcb_requ { struct ddcb_queue *queue; /* associated queue */ struct dma_mapping dma_mappings[DDCB_FIXUPS]; - struct sg_entry *sgl[DDCB_FIXUPS]; - dma_addr_t sgl_dma_addr[DDCB_FIXUPS]; - size_t sgl_size[DDCB_FIXUPS]; + struct genwqe_sgl sgls[DDCB_FIXUPS]; /* kernel/user shared content */ struct genwqe_ddcb_cmd cmd; /* ddcb_no for this request */ @@ -453,22 +489,6 @@ int genwqe_user_vmap(struct genwqe_dev *cd, struct dma_mapping *m, int genwqe_user_vunmap(struct genwqe_dev *cd, struct dma_mapping *m, struct ddcb_requ *req); -struct sg_entry *genwqe_alloc_sgl(struct genwqe_dev *cd, int num_pages, - dma_addr_t *dma_addr, size_t *sgl_size); - -void genwqe_free_sgl(struct genwqe_dev *cd, struct sg_entry *sg_list, - dma_addr_t dma_addr, size_t size); - -int genwqe_setup_sgl(struct genwqe_dev *cd, - unsigned long offs, - unsigned long size, - struct sg_entry *sgl, /* genwqe sgl */ - dma_addr_t dma_addr, size_t sgl_size, - dma_addr_t *dma_list, int page_offs, int num_pages); - -int genwqe_check_sgl(struct genwqe_dev *cd, struct sg_entry *sg_list, - int size); - static inline bool dma_mapping_used(struct dma_mapping *m) { if (!m) diff --git a/drivers/misc/genwqe/card_dev.c b/drivers/misc/genwqe/card_dev.c index 0d05ca77c45..1d2f163a190 100644 --- a/drivers/misc/genwqe/card_dev.c +++ b/drivers/misc/genwqe/card_dev.c @@ -840,15 +840,8 @@ static int ddcb_cmd_cleanup(struct genwqe_file *cfile, struct ddcb_requ *req) __genwqe_del_mapping(cfile, dma_map); genwqe_user_vunmap(cd, dma_map, req); } - if (req->sgl[i] != NULL) { - genwqe_free_sgl(cd, req->sgl[i], - req->sgl_dma_addr[i], - req->sgl_size[i]); - req->sgl[i] = NULL; - req->sgl_dma_addr[i] = 0x0; - req->sgl_size[i] = 0; - } - + if (req->sgls[i].sgl != NULL) + genwqe_free_sync_sgl(cd, &req->sgls[i]); } return 0; } @@ -917,7 +910,7 @@ static int ddcb_cmd_fixups(struct genwqe_file *cfile, struct ddcb_requ *req) case ATS_TYPE_SGL_RDWR: case ATS_TYPE_SGL_RD: { - int page_offs, nr_pages, offs; + int page_offs; u_addr = be64_to_cpu(*((__be64 *) &cmd->asiv[asiv_offs])); @@ -955,27 +948,18 @@ static int ddcb_cmd_fixups(struct genwqe_file *cfile, struct ddcb_requ *req) page_offs = 0; } - offs = offset_in_page(u_addr); - nr_pages = DIV_ROUND_UP(offs + u_size, PAGE_SIZE); - /* create genwqe style scatter gather list */ - req->sgl[i] = genwqe_alloc_sgl(cd, m->nr_pages, - &req->sgl_dma_addr[i], - &req->sgl_size[i]); - if (req->sgl[i] == NULL) { - rc = -ENOMEM; + rc = genwqe_alloc_sync_sgl(cd, &req->sgls[i], + (void __user *)u_addr, + u_size); + if (rc != 0) goto err_out; - } - genwqe_setup_sgl(cd, offs, u_size, - req->sgl[i], - req->sgl_dma_addr[i], - req->sgl_size[i], - m->dma_list, - page_offs, - nr_pages); + + genwqe_setup_sgl(cd, &req->sgls[i], + &m->dma_list[page_offs]); *((__be64 *)&cmd->asiv[asiv_offs]) = - cpu_to_be64(req->sgl_dma_addr[i]); + cpu_to_be64(req->sgls[i].sgl_dma_addr); break; } diff --git a/drivers/misc/genwqe/card_utils.c b/drivers/misc/genwqe/card_utils.c index 6b1a6ef9f1a..d049d271699 100644 --- a/drivers/misc/genwqe/card_utils.c +++ b/drivers/misc/genwqe/card_utils.c @@ -275,67 +275,107 @@ static int genwqe_sgl_size(int num_pages) return roundup(len, PAGE_SIZE); } -struct sg_entry *genwqe_alloc_sgl(struct genwqe_dev *cd, int num_pages, - dma_addr_t *dma_addr, size_t *sgl_size) +/** + * genwqe_alloc_sync_sgl() - Allocate memory for sgl and overlapping pages + * + * Allocates memory for sgl and overlapping pages. Pages which might + * overlap other user-space memory blocks are being cached for DMAs, + * such that we do not run into syncronization issues. Data is copied + * from user-space into the cached pages. + */ +int genwqe_alloc_sync_sgl(struct genwqe_dev *cd, struct genwqe_sgl *sgl, + void __user *user_addr, size_t user_size) { + int rc; struct pci_dev *pci_dev = cd->pci_dev; - struct sg_entry *sgl; - *sgl_size = genwqe_sgl_size(num_pages); - if (get_order(*sgl_size) > MAX_ORDER) { + sgl->fpage_offs = offset_in_page((unsigned long)user_addr); + sgl->fpage_size = min_t(size_t, PAGE_SIZE-sgl->fpage_offs, user_size); + sgl->nr_pages = DIV_ROUND_UP(sgl->fpage_offs + user_size, PAGE_SIZE); + sgl->lpage_size = (user_size - sgl->fpage_size) % PAGE_SIZE; + + dev_dbg(&pci_dev->dev, "[%s] uaddr=%p usize=%8ld nr_pages=%ld " + "fpage_offs=%lx fpage_size=%ld lpage_size=%ld\n", + __func__, user_addr, user_size, sgl->nr_pages, + sgl->fpage_offs, sgl->fpage_size, sgl->lpage_size); + + sgl->user_addr = user_addr; + sgl->user_size = user_size; + sgl->sgl_size = genwqe_sgl_size(sgl->nr_pages); + + if (get_order(sgl->sgl_size) > MAX_ORDER) { dev_err(&pci_dev->dev, "[%s] err: too much memory requested!\n", __func__); - return NULL; + return -ENOMEM; } - sgl = __genwqe_alloc_consistent(cd, *sgl_size, dma_addr); - if (sgl == NULL) { + sgl->sgl = __genwqe_alloc_consistent(cd, sgl->sgl_size, + &sgl->sgl_dma_addr); + if (sgl->sgl == NULL) { dev_err(&pci_dev->dev, "[%s] err: no memory available!\n", __func__); - return NULL; + return -ENOMEM; } - return sgl; + /* Only use buffering on incomplete pages */ + if ((sgl->fpage_size != 0) && (sgl->fpage_size != PAGE_SIZE)) { + sgl->fpage = __genwqe_alloc_consistent(cd, PAGE_SIZE, + &sgl->fpage_dma_addr); + if (sgl->fpage == NULL) + goto err_out; + + /* Sync with user memory */ + if (copy_from_user(sgl->fpage + sgl->fpage_offs, + user_addr, sgl->fpage_size)) { + rc = -EFAULT; + goto err_out; + } + } + if (sgl->lpage_size != 0) { + sgl->lpage = __genwqe_alloc_consistent(cd, PAGE_SIZE, + &sgl->lpage_dma_addr); + if (sgl->lpage == NULL) + goto err_out1; + + /* Sync with user memory */ + if (copy_from_user(sgl->lpage, user_addr + user_size - + sgl->lpage_size, sgl->lpage_size)) { + rc = -EFAULT; + goto err_out1; + } + } + return 0; + + err_out1: + __genwqe_free_consistent(cd, PAGE_SIZE, sgl->fpage, + sgl->fpage_dma_addr); + err_out: + __genwqe_free_consistent(cd, sgl->sgl_size, sgl->sgl, + sgl->sgl_dma_addr); + return -ENOMEM; } -int genwqe_setup_sgl(struct genwqe_dev *cd, - unsigned long offs, - unsigned long size, - struct sg_entry *sgl, - dma_addr_t dma_addr, size_t sgl_size, - dma_addr_t *dma_list, int page_offs, int num_pages) +int genwqe_setup_sgl(struct genwqe_dev *cd, struct genwqe_sgl *sgl, + dma_addr_t *dma_list) { int i = 0, j = 0, p; unsigned long dma_offs, map_offs; - struct pci_dev *pci_dev = cd->pci_dev; dma_addr_t prev_daddr = 0; struct sg_entry *s, *last_s = NULL; - - /* sanity checks */ - if (offs > PAGE_SIZE) { - dev_err(&pci_dev->dev, - "[%s] too large start offs %08lx\n", __func__, offs); - return -EFAULT; - } - if (sgl_size < genwqe_sgl_size(num_pages)) { - dev_err(&pci_dev->dev, - "[%s] sgl_size too small %08lx for %d pages\n", - __func__, sgl_size, num_pages); - return -EFAULT; - } + size_t size = sgl->user_size; dma_offs = 128; /* next block if needed/dma_offset */ - map_offs = offs; /* offset in first page */ + map_offs = sgl->fpage_offs; /* offset in first page */ - s = &sgl[0]; /* first set of 8 entries */ + s = &sgl->sgl[0]; /* first set of 8 entries */ p = 0; /* page */ - while (p < num_pages) { + while (p < sgl->nr_pages) { dma_addr_t daddr; unsigned int size_to_map; /* always write the chaining entry, cleanup is done later */ j = 0; - s[j].target_addr = cpu_to_be64(dma_addr + dma_offs); + s[j].target_addr = cpu_to_be64(sgl->sgl_dma_addr + dma_offs); s[j].len = cpu_to_be32(128); s[j].flags = cpu_to_be32(SG_CHAINED); j++; @@ -343,7 +383,17 @@ int genwqe_setup_sgl(struct genwqe_dev *cd, while (j < 8) { /* DMA mapping for requested page, offs, size */ size_to_map = min(size, PAGE_SIZE - map_offs); - daddr = dma_list[page_offs + p] + map_offs; + + if ((p == 0) && (sgl->fpage != NULL)) { + daddr = sgl->fpage_dma_addr + map_offs; + + } else if ((p == sgl->nr_pages - 1) && + (sgl->lpage != NULL)) { + daddr = sgl->lpage_dma_addr; + } else { + daddr = dma_list[p] + map_offs; + } + size -= size_to_map; map_offs = 0; @@ -358,7 +408,7 @@ int genwqe_setup_sgl(struct genwqe_dev *cd, size_to_map); p++; /* process next page */ - if (p == num_pages) + if (p == sgl->nr_pages) goto fixup; /* nothing to do */ prev_daddr = daddr + size_to_map; @@ -374,7 +424,7 @@ int genwqe_setup_sgl(struct genwqe_dev *cd, j++; p++; /* process next page */ - if (p == num_pages) + if (p == sgl->nr_pages) goto fixup; /* nothing to do */ } dma_offs += 128; @@ -395,10 +445,50 @@ int genwqe_setup_sgl(struct genwqe_dev *cd, return 0; } -void genwqe_free_sgl(struct genwqe_dev *cd, struct sg_entry *sg_list, - dma_addr_t dma_addr, size_t size) +/** + * genwqe_free_sync_sgl() - Free memory for sgl and overlapping pages + * + * After the DMA transfer has been completed we free the memory for + * the sgl and the cached pages. Data is being transfered from cached + * pages into user-space buffers. + */ +int genwqe_free_sync_sgl(struct genwqe_dev *cd, struct genwqe_sgl *sgl) { - __genwqe_free_consistent(cd, size, sg_list, dma_addr); + int rc; + struct pci_dev *pci_dev = cd->pci_dev; + + if (sgl->fpage) { + if (copy_to_user(sgl->user_addr, sgl->fpage + sgl->fpage_offs, + sgl->fpage_size)) { + dev_err(&pci_dev->dev, "[%s] err: copying fpage!\n", + __func__); + rc = -EFAULT; + } + __genwqe_free_consistent(cd, PAGE_SIZE, sgl->fpage, + sgl->fpage_dma_addr); + sgl->fpage = NULL; + sgl->fpage_dma_addr = 0; + } + if (sgl->lpage) { + if (copy_to_user(sgl->user_addr + sgl->user_size - + sgl->lpage_size, sgl->lpage, + sgl->lpage_size)) { + dev_err(&pci_dev->dev, "[%s] err: copying lpage!\n", + __func__); + rc = -EFAULT; + } + __genwqe_free_consistent(cd, PAGE_SIZE, sgl->lpage, + sgl->lpage_dma_addr); + sgl->lpage = NULL; + sgl->lpage_dma_addr = 0; + } + __genwqe_free_consistent(cd, sgl->sgl_size, sgl->sgl, + sgl->sgl_dma_addr); + + sgl->sgl = NULL; + sgl->sgl_dma_addr = 0x0; + sgl->sgl_size = 0; + return rc; } /** -- cgit v1.2.3-70-g09d2 From 73590a25ba6f55eecde4ffbbbc53835d7ccf5402 Mon Sep 17 00:00:00 2001 From: Frank Haverkamp Date: Thu, 20 Mar 2014 15:11:06 +0100 Subject: GenWQE: Increase driver version number Increase genwqe driver version number. Signed-off-by: Frank Haverkamp Signed-off-by: Greg Kroah-Hartman --- drivers/misc/genwqe/genwqe_driver.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/misc/genwqe/genwqe_driver.h b/drivers/misc/genwqe/genwqe_driver.h index 46e916b36c7..cd5263163a6 100644 --- a/drivers/misc/genwqe/genwqe_driver.h +++ b/drivers/misc/genwqe/genwqe_driver.h @@ -36,7 +36,7 @@ #include #include -#define DRV_VERS_STRING "2.0.0" +#define DRV_VERS_STRING "2.0.15" /* * Static minor number assignement, until we decide/implement -- cgit v1.2.3-70-g09d2 From b7a314054eb55e3745a9409beaa5d8be5cd2d273 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 16 Apr 2014 14:25:16 +0300 Subject: isdn: icn: buffer overflow in icn_command() This buffer over was detected using static analysis: drivers/isdn/icn/icn.c:1325 icn_command() error: format string overflow. buf_size: 60 length: 98 The calculation for the length of the string is off because it assumes that the dial[] buffer holds a 50 character string, but actually it is at most 31 characters and NUL. I have removed the dial[] buffer because it isn't needed. The maximum length of the string is actually 79 characters and a NUL. I have made the cbuf[] array large enough to hold it and changed the sprintf() to an snprintf() as a further safety enhancement. Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller --- drivers/isdn/icn/icn.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/isdn/icn/icn.c b/drivers/isdn/icn/icn.c index 53d487f0c79..6a7447c304a 100644 --- a/drivers/isdn/icn/icn.c +++ b/drivers/isdn/icn/icn.c @@ -1155,7 +1155,7 @@ icn_command(isdn_ctrl *c, icn_card *card) ulong a; ulong flags; int i; - char cbuf[60]; + char cbuf[80]; isdn_ctrl cmd; icn_cdef cdef; char __user *arg; @@ -1309,7 +1309,6 @@ icn_command(isdn_ctrl *c, icn_card *card) break; if ((c->arg & 255) < ICN_BCH) { char *p; - char dial[50]; char dcode[4]; a = c->arg; @@ -1321,10 +1320,10 @@ icn_command(isdn_ctrl *c, icn_card *card) } else /* Normal Dial */ strcpy(dcode, "CAL"); - strcpy(dial, p); - sprintf(cbuf, "%02d;D%s_R%s,%02d,%02d,%s\n", (int) (a + 1), - dcode, dial, c->parm.setup.si1, - c->parm.setup.si2, c->parm.setup.eazmsn); + snprintf(cbuf, sizeof(cbuf), + "%02d;D%s_R%s,%02d,%02d,%s\n", (int) (a + 1), + dcode, p, c->parm.setup.si1, + c->parm.setup.si2, c->parm.setup.eazmsn); i = icn_writecmd(cbuf, strlen(cbuf), 0, card); } break; -- cgit v1.2.3-70-g09d2 From 5e6533a6f52f1a8283b2f818f5828be99a417dd6 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Tue, 25 Mar 2014 21:25:18 +0200 Subject: mei: me: do not load the driver if the FW doesn't support MEI interface NM and SPS FW types that may run on ME device on server platforms do not have valid MEI/HECI interface and driver should not be bound to it as this might lead to system hung. In practice not all BIOSes effectively hide such devices from the OS and in some cases it is not possible. We determine FW type by examining Host FW status registers in order to unbind the driver. In this patch we are adding check for ME on Cougar Point, Lynx Point Devices Cc: stable # 3.10+ Signed-off-by: Tomas Winkler Tested-by: Nikola Ciprich Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/hw-me-regs.h | 5 +++++ drivers/misc/mei/pci-me.c | 30 +++++++++++++++++++++++------- 2 files changed, 28 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h index 66f411a6e8e..cabc0438368 100644 --- a/drivers/misc/mei/hw-me-regs.h +++ b/drivers/misc/mei/hw-me-regs.h @@ -115,6 +115,11 @@ #define MEI_DEV_ID_LPT_HR 0x8CBA /* Lynx Point H Refresh */ #define MEI_DEV_ID_WPT_LP 0x9CBA /* Wildcat Point LP */ + +/* Host Firmware Status Registers in PCI Config Space */ +#define PCI_CFG_HFS_1 0x40 +#define PCI_CFG_HFS_2 0x48 + /* * MEI HW Section */ diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c index 1c8fd3a3e13..95889e2e31f 100644 --- a/drivers/misc/mei/pci-me.c +++ b/drivers/misc/mei/pci-me.c @@ -97,15 +97,31 @@ static bool mei_me_quirk_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { u32 reg; - if (ent->device == MEI_DEV_ID_PBG_1) { - pci_read_config_dword(pdev, 0x48, ®); - /* make sure that bit 9 is up and bit 10 is down */ - if ((reg & 0x600) == 0x200) { - dev_info(&pdev->dev, "Device doesn't have valid ME Interface\n"); - return false; - } + /* Cougar Point || Patsburg */ + if (ent->device == MEI_DEV_ID_CPT_1 || + ent->device == MEI_DEV_ID_PBG_1) { + pci_read_config_dword(pdev, PCI_CFG_HFS_2, ®); + /* make sure that bit 9 (NM) is up and bit 10 (DM) is down */ + if ((reg & 0x600) == 0x200) + goto no_mei; } + + /* Lynx Point */ + if (ent->device == MEI_DEV_ID_LPT_H || + ent->device == MEI_DEV_ID_LPT_W || + ent->device == MEI_DEV_ID_LPT_HR) { + /* Read ME FW Status check for SPS Firmware */ + pci_read_config_dword(pdev, PCI_CFG_HFS_1, ®); + /* if bits [19:16] = 15, running SPS Firmware */ + if ((reg & 0xf0000) == 0xf0000) + goto no_mei; + } + return true; + +no_mei: + dev_info(&pdev->dev, "Device doesn't have valid ME Interface\n"); + return false; } /** * mei_probe - Device Initialization Routine -- cgit v1.2.3-70-g09d2 From 34ec43661fe8f1977dd0f05353302ae2ed10aabb Mon Sep 17 00:00:00 2001 From: Alexander Usyskin Date: Tue, 1 Apr 2014 23:50:41 +0300 Subject: mei: ignore client writing state during cb completion Ignore client writing state during cb completion to fix a memory leak. When moving cbs to the completion list we should not look at writing_state as this state can be already overwritten by next write, the fact that a cb is on the write waiting list means that it was already written to the HW and we can safely complete it. Same pays for wait in poll handler, we do not have to check the state wake is done after completion list processing. Cc: stable@vger.kernel.org Signed-off-by: Alexander Usyskin Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/interrupt.c | 3 +-- drivers/misc/mei/main.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/mei/interrupt.c b/drivers/misc/mei/interrupt.c index 29b5af8efb7..4e3cba6da3f 100644 --- a/drivers/misc/mei/interrupt.c +++ b/drivers/misc/mei/interrupt.c @@ -455,8 +455,7 @@ int mei_irq_write_handler(struct mei_device *dev, struct mei_cl_cb *cmpl_list) cl->status = 0; list_del(&cb->list); - if (MEI_WRITING == cl->writing_state && - cb->fop_type == MEI_FOP_WRITE && + if (cb->fop_type == MEI_FOP_WRITE && cl != &dev->iamthif_cl) { cl_dbg(dev, cl, "MEI WRITE COMPLETE\n"); cl->writing_state = MEI_WRITE_COMPLETE; diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index b35594dbf52..147413145c9 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -644,8 +644,7 @@ static unsigned int mei_poll(struct file *file, poll_table *wait) goto out; } - if (MEI_WRITE_COMPLETE == cl->writing_state) - mask |= (POLLIN | POLLRDNORM); + mask |= (POLLIN | POLLRDNORM); out: mutex_unlock(&dev->device_lock); -- cgit v1.2.3-70-g09d2 From 7c7352827343b377446bb59b844d387df665e401 Mon Sep 17 00:00:00 2001 From: Christoph Jaeger Date: Fri, 11 Apr 2014 18:40:05 +0200 Subject: drivers: mcb: fix memory leak in chameleon_parse_cells() error path chameleon_parse_cells() bails out if chameleon descriptor type is invalid but does not free the storage 'header' points to. Signed-off-by: Christoph Jaeger Signed-off-by: Johannes Thumshirn Signed-off-by: Greg Kroah-Hartman --- drivers/mcb/mcb-parse.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/mcb/mcb-parse.c b/drivers/mcb/mcb-parse.c index d1278b5f302..00492695526 100644 --- a/drivers/mcb/mcb-parse.c +++ b/drivers/mcb/mcb-parse.c @@ -141,6 +141,7 @@ int chameleon_parse_cells(struct mcb_bus *bus, phys_addr_t mapbase, default: pr_err("Invalid chameleon descriptor type 0x%x\n", dtype); + kfree(header); return -EINVAL; } num_cells++; -- cgit v1.2.3-70-g09d2 From a82cb8b91a37b6015f171a90dc4670e4c8e12e12 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 14 Apr 2014 18:55:49 +0200 Subject: misc: Grammar s/addition/additional/ Signed-off-by: Geert Uytterhoeven Cc: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman --- drivers/misc/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 1cb74085e41..8baff0effc7 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -300,8 +300,8 @@ config SGI_GRU_DEBUG depends on SGI_GRU default n ---help--- - This option enables addition debugging code for the SGI GRU driver. If - you are unsure, say N. + This option enables additional debugging code for the SGI GRU driver. + If you are unsure, say N. config APDS9802ALS tristate "Medfield Avago APDS9802 ALS Sensor module" -- cgit v1.2.3-70-g09d2 From f764cd68d9036498f08fe8834deb6a367b5c2542 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Wed, 16 Apr 2014 14:49:33 -0500 Subject: staging: r8712u: Fix case where ethtype was never obtained and always be checked against 0 Zero-initializing ether_type masked that the ether type would never be obtained for 8021x packets and the comparison against eapol_type would always fail. Reported-by: Jes Sorensen Signed-off-by: Larry Finger Cc: Stable Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8712/rtl871x_recv.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8712/rtl871x_recv.c b/drivers/staging/rtl8712/rtl871x_recv.c index 23ec684b60e..274c359279e 100644 --- a/drivers/staging/rtl8712/rtl871x_recv.c +++ b/drivers/staging/rtl8712/rtl871x_recv.c @@ -254,7 +254,7 @@ union recv_frame *r8712_portctrl(struct _adapter *adapter, struct sta_info *psta; struct sta_priv *pstapriv; union recv_frame *prtnframe; - u16 ether_type = 0; + u16 ether_type; pstapriv = &adapter->stapriv; ptr = get_recvframe_data(precv_frame); @@ -263,15 +263,14 @@ union recv_frame *r8712_portctrl(struct _adapter *adapter, psta = r8712_get_stainfo(pstapriv, psta_addr); auth_alg = adapter->securitypriv.AuthAlgrthm; if (auth_alg == 2) { + /* get ether_type */ + ptr = ptr + pfhdr->attrib.hdrlen + LLC_HEADER_SIZE; + memcpy(ðer_type, ptr, 2); + ether_type = ntohs((unsigned short)ether_type); + if ((psta != NULL) && (psta->ieee8021x_blocked)) { /* blocked * only accept EAPOL frame */ - prtnframe = precv_frame; - /*get ether_type */ - ptr = ptr + pfhdr->attrib.hdrlen + - pfhdr->attrib.iv_len + LLC_HEADER_SIZE; - memcpy(ðer_type, ptr, 2); - ether_type = ntohs((unsigned short)ether_type); if (ether_type == 0x888e) prtnframe = precv_frame; else { -- cgit v1.2.3-70-g09d2 From 33c84bc14c25074ac14644cf7db75a57e9abaf1a Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Wed, 16 Apr 2014 14:49:34 -0500 Subject: staging: r8188eu: Fix case where ethtype was never obtained and always be checked against 0 Zero-initializing ether_type masked that the ether type would never be obtained for 8021x packets and the comparison against eapol_type would always fail. Reported-by: Jes Sorensen Signed-off-by: Larry Finger Cc: Stable Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8188eu/core/rtw_recv.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/rtl8188eu/core/rtw_recv.c b/drivers/staging/rtl8188eu/core/rtw_recv.c index 01fcabcc8e5..e305d43ebd0 100644 --- a/drivers/staging/rtl8188eu/core/rtw_recv.c +++ b/drivers/staging/rtl8188eu/core/rtw_recv.c @@ -551,10 +551,9 @@ static struct recv_frame *portctrl(struct adapter *adapter, struct sta_info *psta; struct sta_priv *pstapriv; struct recv_frame *prtnframe; - u16 ether_type = 0; + u16 ether_type; u16 eapol_type = 0x888e;/* for Funia BD's WPA issue */ struct rx_pkt_attrib *pattrib; - __be16 be_tmp; pstapriv = &adapter->stapriv; @@ -572,18 +571,16 @@ static struct recv_frame *portctrl(struct adapter *adapter, RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("########portctrl:adapter->securitypriv.dot11AuthAlgrthm=%d\n", adapter->securitypriv.dot11AuthAlgrthm)); if (auth_alg == 2) { + /* get ether_type */ + ptr = ptr + pfhdr->attrib.hdrlen + LLC_HEADER_SIZE; + memcpy(ðer_type, ptr, 2); + ether_type = ntohs((unsigned short)ether_type); + if ((psta != NULL) && (psta->ieee8021x_blocked)) { /* blocked */ /* only accept EAPOL frame */ RT_TRACE(_module_rtl871x_recv_c_, _drv_info_, ("########portctrl:psta->ieee8021x_blocked==1\n")); - prtnframe = precv_frame; - - /* get ether_type */ - ptr = ptr+pfhdr->attrib.hdrlen+pfhdr->attrib.iv_len+LLC_HEADER_SIZE; - memcpy(&be_tmp, ptr, 2); - ether_type = ntohs(be_tmp); - if (ether_type == eapol_type) { prtnframe = precv_frame; } else { -- cgit v1.2.3-70-g09d2 From efe26e16b1d93ac0085e69178cc18811629e8fc5 Mon Sep 17 00:00:00 2001 From: Michele Baldessari Date: Mon, 31 Mar 2014 10:51:00 +0200 Subject: USB: serial: ftdi_sio: add id for Brainboxes serial cards Custom VID/PIDs for Brainboxes cards as reported in https://bugzilla.redhat.com/show_bug.cgi?id=1071914 Signed-off-by: Michele Baldessari Cc: stable Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/ftdi_sio.c | 33 +++++++++++++++++++++++++++++++++ drivers/usb/serial/ftdi_sio_ids.h | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 44ab1298680..7c6e1dedeb0 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -909,6 +909,39 @@ static const struct usb_device_id id_table_combined[] = { { USB_DEVICE(FTDI_VID, FTDI_Z3X_PID) }, /* Cressi Devices */ { USB_DEVICE(FTDI_VID, FTDI_CRESSI_PID) }, + /* Brainboxes Devices */ + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_VX_001_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_VX_012_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_VX_023_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_VX_034_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_101_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_160_1_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_160_2_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_160_3_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_160_4_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_160_5_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_160_6_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_160_7_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_160_8_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_257_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_279_1_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_279_2_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_279_3_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_279_4_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_313_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_324_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_346_1_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_346_2_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_357_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_606_1_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_606_2_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_606_3_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_701_1_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_701_2_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_842_1_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_842_2_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_842_3_PID) }, + { USB_DEVICE(BRAINBOXES_VID, BRAINBOXES_US_842_4_PID) }, { } /* Terminating entry */ }; diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index e599fbfcde5..993c93df687 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -1326,3 +1326,40 @@ * Manufacturer: Cressi */ #define FTDI_CRESSI_PID 0x87d0 + +/* + * Brainboxes devices + */ +#define BRAINBOXES_VID 0x05d1 +#define BRAINBOXES_VX_001_PID 0x1001 /* VX-001 ExpressCard 1 Port RS232 */ +#define BRAINBOXES_VX_012_PID 0x1002 /* VX-012 ExpressCard 2 Port RS232 */ +#define BRAINBOXES_VX_023_PID 0x1003 /* VX-023 ExpressCard 1 Port RS422/485 */ +#define BRAINBOXES_VX_034_PID 0x1004 /* VX-034 ExpressCard 2 Port RS422/485 */ +#define BRAINBOXES_US_101_PID 0x1011 /* US-101 1xRS232 */ +#define BRAINBOXES_US_324_PID 0x1013 /* US-324 1xRS422/485 1Mbaud */ +#define BRAINBOXES_US_606_1_PID 0x2001 /* US-606 6 Port RS232 Serial Port 1 and 2 */ +#define BRAINBOXES_US_606_2_PID 0x2002 /* US-606 6 Port RS232 Serial Port 3 and 4 */ +#define BRAINBOXES_US_606_3_PID 0x2003 /* US-606 6 Port RS232 Serial Port 4 and 6 */ +#define BRAINBOXES_US_701_1_PID 0x2011 /* US-701 4xRS232 1Mbaud Port 1 and 2 */ +#define BRAINBOXES_US_701_2_PID 0x2012 /* US-701 4xRS422 1Mbaud Port 3 and 4 */ +#define BRAINBOXES_US_279_1_PID 0x2021 /* US-279 8xRS422 1Mbaud Port 1 and 2 */ +#define BRAINBOXES_US_279_2_PID 0x2022 /* US-279 8xRS422 1Mbaud Port 3 and 4 */ +#define BRAINBOXES_US_279_3_PID 0x2023 /* US-279 8xRS422 1Mbaud Port 5 and 6 */ +#define BRAINBOXES_US_279_4_PID 0x2024 /* US-279 8xRS422 1Mbaud Port 7 and 8 */ +#define BRAINBOXES_US_346_1_PID 0x3011 /* US-346 4xRS422/485 1Mbaud Port 1 and 2 */ +#define BRAINBOXES_US_346_2_PID 0x3012 /* US-346 4xRS422/485 1Mbaud Port 3 and 4 */ +#define BRAINBOXES_US_257_PID 0x5001 /* US-257 2xRS232 1Mbaud */ +#define BRAINBOXES_US_313_PID 0x6001 /* US-313 2xRS422/485 1Mbaud */ +#define BRAINBOXES_US_357_PID 0x7001 /* US_357 1xRS232/422/485 */ +#define BRAINBOXES_US_842_1_PID 0x8001 /* US-842 8xRS422/485 1Mbaud Port 1 and 2 */ +#define BRAINBOXES_US_842_2_PID 0x8002 /* US-842 8xRS422/485 1Mbaud Port 3 and 4 */ +#define BRAINBOXES_US_842_3_PID 0x8003 /* US-842 8xRS422/485 1Mbaud Port 5 and 6 */ +#define BRAINBOXES_US_842_4_PID 0x8004 /* US-842 8xRS422/485 1Mbaud Port 7 and 8 */ +#define BRAINBOXES_US_160_1_PID 0x9001 /* US-160 16xRS232 1Mbaud Port 1 and 2 */ +#define BRAINBOXES_US_160_2_PID 0x9002 /* US-160 16xRS232 1Mbaud Port 3 and 4 */ +#define BRAINBOXES_US_160_3_PID 0x9003 /* US-160 16xRS232 1Mbaud Port 5 and 6 */ +#define BRAINBOXES_US_160_4_PID 0x9004 /* US-160 16xRS232 1Mbaud Port 7 and 8 */ +#define BRAINBOXES_US_160_5_PID 0x9005 /* US-160 16xRS232 1Mbaud Port 9 and 10 */ +#define BRAINBOXES_US_160_6_PID 0x9006 /* US-160 16xRS232 1Mbaud Port 11 and 12 */ +#define BRAINBOXES_US_160_7_PID 0x9007 /* US-160 16xRS232 1Mbaud Port 13 and 14 */ +#define BRAINBOXES_US_160_8_PID 0x9008 /* US-160 16xRS232 1Mbaud Port 15 and 16 */ -- cgit v1.2.3-70-g09d2 From 2e01280d2801c72878cf3a7119eac30077b463d5 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Fri, 28 Mar 2014 18:05:10 +0100 Subject: Revert "USB: serial: add usbid for dell wwan card to sierra.c" This reverts commit 1ebca9dad5abe8b2ed4dbd186cd657fb47c1f321. This device was erroneously added to the sierra driver even though it's not a Sierra device and was already handled by the option driver. Cc: Richard Farina Cc: stable@vger.kernel.org Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/sierra.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index a9eb6221a81..6b192e602ce 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c @@ -291,7 +291,6 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x0f3d, 0x68A3), /* Airprime/Sierra Wireless Direct IP modems */ .driver_info = (kernel_ulong_t)&direct_ip_interface_blacklist }, - { USB_DEVICE(0x413C, 0x08133) }, /* Dell Computer Corp. Wireless 5720 VZW Mobile Broadband (EVDO Rev-A) Minicard GPS Port */ { } }; -- cgit v1.2.3-70-g09d2 From d6de486bc22255779bd54b0fceb4c240962bf146 Mon Sep 17 00:00:00 2001 From: Daniele Palmas Date: Wed, 2 Apr 2014 11:19:48 +0200 Subject: usb: option driver, add support for Telit UE910v2 option driver, added VID/PID for Telit UE910v2 modem Signed-off-by: Daniele Palmas Cc: stable Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/option.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 68fc9fe6593..367c7f08b27 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -243,6 +243,7 @@ static void option_instat_callback(struct urb *urb); #define TELIT_PRODUCT_CC864_DUAL 0x1005 #define TELIT_PRODUCT_CC864_SINGLE 0x1006 #define TELIT_PRODUCT_DE910_DUAL 0x1010 +#define TELIT_PRODUCT_UE910_V2 0x1012 #define TELIT_PRODUCT_LE920 0x1200 /* ZTE PRODUCTS */ @@ -1041,6 +1042,7 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_CC864_DUAL) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_CC864_SINGLE) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_DE910_DUAL) }, + { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UE910_V2) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE920), .driver_info = (kernel_ulong_t)&telit_le920_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF622, 0xff, 0xff, 0xff) }, /* ZTE WCDMA products */ -- cgit v1.2.3-70-g09d2 From 72b3007951010ce1bbf950e23b19d9839fa905a5 Mon Sep 17 00:00:00 2001 From: Tristan Bruns Date: Sun, 13 Apr 2014 23:57:16 +0200 Subject: USB: cp210x: Add 8281 (Nanotec Plug & Drive) Signed-off-by: Tristan Bruns Cc: stable Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/cp210x.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index 95fa1217afd..762e4a5f5ae 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -104,6 +104,7 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x10C4, 0x8218) }, /* Lipowsky Industrie Elektronik GmbH, HARP-1 */ { USB_DEVICE(0x10C4, 0x822B) }, /* Modem EDGE(GSM) Comander 2 */ { USB_DEVICE(0x10C4, 0x826B) }, /* Cygnal Integrated Products, Inc., Fasttrax GPS demonstration module */ + { USB_DEVICE(0x10C4, 0x8281) }, /* Nanotec Plug & Drive */ { USB_DEVICE(0x10C4, 0x8293) }, /* Telegesis ETRX2USB */ { USB_DEVICE(0x10C4, 0x82F9) }, /* Procyon AVS */ { USB_DEVICE(0x10C4, 0x8341) }, /* Siemens MC35PU GPRS Modem */ -- cgit v1.2.3-70-g09d2 From b16c02fbfb963fa2941b7517ebf1f8a21946775e Mon Sep 17 00:00:00 2001 From: Aaron Sanders Date: Mon, 31 Mar 2014 15:54:21 +0200 Subject: USB: pl2303: add ids for Hewlett-Packard HP POS pole displays Add device ids to pl2303 for the Hewlett-Packard HP POS pole displays: LD960: 03f0:0B39 LCM220: 03f0:3139 LCM960: 03f0:3239 [ Johan: fix indentation and sort PIDs numerically ] Signed-off-by: Aaron Sanders Cc: stable@vger.kernel.org Signed-off-by: Johan Hovold Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/pl2303.c | 3 +++ drivers/usb/serial/pl2303.h | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 2e22fc22c38..b3d5a35c0d4 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -83,6 +83,9 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(YCCABLE_VENDOR_ID, YCCABLE_PRODUCT_ID) }, { USB_DEVICE(SUPERIAL_VENDOR_ID, SUPERIAL_PRODUCT_ID) }, { USB_DEVICE(HP_VENDOR_ID, HP_LD220_PRODUCT_ID) }, + { USB_DEVICE(HP_VENDOR_ID, HP_LD960_PRODUCT_ID) }, + { USB_DEVICE(HP_VENDOR_ID, HP_LCM220_PRODUCT_ID) }, + { USB_DEVICE(HP_VENDOR_ID, HP_LCM960_PRODUCT_ID) }, { USB_DEVICE(CRESSI_VENDOR_ID, CRESSI_EDY_PRODUCT_ID) }, { USB_DEVICE(ZEAGLE_VENDOR_ID, ZEAGLE_N2ITION3_PRODUCT_ID) }, { USB_DEVICE(SONY_VENDOR_ID, SONY_QN3USB_PRODUCT_ID) }, diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h index c38b8c00c06..42bc082896a 100644 --- a/drivers/usb/serial/pl2303.h +++ b/drivers/usb/serial/pl2303.h @@ -121,8 +121,11 @@ #define SUPERIAL_VENDOR_ID 0x5372 #define SUPERIAL_PRODUCT_ID 0x2303 -/* Hewlett-Packard LD220-HP POS Pole Display */ +/* Hewlett-Packard POS Pole Displays */ #define HP_VENDOR_ID 0x03f0 +#define HP_LD960_PRODUCT_ID 0x0b39 +#define HP_LCM220_PRODUCT_ID 0x3139 +#define HP_LCM960_PRODUCT_ID 0x3239 #define HP_LD220_PRODUCT_ID 0x3524 /* Cressi Edy (diving computer) PC interface */ -- cgit v1.2.3-70-g09d2 From bd73bd8831696f189a479a0712ae95208e513d7e Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 3 Apr 2014 13:06:46 +0200 Subject: USB: usb_wwan: fix handling of missing bulk endpoints MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix regression introduced by commit 8e493ca1767d ("USB: usb_wwan: fix bulk-urb allocation") by making sure to require both bulk-in and out endpoints during port probe. The original option driver (which usb_wwan is based on) was written under the assumption that either endpoint could be missing, but evidently this cannot have been tested properly. Specifically, it would handle opening a device without bulk-in (but would blow up during resume which was implemented later), but not a missing bulk-out in write() (although it is handled in some places such as write_room()). Fortunately (?), the driver also got the test for missing endpoints wrong so the urbs were in fact always allocated, although they would be initialised using the wrong endpoint address (0) and any submission of such an urb would fail. The commit mentioned above fixed the test for missing endpoints but thereby exposed the other bugs which would now generate null-pointer exceptions rather than failed urb submissions. The regression was introduced in v3.7, but the offending commit was also marked for stable. Reported-by: Rafał Miłecki Cc: stable Signed-off-by: Johan Hovold Tested-by: Rafał Miłecki Signed-off-by: Greg Kroah-Hartman --- drivers/usb/serial/usb_wwan.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c index 640fe017323..b078440e822 100644 --- a/drivers/usb/serial/usb_wwan.c +++ b/drivers/usb/serial/usb_wwan.c @@ -466,6 +466,9 @@ int usb_wwan_port_probe(struct usb_serial_port *port) int err; int i; + if (!port->bulk_in_size || !port->bulk_out_size) + return -ENODEV; + portdata = kzalloc(sizeof(*portdata), GFP_KERNEL); if (!portdata) return -ENOMEM; @@ -473,9 +476,6 @@ int usb_wwan_port_probe(struct usb_serial_port *port) init_usb_anchor(&portdata->delayed); for (i = 0; i < N_IN_URB; i++) { - if (!port->bulk_in_size) - break; - buffer = (u8 *)__get_free_page(GFP_KERNEL); if (!buffer) goto bail_out_error; @@ -489,9 +489,6 @@ int usb_wwan_port_probe(struct usb_serial_port *port) } for (i = 0; i < N_OUT_URB; i++) { - if (!port->bulk_out_size) - break; - buffer = kmalloc(OUT_BUFLEN, GFP_KERNEL); if (!buffer) goto bail_out_error2; -- cgit v1.2.3-70-g09d2 From f9076e28013e448ba2a905ae905ac9b53f8a2e16 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Wed, 9 Apr 2014 14:48:58 +0800 Subject: usb: usb-common: fix typo for usb_state_string %s/addresssed/addressed Signed-off-by: Peter Chen Signed-off-by: Greg Kroah-Hartman --- drivers/usb/usb-common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/usb-common.c b/drivers/usb/usb-common.c index d771870a819..6dfd30a863c 100644 --- a/drivers/usb/usb-common.c +++ b/drivers/usb/usb-common.c @@ -69,7 +69,7 @@ const char *usb_state_string(enum usb_device_state state) [USB_STATE_RECONNECTING] = "reconnecting", [USB_STATE_UNAUTHENTICATED] = "unauthenticated", [USB_STATE_DEFAULT] = "default", - [USB_STATE_ADDRESS] = "addresssed", + [USB_STATE_ADDRESS] = "addressed", [USB_STATE_CONFIGURED] = "configured", [USB_STATE_SUSPENDED] = "suspended", }; -- cgit v1.2.3-70-g09d2 From 070c0b17f6a1ba39dff9be112218127e7e8fd456 Mon Sep 17 00:00:00 2001 From: Alexey Khoroshilov Date: Sat, 12 Apr 2014 02:10:45 +0400 Subject: USB: cdc-acm: fix double usb_autopm_put_interface() in acm_port_activate() If acm_submit_read_urbs() fails in acm_port_activate(), error handling code calls usb_autopm_put_interface() while it is already called before acm_submit_read_urbs(). The patch reorganizes error handling code to avoid double decrement of USB interface's PM-usage counter. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov Acked-by: Oliver Neukum Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-acm.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 900f7ff805e..d5d2c922186 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -518,13 +518,16 @@ static int acm_port_activate(struct tty_port *port, struct tty_struct *tty) if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL)) { dev_err(&acm->control->dev, "%s - usb_submit_urb(ctrl irq) failed\n", __func__); + usb_autopm_put_interface(acm->control); goto error_submit_urb; } acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS; if (acm_set_control(acm, acm->ctrlout) < 0 && - (acm->ctrl_caps & USB_CDC_CAP_LINE)) + (acm->ctrl_caps & USB_CDC_CAP_LINE)) { + usb_autopm_put_interface(acm->control); goto error_set_control; + } usb_autopm_put_interface(acm->control); @@ -549,7 +552,6 @@ error_submit_read_urbs: error_set_control: usb_kill_urb(acm->ctrlurb); error_submit_urb: - usb_autopm_put_interface(acm->control); error_get_interface: disconnected: mutex_unlock(&acm->mutex); -- cgit v1.2.3-70-g09d2 From a2ff864b53eac9a0e9b05bfe9d1781ccd6c2af71 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 14 Apr 2014 13:48:47 -0400 Subject: USB: fix crash during hotplug of PCI USB controller card The code in hcd-pci.c that matches up EHCI controllers with their companion UHCI or OHCI controllers assumes that the private drvdata fields don't get set too early. However, it turns out that this field gets set by usb_create_hcd(), before hcd-pci expects it, and this can result in a crash when two controllers are probed in parallel (as can happen when a new controller card is hotplugged). The companions_rwsem lock was supposed to prevent this sort of thing, but usb_create_hcd() is called outside the scope of the rwsem. A simple solution is to check that the root-hub pointer has been initialized as well as the drvdata field. This doesn't happen until usb_add_hcd() is called; that call and the check are both protected by the rwsem. This patch should be applied to stable kernels from 3.10 onward. Signed-off-by: Alan Stern Reported-by: Stefani Seibold Tested-by: Stefani Seibold CC: Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd-pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index d59d99347d5..1f02e65fe30 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -75,7 +75,7 @@ static void for_each_companion(struct pci_dev *pdev, struct usb_hcd *hcd, PCI_SLOT(companion->devfn) != slot) continue; companion_hcd = pci_get_drvdata(companion); - if (!companion_hcd) + if (!companion_hcd || !companion_hcd->self.root_hub) continue; fn(pdev, hcd, companion, companion_hcd); } -- cgit v1.2.3-70-g09d2 From d72175103f25783b0504f864a4f381621a789ca2 Mon Sep 17 00:00:00 2001 From: Vivek Gautam Date: Thu, 10 Apr 2014 15:58:01 +0530 Subject: usb: ehci-exynos: Return immediately from suspend if ehci_suspend fails Patch 'b8efdaf USB: EHCI: add check for wakeup/suspend race' adds a check for possible race between suspend and wakeup interrupt, and thereby it returns -EBUSY as error code if there's a wakeup interrupt. So the platform host controller should not proceed further with its suspend callback, rather should return immediately to avoid powering down the essential things, like phy. Signed-off-by: Vivek Gautam Acked-by: Jingoo Han Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-exynos.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/host/ehci-exynos.c b/drivers/usb/host/ehci-exynos.c index d1d8c47777c..7f425acd9be 100644 --- a/drivers/usb/host/ehci-exynos.c +++ b/drivers/usb/host/ehci-exynos.c @@ -212,6 +212,8 @@ static int exynos_ehci_suspend(struct device *dev) int rc; rc = ehci_suspend(hcd, do_wakeup); + if (rc) + return rc; if (exynos_ehci->otg) exynos_ehci->otg->set_host(exynos_ehci->otg, &hcd->self); -- cgit v1.2.3-70-g09d2 From e155b5b8d2d42455d3a94c2460c287e97184ec61 Mon Sep 17 00:00:00 2001 From: Vivek Gautam Date: Thu, 10 Apr 2014 15:58:02 +0530 Subject: usb: ehci-platform: Return immediately from suspend if ehci_suspend fails Patch 'b8efdaf USB: EHCI: add check for wakeup/suspend race' adds a check for possible race between suspend and wakeup interrupt, and thereby it returns -EBUSY as error code if there's a wakeup interrupt. So the platform host controller should not proceed further with its suspend callback, rather should return immediately to avoid powering down the essential things, like phy. Signed-off-by: Vivek Gautam Acked-by: Alan Stern Cc: Hauke Mehrtens Cc: Hans de Goede Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-platform.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c index b3a0e11073a..c7dd93aad20 100644 --- a/drivers/usb/host/ehci-platform.c +++ b/drivers/usb/host/ehci-platform.c @@ -303,6 +303,8 @@ static int ehci_platform_suspend(struct device *dev) int ret; ret = ehci_suspend(hcd, do_wakeup); + if (ret) + return ret; if (pdata->power_suspend) pdata->power_suspend(pdev); -- cgit v1.2.3-70-g09d2 From 4f2fe2d27472f4a5dbd875888af4fc5175f3fdc5 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Mon, 14 Apr 2014 15:21:23 -0600 Subject: USB: EHCI: tegra: set txfill_tuning To avoid memory fetch underflows with larger USB transfers, Tegra SoCs need txfill_tuning's txfifothresh register field set to a non-default value. Add a custom reset override in order to set this up. These values are recommended practice for all Tegra chips. However, I've only noticed practical problems when not setting them this way on systems using Tegra124. Hence, CC: stable only for recent kernels which actually support Tegra124. Cc: # 3.14+ Signed-off-by: Stephen Warren Acked-by: Alan Stern Tested-by: Alexandre Courbot Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-tegra.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index 27ac6ad53c3..7ef00ecb0da 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -509,8 +509,31 @@ static struct platform_driver tegra_ehci_driver = { } }; +static int tegra_ehci_reset(struct usb_hcd *hcd) +{ + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + int retval; + int txfifothresh; + + retval = ehci_setup(hcd); + if (retval) + return retval; + + /* + * We should really pull this value out of tegra_ehci_soc_config, but + * to avoid needing access to it, make use of the fact that Tegra20 is + * the only one so far that needs a value of 10, and Tegra20 is the + * only one which doesn't set has_hostpc. + */ + txfifothresh = ehci->has_hostpc ? 0x10 : 10; + ehci_writel(ehci, txfifothresh << 16, &ehci->regs->txfill_tuning); + + return 0; +} + static const struct ehci_driver_overrides tegra_overrides __initconst = { .extra_priv_size = sizeof(struct tegra_ehci_hcd), + .reset = tegra_ehci_reset, }; static int __init ehci_tegra_init(void) -- cgit v1.2.3-70-g09d2 From 4d6b5161dba1aa1964e505d2a09bfe4e3a1a7378 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 14 Apr 2014 12:08:13 +0200 Subject: USB: ohci-jz4740: Fix uninitialized variable warning The ret variable is not initialized in all code paths of the ohci_jz4740_hub_control function. Fix it. Signed-off-by: Laurent Pinchart Acked-by: Lars-Peter Clausen Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-jz4740.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/host/ohci-jz4740.c b/drivers/usb/host/ohci-jz4740.c index af8dc1b92d7..b34315ca6cf 100644 --- a/drivers/usb/host/ohci-jz4740.c +++ b/drivers/usb/host/ohci-jz4740.c @@ -82,7 +82,7 @@ static int ohci_jz4740_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength) { struct jz4740_ohci_hcd *jz4740_ohci = hcd_to_jz4740_hcd(hcd); - int ret; + int ret = 0; switch (typeReq) { case SetHubFeature: -- cgit v1.2.3-70-g09d2 From 166cf4aa354c0066cb1903336382772e9e1b7941 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 14 Apr 2014 12:08:14 +0200 Subject: USB: ohci-jz4740: FEAT_POWER is a port feature, not a hub feature Power control of hub ports target the CLEAR_FEATURE and SET_FEATURE requests to ports, not to the hub. Fix the hub control function to detect the request correctly. Signed-off-by: Laurent Pinchart Acked-by: Lars-Peter Clausen Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ohci-jz4740.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/ohci-jz4740.c b/drivers/usb/host/ohci-jz4740.c index b34315ca6cf..c2c221a332e 100644 --- a/drivers/usb/host/ohci-jz4740.c +++ b/drivers/usb/host/ohci-jz4740.c @@ -85,11 +85,11 @@ static int ohci_jz4740_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, int ret = 0; switch (typeReq) { - case SetHubFeature: + case SetPortFeature: if (wValue == USB_PORT_FEAT_POWER) ret = ohci_jz4740_set_vbus_power(jz4740_ohci, true); break; - case ClearHubFeature: + case ClearPortFeature: if (wValue == USB_PORT_FEAT_POWER) ret = ohci_jz4740_set_vbus_power(jz4740_ohci, false); break; -- cgit v1.2.3-70-g09d2 From 895d240d1db0b2736d779200788e4c4aea28a0c6 Mon Sep 17 00:00:00 2001 From: Michael Ulbricht Date: Tue, 25 Mar 2014 10:34:18 +0100 Subject: USB: cdc-acm: Remove Motorola/Telit H24 serial interfaces from ACM driver By specifying NO_UNION_NORMAL the ACM driver does only use the first two USB interfaces (modem data & control). The AT Port, Diagnostic and NMEA interfaces are left to the USB serial driver. Signed-off-by: Michael Ulbricht Signed-off-by: Alexander Stein Signed-off-by: Oliver Neukum Cc: stable Signed-off-by: Greg Kroah-Hartman --- drivers/usb/class/cdc-acm.c | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index d5d2c922186..904efb6035b 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -1654,13 +1654,27 @@ static const struct usb_device_id acm_ids[] = { }, /* Motorola H24 HSPA module: */ { USB_DEVICE(0x22b8, 0x2d91) }, /* modem */ - { USB_DEVICE(0x22b8, 0x2d92) }, /* modem + diagnostics */ - { USB_DEVICE(0x22b8, 0x2d93) }, /* modem + AT port */ - { USB_DEVICE(0x22b8, 0x2d95) }, /* modem + AT port + diagnostics */ - { USB_DEVICE(0x22b8, 0x2d96) }, /* modem + NMEA */ - { USB_DEVICE(0x22b8, 0x2d97) }, /* modem + diagnostics + NMEA */ - { USB_DEVICE(0x22b8, 0x2d99) }, /* modem + AT port + NMEA */ - { USB_DEVICE(0x22b8, 0x2d9a) }, /* modem + AT port + diagnostics + NMEA */ + { USB_DEVICE(0x22b8, 0x2d92), /* modem + diagnostics */ + .driver_info = NO_UNION_NORMAL, /* handle only modem interface */ + }, + { USB_DEVICE(0x22b8, 0x2d93), /* modem + AT port */ + .driver_info = NO_UNION_NORMAL, /* handle only modem interface */ + }, + { USB_DEVICE(0x22b8, 0x2d95), /* modem + AT port + diagnostics */ + .driver_info = NO_UNION_NORMAL, /* handle only modem interface */ + }, + { USB_DEVICE(0x22b8, 0x2d96), /* modem + NMEA */ + .driver_info = NO_UNION_NORMAL, /* handle only modem interface */ + }, + { USB_DEVICE(0x22b8, 0x2d97), /* modem + diagnostics + NMEA */ + .driver_info = NO_UNION_NORMAL, /* handle only modem interface */ + }, + { USB_DEVICE(0x22b8, 0x2d99), /* modem + AT port + NMEA */ + .driver_info = NO_UNION_NORMAL, /* handle only modem interface */ + }, + { USB_DEVICE(0x22b8, 0x2d9a), /* modem + AT port + diagnostics + NMEA */ + .driver_info = NO_UNION_NORMAL, /* handle only modem interface */ + }, { USB_DEVICE(0x0572, 0x1329), /* Hummingbird huc56s (Conexant) */ .driver_info = NO_UNION_NORMAL, /* union descriptor misplaced on -- cgit v1.2.3-70-g09d2 From f7a87195603ae9db133ddd393169dd6c1d45b4a3 Mon Sep 17 00:00:00 2001 From: Daeseok Youn Date: Wed, 16 Apr 2014 18:48:02 +0900 Subject: uwb: adds missing error handling There is checking NULL before dereferncing but it need to add "return". Signed-off-by: Daeseok Youn Signed-off-by: Greg Kroah-Hartman --- drivers/uwb/drp.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/uwb/drp.c b/drivers/uwb/drp.c index 16ada8341c4..1a2fd979536 100644 --- a/drivers/uwb/drp.c +++ b/drivers/uwb/drp.c @@ -599,8 +599,11 @@ static void uwb_drp_handle_alien_drp(struct uwb_rc *rc, struct uwb_ie_drp *drp_i /* alloc and initialize new uwb_cnflt_alien */ cnflt = kzalloc(sizeof(struct uwb_cnflt_alien), GFP_KERNEL); - if (!cnflt) + if (!cnflt) { dev_err(dev, "failed to alloc uwb_cnflt_alien struct\n"); + return; + } + INIT_LIST_HEAD(&cnflt->rc_node); init_timer(&cnflt->timer); cnflt->timer.function = uwb_cnflt_timer; -- cgit v1.2.3-70-g09d2 From e7eda9329372f5e436e5a9291eb115eab0feae02 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Fri, 28 Mar 2014 11:10:30 +0100 Subject: uas: fix GFP_NOIO under spinlock Quote Dan: The patch e36e64930cff: "uas: Use GFP_NOIO rather then GFP_ATOMIC where possible" from Nov 7, 2013, leads to the following static checker warning: drivers/usb/storage/uas.c:806 uas_eh_task_mgmt() error: scheduling with locks held: 'spin_lock:lock' Some other allocations under spinlock are not caught. The fix essentially reverts e36e64930cffd94e1c37fdb82f35989384aa946b Signed-off-by: Oliver Neukum Reported-by: Dan Carpenter Reviewed-by: Hans de Goede Acked-by: Hans de Goede Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/uas.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c index a7ac97cc594..8f4222640bd 100644 --- a/drivers/usb/storage/uas.c +++ b/drivers/usb/storage/uas.c @@ -137,7 +137,7 @@ static void uas_do_work(struct work_struct *work) if (!(cmdinfo->state & IS_IN_WORK_LIST)) continue; - err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_NOIO); + err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_ATOMIC); if (!err) cmdinfo->state &= ~IS_IN_WORK_LIST; else @@ -803,7 +803,7 @@ static int uas_eh_task_mgmt(struct scsi_cmnd *cmnd, devinfo->running_task = 1; memset(&devinfo->response, 0, sizeof(devinfo->response)); - sense_urb = uas_submit_sense_urb(cmnd, GFP_NOIO, + sense_urb = uas_submit_sense_urb(cmnd, GFP_ATOMIC, devinfo->use_streams ? tag : 0); if (!sense_urb) { shost_printk(KERN_INFO, shost, @@ -813,7 +813,7 @@ static int uas_eh_task_mgmt(struct scsi_cmnd *cmnd, spin_unlock_irqrestore(&devinfo->lock, flags); return FAILED; } - if (uas_submit_task_urb(cmnd, GFP_NOIO, function, tag)) { + if (uas_submit_task_urb(cmnd, GFP_ATOMIC, function, tag)) { shost_printk(KERN_INFO, shost, "%s: %s: submit task mgmt urb failed\n", __func__, fname); -- cgit v1.2.3-70-g09d2 From c637f1fa7b0452b71eebd35d00906d371c04714e Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Fri, 28 Mar 2014 11:29:25 +0100 Subject: uas: fix error handling during scsi_scan() intfdata is set only after scsi_scan(). uas_pre_reset() however needs intfdata to be valid and will follow the NULL pointer killing khubd. intfdata must be preemptively set before the host is registered and undone in the error case. Signed-off-by: Oliver Neukum Reviewed-by: Hans de Goede Acked-by: Hans de Goede Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/uas.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c index 8f4222640bd..fcab9b79d9f 100644 --- a/drivers/usb/storage/uas.c +++ b/drivers/usb/storage/uas.c @@ -1096,16 +1096,17 @@ static int uas_probe(struct usb_interface *intf, const struct usb_device_id *id) if (result) goto free_streams; + usb_set_intfdata(intf, shost); result = scsi_add_host(shost, &intf->dev); if (result) goto free_streams; scsi_scan_host(shost); - usb_set_intfdata(intf, shost); return result; free_streams: uas_free_streams(devinfo); + usb_set_intfdata(intf, NULL); set_alt0: usb_set_interface(udev, intf->altsetting[0].desc.bInterfaceNumber, 0); if (shost) -- cgit v1.2.3-70-g09d2 From 94d72f008909610710bb1841d665eeeb010a0be1 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Fri, 28 Mar 2014 11:25:50 +0100 Subject: uas: fix deadlocky memory allocations There are also two allocations with GFP_KERNEL in the pre-/post_reset code paths. That is no good because that is a part of the SCSI error handler. Signed-off-by: Oliver Neukum Reviewed-by: Hans de Goede Acked-by: Hans de Goede Signed-off-by: Greg Kroah-Hartman --- drivers/usb/storage/uas.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c index fcab9b79d9f..511b2295316 100644 --- a/drivers/usb/storage/uas.c +++ b/drivers/usb/storage/uas.c @@ -1030,7 +1030,7 @@ static int uas_configure_endpoints(struct uas_dev_info *devinfo) devinfo->use_streams = 0; } else { devinfo->qdepth = usb_alloc_streams(devinfo->intf, eps + 1, - 3, 256, GFP_KERNEL); + 3, 256, GFP_NOIO); if (devinfo->qdepth < 0) return devinfo->qdepth; devinfo->use_streams = 1; @@ -1047,7 +1047,7 @@ static void uas_free_streams(struct uas_dev_info *devinfo) eps[0] = usb_pipe_endpoint(udev, devinfo->status_pipe); eps[1] = usb_pipe_endpoint(udev, devinfo->data_in_pipe); eps[2] = usb_pipe_endpoint(udev, devinfo->data_out_pipe); - usb_free_streams(devinfo->intf, eps, 3, GFP_KERNEL); + usb_free_streams(devinfo->intf, eps, 3, GFP_NOIO); } static int uas_probe(struct usb_interface *intf, const struct usb_device_id *id) -- cgit v1.2.3-70-g09d2 From 593ceb0c7046c640cf463022189428a45219f595 Mon Sep 17 00:00:00 2001 From: David Fries Date: Tue, 8 Apr 2014 22:37:07 -0500 Subject: w1: fix netlink refcnt leak on error path If the message type is W1_MASTER_CMD or W1_SLAVE_CMD, then a reference is taken when searching for the slave or master device. If there isn't any following data m->len (mlen is a copy) is 0 and packing up the message for later execution is skipped leaving nothing to decrement the reference counts. Way back when, m->len was checked before the search that increments the reference count, but W1_LIST_MASTERS has no additional data, the check was moved in 9be62e0b2fadaf5ff causing this bug. This change reorders to put the check before the reference count is incremented avoiding the problem. Signed-off-by: David Fries Acked-by: Evgeniy Polyakov Signed-off-by: Greg Kroah-Hartman --- drivers/w1/w1_netlink.c | 44 ++++++++++++++++++++++++++------------------ 1 file changed, 26 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/w1/w1_netlink.c b/drivers/w1/w1_netlink.c index 5234964fe00..a02704a5932 100644 --- a/drivers/w1/w1_netlink.c +++ b/drivers/w1/w1_netlink.c @@ -300,12 +300,6 @@ static int w1_process_command_root(struct cn_msg *msg, struct w1_netlink_msg *w; u32 *id; - if (mcmd->type != W1_LIST_MASTERS) { - printk(KERN_NOTICE "%s: msg: %x.%x, wrong type: %u, len: %u.\n", - __func__, msg->id.idx, msg->id.val, mcmd->type, mcmd->len); - return -EPROTO; - } - cn = kmalloc(PAGE_SIZE, GFP_KERNEL); if (!cn) return -ENOMEM; @@ -441,6 +435,9 @@ static void w1_process_cb(struct w1_master *dev, struct w1_async_cmd *async_cmd) w1_netlink_send_error(&node->block->msg, node->m, cmd, node->block->portid, err); + /* ref taken in w1_search_slave or w1_search_master_id when building + * the block + */ if (sl) w1_unref_slave(sl); else @@ -503,30 +500,42 @@ static void w1_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp) msg_len = msg->len; while (msg_len && !err) { - struct w1_reg_num id; - u16 mlen = m->len; dev = NULL; sl = NULL; - memcpy(&id, m->id.id, sizeof(id)); -#if 0 - printk("%s: %02x.%012llx.%02x: type=%02x, len=%u.\n", - __func__, id.family, (unsigned long long)id.id, id.crc, m->type, m->len); -#endif if (m->len + sizeof(struct w1_netlink_msg) > msg_len) { err = -E2BIG; break; } + /* execute on this thread, no need to process later */ + if (m->type == W1_LIST_MASTERS) { + err = w1_process_command_root(msg, m, nsp->portid); + goto out_cont; + } + + /* All following message types require additional data, + * check here before references are taken. + */ + if (!m->len) { + err = -EPROTO; + goto out_cont; + } + + /* both search calls take reference counts */ if (m->type == W1_MASTER_CMD) { dev = w1_search_master_id(m->id.mst.id); } else if (m->type == W1_SLAVE_CMD) { - sl = w1_search_slave(&id); + sl = w1_search_slave((struct w1_reg_num *)m->id.id); if (sl) dev = sl->master; } else { - err = w1_process_command_root(msg, m, nsp->portid); + printk(KERN_NOTICE + "%s: msg: %x.%x, wrong type: %u, len: %u.\n", + __func__, msg->id.idx, msg->id.val, + m->type, m->len); + err = -EPROTO; goto out_cont; } @@ -536,8 +545,6 @@ static void w1_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp) } err = 0; - if (!mlen) - goto out_cont; atomic_inc(&block->refcnt); node->async.cb = w1_process_cb; @@ -557,7 +564,8 @@ out_cont: if (err) w1_netlink_send_error(msg, m, NULL, nsp->portid, err); msg_len -= sizeof(struct w1_netlink_msg) + m->len; - m = (struct w1_netlink_msg *)(((u8 *)m) + sizeof(struct w1_netlink_msg) + m->len); + m = (struct w1_netlink_msg *)(((u8 *)m) + + sizeof(struct w1_netlink_msg) + m->len); /* * Let's allow requests for nonexisting devices. -- cgit v1.2.3-70-g09d2 From 18d7f891bcc7e49f2900215f17a861ccec34b138 Mon Sep 17 00:00:00 2001 From: David Fries Date: Wed, 16 Apr 2014 01:21:21 -0500 Subject: w1: avoid recursive device_add __w1_attach_slave_device calls device_add which calls w1_bus_notify which calls the w1_bq27000 slave driver, which calls platform_device_add and device_add and deadlocks on getting &(&priv->bus_notifier)->rwsem as it is still held in the previous device_add. This avoids the problem by processing the family add/remove outside of the slave device_add call. Commit 47eba33a0997fc7362a introduced this deadlock and added a KOBJ_ADD, as the add was already reported in device_register two add events were being sent. This change suppresses the device_register add so that any slave device sysfs entries are setup before the add goes out. Belisko Marek reported this change fixed the deadlock he was seeing on ARM device tree, while testing on my x86-64 system never saw the deadlock. Reported-by: Belisko Marek Signed-off-by: David Fries Signed-off-by: Greg Kroah-Hartman --- drivers/w1/w1.c | 32 ++++++-------------------------- 1 file changed, 6 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c index b96f61b15dc..ff52618cafb 100644 --- a/drivers/w1/w1.c +++ b/drivers/w1/w1.c @@ -614,27 +614,11 @@ end: return err; } -/* - * Handle sysfs file creation and removal here, before userspace is told that - * the device is added / removed from the system - */ -static int w1_bus_notify(struct notifier_block *nb, unsigned long action, - void *data) +static int w1_family_notify(unsigned long action, struct w1_slave *sl) { - struct device *dev = data; - struct w1_slave *sl; struct w1_family_ops *fops; int err; - /* - * Only care about slave devices at the moment. Yes, we should use a - * separate "type" for this, but for now, look at the release function - * to know which type it is... - */ - if (dev->release != w1_slave_release) - return 0; - - sl = dev_to_w1_slave(dev); fops = sl->family->fops; if (!fops) @@ -673,10 +657,6 @@ static int w1_bus_notify(struct notifier_block *nb, unsigned long action, return 0; } -static struct notifier_block w1_bus_nb = { - .notifier_call = w1_bus_notify, -}; - static int __w1_attach_slave_device(struct w1_slave *sl) { int err; @@ -698,6 +678,9 @@ static int __w1_attach_slave_device(struct w1_slave *sl) dev_dbg(&sl->dev, "%s: registering %s as %p.\n", __func__, dev_name(&sl->dev), sl); + /* suppress for w1_family_notify before sending KOBJ_ADD */ + dev_set_uevent_suppress(&sl->dev, true); + err = device_register(&sl->dev); if (err < 0) { dev_err(&sl->dev, @@ -705,7 +688,7 @@ static int __w1_attach_slave_device(struct w1_slave *sl) dev_name(&sl->dev), err); return err; } - + w1_family_notify(BUS_NOTIFY_ADD_DEVICE, sl); dev_set_uevent_suppress(&sl->dev, false); kobject_uevent(&sl->dev.kobj, KOBJ_ADD); @@ -799,6 +782,7 @@ int w1_unref_slave(struct w1_slave *sl) msg.type = W1_SLAVE_REMOVE; w1_netlink_send(sl->master, &msg); + w1_family_notify(BUS_NOTIFY_DEL_DEVICE, sl); device_unregister(&sl->dev); #ifdef DEBUG memset(sl, 0, sizeof(*sl)); @@ -1186,10 +1170,6 @@ static int __init w1_init(void) goto err_out_exit_init; } - retval = bus_register_notifier(&w1_bus_type, &w1_bus_nb); - if (retval) - goto err_out_bus_unregister; - retval = driver_register(&w1_master_driver); if (retval) { printk(KERN_ERR -- cgit v1.2.3-70-g09d2 From 098ced8fefe4a4e4240fa47b1ed9b00d65b6cd21 Mon Sep 17 00:00:00 2001 From: Joe Schultz Date: Thu, 3 Apr 2014 14:47:55 -0500 Subject: vme_tsi148: Fix typo in tsi148_slave_get() This patch corrects a typo where "vme_base" was used instead of "*vme_base". The typo resulted in an incorrect value being returned to userspace (via vme_user). It also removes the following compile warning on some platforms: warning: cast from pointer to integer of different size [asierra: commit title/log rewording] Signed-off-by: Joe Schultz Signed-off-by: Aaron Sierra Signed-off-by: Greg Kroah-Hartman --- drivers/vme/bridges/vme_tsi148.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/vme/bridges/vme_tsi148.c b/drivers/vme/bridges/vme_tsi148.c index 06990c6a1a6..6b03be71500 100644 --- a/drivers/vme/bridges/vme_tsi148.c +++ b/drivers/vme/bridges/vme_tsi148.c @@ -741,7 +741,7 @@ static int tsi148_slave_get(struct vme_slave_resource *image, int *enabled, reg_join(vme_bound_high, vme_bound_low, &vme_bound); reg_join(pci_offset_high, pci_offset_low, &pci_offset); - *pci_base = (dma_addr_t)vme_base + pci_offset; + *pci_base = (dma_addr_t)(*vme_base + pci_offset); *enabled = 0; *aspace = 0; -- cgit v1.2.3-70-g09d2 From 226572b110ab6083cb8c1d6afb191166b4178179 Mon Sep 17 00:00:00 2001 From: Joe Schultz Date: Thu, 3 Apr 2014 14:48:16 -0500 Subject: vme_tsi148: Fix PCI address mapping assumption Previously, tsi148_master_set() assumed the address contained in its PCI bus resource represented the actual PCI bus address. This is a fine assumption on some platforms. However, on platforms that don't use a 1:1 (CPU:PCI) mapping this results in the tsi148 driver configuring an invalid master window translation. This patch updates the vme_tsi148 driver to first convert the address contained in the PCI bus resource into a PCI bus address before using it. [asierra: account for pcibios_resource_to_bus() prototype change] Signed-off-by: Joe Schultz Signed-off-by: Aaron Sierra Signed-off-by: Greg Kroah-Hartman --- drivers/vme/bridges/vme_tsi148.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/vme/bridges/vme_tsi148.c b/drivers/vme/bridges/vme_tsi148.c index 6b03be71500..e64e4208de2 100644 --- a/drivers/vme/bridges/vme_tsi148.c +++ b/drivers/vme/bridges/vme_tsi148.c @@ -910,11 +910,15 @@ static int tsi148_master_set(struct vme_master_resource *image, int enabled, unsigned long long pci_bound, vme_offset, pci_base; struct vme_bridge *tsi148_bridge; struct tsi148_driver *bridge; + struct pci_bus_region region; + struct pci_dev *pdev; tsi148_bridge = image->parent; bridge = tsi148_bridge->driver_priv; + pdev = container_of(tsi148_bridge->parent, struct pci_dev, dev); + /* Verify input data */ if (vme_base & 0xFFFF) { dev_err(tsi148_bridge->parent, "Invalid VME Window " @@ -949,7 +953,9 @@ static int tsi148_master_set(struct vme_master_resource *image, int enabled, pci_bound = 0; vme_offset = 0; } else { - pci_base = (unsigned long long)image->bus_resource.start; + pcibios_resource_to_bus(pdev->bus, ®ion, + &image->bus_resource); + pci_base = region.start; /* * Bound address is a valid address for the window, adjust -- cgit v1.2.3-70-g09d2 From 177581faf2a5aa71898d223bc47dbc882eeb1488 Mon Sep 17 00:00:00 2001 From: Aaron Sierra Date: Thu, 3 Apr 2014 14:48:27 -0500 Subject: vme_tsi148: Utilize to_pci_dev() macro Save some characters by using to_pci_dev() instead of container_of(). Signed-off-by: Aaron Sierra Signed-off-by: Greg Kroah-Hartman --- drivers/vme/bridges/vme_tsi148.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/vme/bridges/vme_tsi148.c b/drivers/vme/bridges/vme_tsi148.c index e64e4208de2..61e706c0e00 100644 --- a/drivers/vme/bridges/vme_tsi148.c +++ b/drivers/vme/bridges/vme_tsi148.c @@ -320,7 +320,7 @@ static int tsi148_irq_init(struct vme_bridge *tsi148_bridge) struct pci_dev *pdev; struct tsi148_driver *bridge; - pdev = container_of(tsi148_bridge->parent, struct pci_dev, dev); + pdev = to_pci_dev(tsi148_bridge->parent); bridge = tsi148_bridge->driver_priv; @@ -433,9 +433,7 @@ static void tsi148_irq_set(struct vme_bridge *tsi148_bridge, int level, iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEO); if (sync != 0) { - pdev = container_of(tsi148_bridge->parent, - struct pci_dev, dev); - + pdev = to_pci_dev(tsi148_bridge->parent); synchronize_irq(pdev->irq); } } else { @@ -814,7 +812,7 @@ static int tsi148_alloc_resource(struct vme_master_resource *image, tsi148_bridge = image->parent; - pdev = container_of(tsi148_bridge->parent, struct pci_dev, dev); + pdev = to_pci_dev(tsi148_bridge->parent); existing_size = (unsigned long long)(image->bus_resource.end - image->bus_resource.start); @@ -917,7 +915,7 @@ static int tsi148_master_set(struct vme_master_resource *image, int enabled, bridge = tsi148_bridge->driver_priv; - pdev = container_of(tsi148_bridge->parent, struct pci_dev, dev); + pdev = to_pci_dev(tsi148_bridge->parent); /* Verify input data */ if (vme_base & 0xFFFF) { @@ -2238,7 +2236,7 @@ static void *tsi148_alloc_consistent(struct device *parent, size_t size, struct pci_dev *pdev; /* Find pci_dev container of dev */ - pdev = container_of(parent, struct pci_dev, dev); + pdev = to_pci_dev(parent); return pci_alloc_consistent(pdev, size, dma); } @@ -2249,7 +2247,7 @@ static void tsi148_free_consistent(struct device *parent, size_t size, struct pci_dev *pdev; /* Find pci_dev container of dev */ - pdev = container_of(parent, struct pci_dev, dev); + pdev = to_pci_dev(parent); pci_free_consistent(pdev, size, vaddr, dma); } -- cgit v1.2.3-70-g09d2 From 8845cc6415ec28ef8d57b3fb81c75ef9bce69c5f Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Thu, 10 Apr 2014 21:18:16 -0300 Subject: [media] fc2580: fix tuning failure on 32-bit arch There was some frequency calculation overflows which caused tuning failure on 32-bit architecture. Use 64-bit numbers where needed in order to avoid calculation overflows. Thanks for the Finnish person, who asked remain anonymous, reporting, testing and suggesting the fix. Cc: Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/fc2580.c | 6 +++--- drivers/media/tuners/fc2580_priv.h | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/tuners/fc2580.c b/drivers/media/tuners/fc2580.c index 3aecaf46509..f0c9c42867d 100644 --- a/drivers/media/tuners/fc2580.c +++ b/drivers/media/tuners/fc2580.c @@ -195,7 +195,7 @@ static int fc2580_set_params(struct dvb_frontend *fe) f_ref = 2UL * priv->cfg->clock / r_val; n_val = div_u64_rem(f_vco, f_ref, &k_val); - k_val_reg = 1UL * k_val * (1 << 20) / f_ref; + k_val_reg = div_u64(1ULL * k_val * (1 << 20), f_ref); ret = fc2580_wr_reg(priv, 0x18, r18_val | ((k_val_reg >> 16) & 0xff)); if (ret < 0) @@ -348,8 +348,8 @@ static int fc2580_set_params(struct dvb_frontend *fe) if (ret < 0) goto err; - ret = fc2580_wr_reg(priv, 0x37, 1UL * priv->cfg->clock * \ - fc2580_if_filter_lut[i].mul / 1000000000); + ret = fc2580_wr_reg(priv, 0x37, div_u64(1ULL * priv->cfg->clock * + fc2580_if_filter_lut[i].mul, 1000000000)); if (ret < 0) goto err; diff --git a/drivers/media/tuners/fc2580_priv.h b/drivers/media/tuners/fc2580_priv.h index be38a9e637e..646c9945213 100644 --- a/drivers/media/tuners/fc2580_priv.h +++ b/drivers/media/tuners/fc2580_priv.h @@ -22,6 +22,7 @@ #define FC2580_PRIV_H #include "fc2580.h" +#include struct fc2580_reg_val { u8 reg; -- cgit v1.2.3-70-g09d2 From 53974e06603977f348ed978d75c426b0532daa67 Mon Sep 17 00:00:00 2001 From: Vincent Stehlé Date: Fri, 4 Apr 2014 08:43:18 +0200 Subject: topology: Fix compilation warning when not in SMP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The topology_##name() macro does not use its argument when CONFIG_SMP is not set, as it ultimately calls the cpu_data() macro. So we avoid maintaining a possibly unused `cpu' variable, to avoid the following compilation warning: drivers/base/topology.c: In function ‘show_physical_package_id’: drivers/base/topology.c:103:118: warning: unused variable ‘cpu’ [-Wunused-variable] define_id_show_func(physical_package_id); drivers/base/topology.c: In function ‘show_core_id’: drivers/base/topology.c:106:106: warning: unused variable ‘cpu’ [-Wunused-variable] define_id_show_func(core_id); This can be seen with e.g. x86 defconfig and CONFIG_SMP not set. Signed-off-by: Vincent Stehlé Cc: Greg Kroah-Hartman Cc: # 3.10.x Cc: # 3.13.x Cc: # 3.14.x Signed-off-by: Greg Kroah-Hartman --- drivers/base/topology.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/base/topology.c b/drivers/base/topology.c index bbcbd3c4392..be7c1fb7c0c 100644 --- a/drivers/base/topology.c +++ b/drivers/base/topology.c @@ -39,8 +39,7 @@ static ssize_t show_##name(struct device *dev, \ struct device_attribute *attr, char *buf) \ { \ - unsigned int cpu = dev->id; \ - return sprintf(buf, "%d\n", topology_##name(cpu)); \ + return sprintf(buf, "%d\n", topology_##name(dev->id)); \ } #if defined(topology_thread_cpumask) || defined(topology_core_cpumask) || \ -- cgit v1.2.3-70-g09d2 From 03367ef5ea811475187a0732aada068919e14d61 Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Thu, 3 Apr 2014 18:02:45 -0700 Subject: Drivers: hv: vmbus: Negotiate version 3.0 when running on ws2012r2 hosts Only ws2012r2 hosts support the ability to reconnect to the host on VMBUS. This functionality is needed by kexec in Linux. To use this functionality we need to negotiate version 3.0 of the VMBUS protocol. Signed-off-by: K. Y. Srinivasan Cc: [3.9+] Signed-off-by: Greg Kroah-Hartman --- drivers/hv/connection.c | 5 ++++- include/linux/hyperv.h | 4 +++- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c index f2d7bf90c9f..2e7801af466 100644 --- a/drivers/hv/connection.c +++ b/drivers/hv/connection.c @@ -55,6 +55,9 @@ static __u32 vmbus_get_next_version(__u32 current_version) case (VERSION_WIN8): return VERSION_WIN7; + case (VERSION_WIN8_1): + return VERSION_WIN8; + case (VERSION_WS2008): default: return VERSION_INVAL; @@ -77,7 +80,7 @@ static int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, msg->interrupt_page = virt_to_phys(vmbus_connection.int_page); msg->monitor_page1 = virt_to_phys(vmbus_connection.monitor_pages[0]); msg->monitor_page2 = virt_to_phys(vmbus_connection.monitor_pages[1]); - if (version == VERSION_WIN8) + if (version == VERSION_WIN8_1) msg->target_vcpu = hv_context.vp_index[smp_processor_id()]; /* diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h index ab7359fde98..2d7b4f139c3 100644 --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h @@ -147,15 +147,17 @@ hv_get_ringbuffer_availbytes(struct hv_ring_buffer_info *rbi, * 0 . 13 (Windows Server 2008) * 1 . 1 (Windows 7) * 2 . 4 (Windows 8) + * 3 . 0 (Windows 8 R2) */ #define VERSION_WS2008 ((0 << 16) | (13)) #define VERSION_WIN7 ((1 << 16) | (1)) #define VERSION_WIN8 ((2 << 16) | (4)) +#define VERSION_WIN8_1 ((3 << 16) | (0)) #define VERSION_INVAL -1 -#define VERSION_CURRENT VERSION_WIN8 +#define VERSION_CURRENT VERSION_WIN8_1 /* Make maximum size of pipe payload of 16K */ #define MAX_PIPE_DATA_PAYLOAD (sizeof(u8) * 16384) -- cgit v1.2.3-70-g09d2 From 93a2e470ef3b17495029a89a05e25830aeca1ffb Mon Sep 17 00:00:00 2001 From: Sanjay Singh Rawat Date: Fri, 21 Mar 2014 13:55:10 +0530 Subject: serial: omap: free the wakeup settings in remove Signed-off-by: Sanjay Singh Rawat Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/omap-serial.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index dd8b1a5458f..ecfafbb3035 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -1789,6 +1789,7 @@ static int serial_omap_remove(struct platform_device *dev) pm_runtime_disable(up->dev); uart_remove_one_port(&serial_omap_reg, &up->port); pm_qos_remove_request(&up->pm_qos_request); + device_init_wakeup(&dev->dev, false); return 0; } -- cgit v1.2.3-70-g09d2 From 4ea8dafd2475e26b3cee3836bc6e6fddbdfb2721 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Tue, 25 Mar 2014 15:53:12 +0100 Subject: serial: efm32: use $vendor,$device scheme for compatible string MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Wolfram Sang pointed out that "efm32,$device" is non-standard. So use the common scheme and prefix device with "efm32-". The old compatible string is left in place until arch/arm/boot/dts/efm32* is fixed. Reported-by: Wolfram Sang Signed-off-by: Uwe Kleine-König Acked-by: Wolfram Sang Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/serial/efm32-uart.txt | 4 ++-- drivers/tty/serial/efm32-uart.c | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/serial/efm32-uart.txt b/Documentation/devicetree/bindings/serial/efm32-uart.txt index 1984bdfbd54..3ca01336b83 100644 --- a/Documentation/devicetree/bindings/serial/efm32-uart.txt +++ b/Documentation/devicetree/bindings/serial/efm32-uart.txt @@ -1,7 +1,7 @@ * Energymicro efm32 UART Required properties: -- compatible : Should be "efm32,uart" +- compatible : Should be "energymicro,efm32-uart" - reg : Address and length of the register set - interrupts : Should contain uart interrupt @@ -13,7 +13,7 @@ Optional properties: Example: uart@0x4000c400 { - compatible = "efm32,uart"; + compatible = "energymicro,efm32-uart"; reg = <0x4000c400 0x400>; interrupts = <15>; efm32,location = <0>; diff --git a/drivers/tty/serial/efm32-uart.c b/drivers/tty/serial/efm32-uart.c index 028582e924a..c167a710dc3 100644 --- a/drivers/tty/serial/efm32-uart.c +++ b/drivers/tty/serial/efm32-uart.c @@ -798,6 +798,9 @@ static int efm32_uart_remove(struct platform_device *pdev) static const struct of_device_id efm32_uart_dt_ids[] = { { + .compatible = "energymicro,efm32-uart", + }, { + /* doesn't follow the "vendor,device" scheme, don't use */ .compatible = "efm32,uart", }, { /* sentinel */ -- cgit v1.2.3-70-g09d2 From 717f3bbab3c7628736ef738fdbf3d9a28578c26c Mon Sep 17 00:00:00 2001 From: Seth Bollinger Date: Tue, 25 Mar 2014 12:55:37 -0500 Subject: serial_core: Fix conditional start_tx on ring buffer not empty If the serial_core ring buffer empties just as the tty layer receives an XOFF, then start_tx will never be called when the tty layer receives an XON as the serial_core ring buffer is empty. This will possibly leave a few bytes trapped in the fifo for drivers that disable the transmitter when flow controlled. Signed-off-by: Seth Bollinger Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 2cf5649a6dc..dd1a7bef664 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -89,8 +89,7 @@ static void __uart_start(struct tty_struct *tty) struct uart_state *state = tty->driver_data; struct uart_port *port = state->uart_port; - if (!uart_circ_empty(&state->xmit) && state->xmit.buf && - !tty->stopped && !tty->hw_stopped) + if (!tty->stopped && !tty->hw_stopped) port->ops->start_tx(port); } -- cgit v1.2.3-70-g09d2 From 2f310b8e418ac5eb3833a9f36791c24a97f1f557 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Thu, 27 Mar 2014 13:38:19 +0400 Subject: Revert "serial: clps711x: Give a chance to perform useful tasks during wait loop" This reverts commit 63e3ad3252695a2b8c01b6f6c225e4537af08b85, since this not works as expected and produce runtime error: BUG: sleeping function called from invalid context at drivers/tty/serial/clps711x.c:379 in_atomic(): 0, irqs_disabled(): 128, pid: 287, name: mount Signed-off-by: Alexander Shiyan Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/clps711x.c | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/clps711x.c b/drivers/tty/serial/clps711x.c index 5e6fdb1ea73..14aaea0d413 100644 --- a/drivers/tty/serial/clps711x.c +++ b/drivers/tty/serial/clps711x.c @@ -368,16 +368,12 @@ static const struct uart_ops uart_clps711x_ops = { static void uart_clps711x_console_putchar(struct uart_port *port, int ch) { struct clps711x_port *s = dev_get_drvdata(port->dev); + u32 sysflg = 0; /* Wait for FIFO is not full */ - while (1) { - u32 sysflg = 0; - + do { regmap_read(s->syscon, SYSFLG_OFFSET, &sysflg); - if (!(sysflg & SYSFLG_UTXFF)) - break; - cond_resched(); - } + } while (sysflg & SYSFLG_UTXFF); writew(ch, port->membase + UARTDR_OFFSET); } @@ -387,18 +383,14 @@ static void uart_clps711x_console_write(struct console *co, const char *c, { struct uart_port *port = clps711x_uart.state[co->index].uart_port; struct clps711x_port *s = dev_get_drvdata(port->dev); + u32 sysflg = 0; uart_console_write(port, c, n, uart_clps711x_console_putchar); /* Wait for transmitter to become empty */ - while (1) { - u32 sysflg = 0; - + do { regmap_read(s->syscon, SYSFLG_OFFSET, &sysflg); - if (!(sysflg & SYSFLG_UBUSY)) - break; - cond_resched(); - } + } while (sysflg & SYSFLG_UBUSY); } static int uart_clps711x_console_setup(struct console *co, char *options) -- cgit v1.2.3-70-g09d2 From c3c00b6f7f79be1dd1aa0969ee0ab7d1f79eda79 Mon Sep 17 00:00:00 2001 From: Daniel Thompson Date: Fri, 28 Mar 2014 10:53:10 +0000 Subject: serial: st-asc: Fix SysRq char handling This driver, like several others, uses the upper bits of the character to track both real and dummy state. Unfortunately it neglects to mask these bits properly when passing the character data around. This means neither break detection nor sysrq character handling work correctly. This patch adds the requires masking and has been tested to confirm that it correctly handles magic sysrq sequences on ST's B2020 board. Signed-off-by: Daniel Thompson Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/st-asc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c index 21e6e84c0df..dd3a96e0702 100644 --- a/drivers/tty/serial/st-asc.c +++ b/drivers/tty/serial/st-asc.c @@ -295,7 +295,7 @@ static void asc_receive_chars(struct uart_port *port) status & ASC_STA_OE) { if (c & ASC_RXBUF_FE) { - if (c == ASC_RXBUF_FE) { + if (c == (ASC_RXBUF_FE | ASC_RXBUF_DUMMY_RX)) { port->icount.brk++; if (uart_handle_break(port)) continue; @@ -325,7 +325,7 @@ static void asc_receive_chars(struct uart_port *port) flag = TTY_FRAME; } - if (uart_handle_sysrq_char(port, c)) + if (uart_handle_sysrq_char(port, c & 0xff)) continue; uart_insert_char(port, c, ASC_RXBUF_DUMMY_OE, c & 0xff, flag); -- cgit v1.2.3-70-g09d2 From e55c2a07c4abf65d1915a7507a625c82c72fed5a Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 3 Apr 2014 11:36:22 +0200 Subject: serial: timberdale: Depend on X86_32 As far as I know the Timberdale chip was only used as a companion for Intel Atom E600 series processors. As such, its drivers are only useful on X86_32. Signed-off-by: Jean Delvare Cc: Greg Kroah-Hartman Cc: Jiri Slaby Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 2e6d8ddc442..5d9b01aa54f 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1226,6 +1226,7 @@ config SERIAL_BFIN_SPORT3_UART_CTSRTS config SERIAL_TIMBERDALE tristate "Support for timberdale UART" select SERIAL_CORE + depends on X86_32 || COMPILE_TEST ---help--- Add support for UART controller on timberdale. -- cgit v1.2.3-70-g09d2 From b2aeb775f814c9543784b15a5f2d87ea91005f3f Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Sat, 12 Apr 2014 19:47:17 +0200 Subject: serial: pl011: change Rx burst size to half of trigger level The amba-pl011.c driver sets DMA burst size equal to FIFO trigger level. If now exactly DMA burst size bytes are received, the DMAC will retrieve them all and no Rx timeout interrupt will be generated. To fix that set the burst size to half the FIFO trigger level. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/amba-pl011.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index d4eda24aa68..ca0ec600fab 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -318,7 +318,7 @@ static void pl011_dma_probe_initcall(struct device *dev, struct uart_amba_port * .src_addr = uap->port.mapbase + UART01x_DR, .src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE, .direction = DMA_DEV_TO_MEM, - .src_maxburst = uap->fifosize >> 1, + .src_maxburst = uap->fifosize >> 2, .device_fc = false, }; -- cgit v1.2.3-70-g09d2 From bf903c0c6ddfedec19ba92626ca30e98bfafbe08 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 27 Mar 2014 11:40:39 +0100 Subject: serial_core: Fix pm imbalance on unbind When a serial port is closed, uart_close() takes care of shutting down the hardware, and powering it down. When a serial port is unbound while in use, uart_close() bypasses all of this, as this is supposed to be done through uart_hangup() (invoked via tty_vhangup() in uart_remove_one_port()). However, uart_hangup() does not set the hardware's power state, leaving it powered up. This may also lead to unbounded nesting counts in clock and power management, depending on their internal implementation. Make sure to power down the port in uart_hangup(), except when the port is used as a serial console. For serial consoles, this operation must be postponed until after the port becomes completely unused. This case is not fixed yet, as it depends on a (future) fix for the tty->count vs. port->count imbalance on failed uart_open(). After this, the module clock used by the sh-sci driver is disabled on unbind while the serial port is in use. Signed-off-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_core.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index dd1a7bef664..f26834d262b 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -1451,6 +1451,8 @@ static void uart_hangup(struct tty_struct *tty) clear_bit(ASYNCB_NORMAL_ACTIVE, &port->flags); spin_unlock_irqrestore(&port->lock, flags); tty_port_tty_set(port, NULL); + if (!uart_console(state->uart_port)) + uart_change_pm(state, UART_PM_STATE_OFF); wake_up_interruptible(&port->open_wait); wake_up_interruptible(&port->delta_msr_wait); } -- cgit v1.2.3-70-g09d2 From d758c9c1b36b4d9a141c2146c70398d756167ed1 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Tue, 25 Mar 2014 11:48:47 -0700 Subject: serial: omap: Fix missing pm_runtime_resume handling by simplifying code The lack of pm_runtime_resume handling for the device state leads into device wake-up interrupts not working after a while for runtime PM. Also, serial-omap is confused about the use of device_may_wakeup. The checks for device_may_wakeup should only be done for suspend and resume, not for pm_runtime_suspend and pm_runtime_resume. The wake-up events for PM runtime should always be enabled. The lack of pm_runtime_resume handling leads into device wake-up interrupts not working after a while for runtime PM. Rather than try to patch over the issue of adding complex tests to the pm_runtime_resume, let's fix the issues properly: 1. Make serial_omap_enable_wakeup deal with all internal PM state handling so we don't need to test for up->wakeups_enabled elsewhere. Later on once omap3 boots in device tree only mode we can also remove the up->wakeups_enabled flag and rely on the wake-up interrupt enable/disable state alone. 2. Do the device_may_wakeup checks in suspend and resume only, for runtime PM the wake-up events need to be always enabled. 3. Finally just call serial_omap_enable_wakeup and make sure we call it also in pm_runtime_resume. 4. Note that we also have to use disable_irq_nosync as serial_omap_irq calls pm_runtime_get_sync. Fixes: 2a0b965cfb6e (serial: omap: Add support for optional wake-up) Cc: stable@vger.kernel.org # v3.13+ Signed-off-by: Tony Lindgren Acked-by: Felipe Balbi Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/omap-serial.c | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index ecfafbb3035..08b6b9419f0 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -225,14 +225,19 @@ static inline void serial_omap_enable_wakeirq(struct uart_omap_port *up, if (enable) enable_irq(up->wakeirq); else - disable_irq(up->wakeirq); + disable_irq_nosync(up->wakeirq); } static void serial_omap_enable_wakeup(struct uart_omap_port *up, bool enable) { struct omap_uart_port_info *pdata = dev_get_platdata(up->dev); + if (enable == up->wakeups_enabled) + return; + serial_omap_enable_wakeirq(up, enable); + up->wakeups_enabled = enable; + if (!pdata || !pdata->enable_wakeup) return; @@ -1495,6 +1500,11 @@ static int serial_omap_suspend(struct device *dev) uart_suspend_port(&serial_omap_reg, &up->port); flush_work(&up->qos_work); + if (device_may_wakeup(dev)) + serial_omap_enable_wakeup(up, true); + else + serial_omap_enable_wakeup(up, false); + return 0; } @@ -1502,6 +1512,9 @@ static int serial_omap_resume(struct device *dev) { struct uart_omap_port *up = dev_get_drvdata(dev); + if (device_may_wakeup(dev)) + serial_omap_enable_wakeup(up, false); + uart_resume_port(&serial_omap_reg, &up->port); return 0; @@ -1878,17 +1891,7 @@ static int serial_omap_runtime_suspend(struct device *dev) up->context_loss_cnt = serial_omap_get_context_loss_count(up); - if (device_may_wakeup(dev)) { - if (!up->wakeups_enabled) { - serial_omap_enable_wakeup(up, true); - up->wakeups_enabled = true; - } - } else { - if (up->wakeups_enabled) { - serial_omap_enable_wakeup(up, false); - up->wakeups_enabled = false; - } - } + serial_omap_enable_wakeup(up, true); up->latency = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE; schedule_work(&up->qos_work); @@ -1902,6 +1905,8 @@ static int serial_omap_runtime_resume(struct device *dev) int loss_cnt = serial_omap_get_context_loss_count(up); + serial_omap_enable_wakeup(up, false); + if (loss_cnt < 0) { dev_dbg(dev, "serial_omap_get_context_loss_count failed : %d\n", loss_cnt); -- cgit v1.2.3-70-g09d2 From f4f653e9875e573860e783fecbebde284a8626f5 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 1 Apr 2014 13:37:00 +0200 Subject: serial: 8250, disable "too much work" messages The 8250 driver now reports many of these: serial8250: too much work for irq4 These messages turned out to be common these days with a use of virtualization. I tried to increase the limit of processed characters in commit e7328ae1848966181a7ac47e8ae6cddbd2cf55f3 (serial: 8250, increase PASS_LIMIT) in 2011. It was raised from 256 to 512, but it is still not enough, apparently. So disable the warning unless somebody turns on DEBUG (or DYNAMIC_DEBUG _and_ the message). Signed-off-by: Jiri Slaby Reported-by: Martin Pluskal Reported-by: Takashi Iwai Tested-by: Takashi Iwai References: https://bugzilla.novell.com/show_bug.cgi?id=868394 Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index 81f909c2101..139ab1997e0 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -1601,8 +1601,7 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id) l = l->next; if (l == i->head && pass_counter++ > PASS_LIMIT) { - /* If we hit this, we're dead. */ - printk_ratelimited(KERN_ERR + pr_debug_ratelimited( "serial8250: too much work for irq%d\n", irq); break; } -- cgit v1.2.3-70-g09d2 From 7d1c2858c49095ab748f55354b89dbd6b18d28b9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 2 Apr 2014 14:45:21 +0200 Subject: ttyprintk: Fix wrong tty_unregister_driver() call in the error path ttyprintk driver calls tty_unregister_driver() wrongly in the error path of tty_register_driver(). Also, setting ttyprintk_driver to NULL is utterly superfluous, so let's get rid of it, too. Reported-by: Jean Delvare Reviewed-by: Jean Delvare Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- drivers/char/ttyprintk.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/char/ttyprintk.c b/drivers/char/ttyprintk.c index daea84c4174..2a39c579036 100644 --- a/drivers/char/ttyprintk.c +++ b/drivers/char/ttyprintk.c @@ -210,10 +210,8 @@ static int __init ttyprintk_init(void) return 0; error: - tty_unregister_driver(ttyprintk_driver); put_tty_driver(ttyprintk_driver); tty_port_destroy(&tpk_port.port); - ttyprintk_driver = NULL; return ret; } device_initcall(ttyprintk_init); -- cgit v1.2.3-70-g09d2 From b24313a82cf24e90170671ea74360b3e6ef3a91f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 2 Apr 2014 14:45:22 +0200 Subject: ttyprintk: Allow built as a module The driver is well written to be used as a module, just the exit call is missing. Reviewed-by: Jean Delvare Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- drivers/char/Kconfig | 2 +- drivers/char/ttyprintk.c | 13 ++++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index fbae63e3d30..6e9f74a5c09 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -40,7 +40,7 @@ config SGI_MBCS source "drivers/tty/serial/Kconfig" config TTY_PRINTK - bool "TTY driver to output user messages via printk" + tristate "TTY driver to output user messages via printk" depends on EXPERT && TTY default n ---help--- diff --git a/drivers/char/ttyprintk.c b/drivers/char/ttyprintk.c index 2a39c579036..a15ce4ef39c 100644 --- a/drivers/char/ttyprintk.c +++ b/drivers/char/ttyprintk.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include struct ttyprintk_port { struct tty_port port; @@ -214,4 +214,15 @@ error: tty_port_destroy(&tpk_port.port); return ret; } + +static void __exit ttyprintk_exit(void) +{ + tty_unregister_driver(ttyprintk_driver); + put_tty_driver(ttyprintk_driver); + tty_port_destroy(&tpk_port.port); +} + device_initcall(ttyprintk_init); +module_exit(ttyprintk_exit); + +MODULE_LICENSE("GPL"); -- cgit v1.2.3-70-g09d2 From c70dbb1e79a1ac2802b4b7b6de7456b230fbbbeb Mon Sep 17 00:00:00 2001 From: Chen Tingjie Date: Tue, 15 Apr 2014 11:52:51 +0800 Subject: tty: fix memleak in alloc_pid There is memleak in alloc_pid: ------------------------------ unreferenced object 0xd3453a80 (size 64): comm "adbd", pid 1730, jiffies 66363 (age 6586.950s) hex dump (first 32 bytes): 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00 00 00 00 40 c2 f6 d5 00 d3 25 c1 59 28 00 00 ....@.....%.Y(.. backtrace: [] kmemleak_alloc+0x3c/0xa0 [] kmem_cache_alloc+0xc6/0x190 [] alloc_pid+0x1e/0x400 [] copy_process.part.39+0xad4/0x1120 [] do_fork+0x99/0x330 [] sys_fork+0x28/0x30 [] syscall_call+0x7/0xb [] 0xffffffff the leak is due to unreleased pid->count, which execute in function: get_pid()(pid->count++) and put_pid()(pid->count--). The race condition as following: task[dumpsys] task[adbd] in disassociate_ctty() in tty_signal_session_leader() ----------------------- ------------------------- tty = get_current_tty(); // tty is not NULL ... spin_lock_irq(¤t->sighand->siglock); put_pid(current->signal->tty_old_pgrp); current->signal->tty_old_pgrp = NULL; spin_unlock_irq(¤t->sighand->siglock); spin_lock_irq(&p->sighand->siglock); ... p->signal->tty = NULL; ... spin_unlock_irq(&p->sighand->siglock); tty = get_current_tty(); // tty NULL, goto else branch by accident. if (tty) { ... put_pid(tty_session); put_pid(tty_pgrp); ... } else { print msg } in task[dumpsys], in disassociate_ctty(), tty is set NULL by task[adbd], tty_signal_session_leader(), then it goto else branch and lack of put_pid(), cause memleak. move spin_unlock(sighand->siglock) after get_current_tty() can avoid the race and fix the memleak. Signed-off-by: Zhang Jun Signed-off-by: Chen Tingjie Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_io.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index d3448a90f0f..34110719fe0 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -878,9 +878,8 @@ void disassociate_ctty(int on_exit) spin_lock_irq(¤t->sighand->siglock); put_pid(current->signal->tty_old_pgrp); current->signal->tty_old_pgrp = NULL; - spin_unlock_irq(¤t->sighand->siglock); - tty = get_current_tty(); + tty = tty_kref_get(current->signal->tty); if (tty) { unsigned long flags; spin_lock_irqsave(&tty->ctrl_lock, flags); @@ -897,6 +896,7 @@ void disassociate_ctty(int on_exit) #endif } + spin_unlock_irq(¤t->sighand->siglock); /* Now clear signal->tty under the lock */ read_lock(&tasklist_lock); session_clear_tty(task_session(current)); -- cgit v1.2.3-70-g09d2 From 9ca83fd2d5805a5e4608a901ffa802697adc638b Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Mon, 14 Apr 2014 18:32:13 +0200 Subject: tty: Fix help text of SYNCLINK_CS Enabling SYNCLINK_CS as a module builds synclink_cs, not synclinkmp. Signed-off-by: Jean Delvare Signed-off-by: Greg Kroah-Hartman --- drivers/char/pcmcia/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/char/pcmcia/Kconfig b/drivers/char/pcmcia/Kconfig index b27f5342fe7..8d3dfb0c8a2 100644 --- a/drivers/char/pcmcia/Kconfig +++ b/drivers/char/pcmcia/Kconfig @@ -15,7 +15,7 @@ config SYNCLINK_CS This driver may be built as a module ( = code which can be inserted in and removed from the running kernel whenever you want). - The module will be called synclinkmp. If you want to do that, say M + The module will be called synclink_cs. If you want to do that, say M here. config CARDMAN_4000 -- cgit v1.2.3-70-g09d2 From 1e7da0530423a232747d64c2113ace55b01e5754 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Sat, 5 Apr 2014 16:31:08 +0200 Subject: serial: amba-pl011: fix regression, causing an Oops on rmmod A recent commit ef2889f7ffee67f0aed49e854c72be63f1466759 "serial: pl011: Move uart_register_driver call to device probe" introduced a regression, causing the pl011 driver to Oops if more than 1 port have been probed. Fix the Oops by only calling uart_unregister_driver() once after the last port has been removed. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/amba-pl011.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index ca0ec600fab..dacf0a09ab2 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -2176,6 +2176,7 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id) static int pl011_remove(struct amba_device *dev) { struct uart_amba_port *uap = amba_get_drvdata(dev); + bool busy = false; int i; uart_remove_one_port(&amba_reg, &uap->port); @@ -2183,9 +2184,12 @@ static int pl011_remove(struct amba_device *dev) for (i = 0; i < ARRAY_SIZE(amba_ports); i++) if (amba_ports[i] == uap) amba_ports[i] = NULL; + else if (amba_ports[i]) + busy = true; pl011_dma_remove(uap); - uart_unregister_driver(&amba_reg); + if (!busy) + uart_unregister_driver(&amba_reg); return 0; } -- cgit v1.2.3-70-g09d2 From 94f8cc0eea03648e5cc5de1a4e7dc464de92cc74 Mon Sep 17 00:00:00 2001 From: Frank Rowand Date: Wed, 16 Apr 2014 17:12:30 -0700 Subject: drivers/base/dd.c incorrect pr_debug() parameters pr_debug() parameters are reverse order of format string Signed-off-by: Frank Rowand Signed-off-by: Greg Kroah-Hartman --- drivers/base/dd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 06051767393..8986b9f2278 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -187,8 +187,8 @@ static void driver_bound(struct device *dev) return; } - pr_debug("driver: '%s': %s: bound to device '%s'\n", dev_name(dev), - __func__, dev->driver->name); + pr_debug("driver: '%s': %s: bound to device '%s'\n", dev->driver->name, + __func__, dev_name(dev)); klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices); -- cgit v1.2.3-70-g09d2 From ce965c3d2e68c5325dd5624eb101d70423022fef Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Mon, 14 Apr 2014 17:29:18 +0200 Subject: memory: mvebu-devbus: fix the conversion of the bus width According to the Armada 370 and Armada XP datasheets, the part of the Device Bus register that configure the bus width should contain 0 for a 8 bits bus width, and 1 for a 16 bits bus width (other values are unsupported/reserved). However, the current conversion done in the driver to convert from a bus width in bits to the value expected by the register leads to setting the register to 1 for a 8 bits bus, and 2 for a 16 bits bus. This mistake was compensated by a mistake in the existing Device Tree files for Armada 370/XP platforms: they were declaring a 8 bits bus width, while the hardware in fact uses a 16 bits bus width. This commit fixes that by adjusting the conversion logic. This patch fixes a bug that was introduced in 3edad321b1bd2e6c8b5f38146c115c8982438f06 ('drivers: memory: Introduce Marvell EBU Device Bus driver'), which was merged in v3.11. Signed-off-by: Thomas Petazzoni Link: https://lkml.kernel.org/r/1397489361-5833-2-git-send-email-thomas.petazzoni@free-electrons.com Fixes: 3edad321b1bd ('drivers: memory: Introduce Marvell EBU Device Bus driver') Cc: stable@vger.kernel.org # v3.11+ Acked-by: Ezequiel Garcia Acked-by: Gregory CLEMENT Signed-off-by: Jason Cooper --- drivers/memory/mvebu-devbus.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/memory/mvebu-devbus.c b/drivers/memory/mvebu-devbus.c index 110c0362705..b59a17fb7c3 100644 --- a/drivers/memory/mvebu-devbus.c +++ b/drivers/memory/mvebu-devbus.c @@ -108,8 +108,19 @@ static int devbus_set_timing_params(struct devbus *devbus, node->full_name); return err; } - /* Convert bit width to byte width */ - r.bus_width /= 8; + + /* + * The bus width is encoded into the register as 0 for 8 bits, + * and 1 for 16 bits, so we do the necessary conversion here. + */ + if (r.bus_width == 8) + r.bus_width = 0; + else if (r.bus_width == 16) + r.bus_width = 1; + else { + dev_err(devbus->dev, "invalid bus width %d\n", r.bus_width); + return -EINVAL; + } err = get_timing_param_ps(devbus, node, "devbus,badr-skew-ps", &r.badr_skew); -- cgit v1.2.3-70-g09d2 From f7018c21350204c4cf628462f229d44d03545254 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 13 Feb 2014 15:31:38 +0200 Subject: video: move fbdev to drivers/video/fbdev The drivers/video directory is a mess. It contains generic video related files, directories for backlight, console, linux logo, lots of fbdev device drivers, fbdev framework files. Make some order into the chaos by creating drivers/video/fbdev directory, and move all fbdev related files there. No functionality is changed, although I guess it is possible that some subtle Makefile build order related issue could be created by this patch. Signed-off-by: Tomi Valkeinen Acked-by: Laurent Pinchart Acked-by: Geert Uytterhoeven Acked-by: Rob Clark Acked-by: Jingoo Han Acked-by: Daniel Vetter --- Documentation/DocBook/device-drivers.tmpl | 10 +- drivers/Makefile | 4 +- drivers/staging/xgifb/vb_def.h | 2 +- drivers/staging/xgifb/vb_struct.h | 2 +- drivers/staging/xgifb/vgatypes.h | 4 +- drivers/video/68328fb.c | 503 - drivers/video/Kconfig | 2476 +---- drivers/video/Makefile | 166 +- drivers/video/acornfb.c | 1143 -- drivers/video/acornfb.h | 169 - drivers/video/amba-clcd.c | 656 -- drivers/video/amifb.c | 3792 ------- drivers/video/arcfb.c | 667 -- drivers/video/arkfb.c | 1231 --- drivers/video/asiliantfb.c | 624 -- drivers/video/atafb.c | 3266 ------ drivers/video/atafb.h | 36 - drivers/video/atafb_iplan2p2.c | 293 - drivers/video/atafb_iplan2p4.c | 308 - drivers/video/atafb_iplan2p8.c | 345 - drivers/video/atafb_mfb.c | 112 - drivers/video/atafb_utils.h | 400 - drivers/video/atmel_lcdfb.c | 1453 --- drivers/video/aty/Makefile | 15 - drivers/video/aty/ati_ids.h | 214 - drivers/video/aty/aty128fb.c | 2591 ----- drivers/video/aty/atyfb.h | 369 - drivers/video/aty/atyfb_base.c | 4029 ------- drivers/video/aty/mach64_accel.c | 430 - drivers/video/aty/mach64_ct.c | 649 -- drivers/video/aty/mach64_cursor.c | 225 - drivers/video/aty/mach64_gx.c | 910 -- drivers/video/aty/radeon_accel.c | 328 - drivers/video/aty/radeon_backlight.c | 221 - drivers/video/aty/radeon_base.c | 2568 ----- drivers/video/aty/radeon_i2c.c | 167 - drivers/video/aty/radeon_monitor.c | 1052 -- drivers/video/aty/radeon_pm.c | 2906 ----- drivers/video/aty/radeonfb.h | 634 -- drivers/video/au1100fb.c | 642 -- drivers/video/au1100fb.h | 377 - drivers/video/au1200fb.c | 1859 ---- drivers/video/au1200fb.h | 572 - drivers/video/auo_k1900fb.c | 205 - drivers/video/auo_k1901fb.c | 258 - drivers/video/auo_k190x.c | 1198 -- drivers/video/auo_k190x.h | 129 - drivers/video/bf537-lq035.c | 915 -- drivers/video/bf54x-lq043fb.c | 767 -- drivers/video/bfin-lq035q1-fb.c | 864 -- drivers/video/bfin-t350mcqb-fb.c | 670 -- drivers/video/bfin_adv7393fb.c | 827 -- drivers/video/bfin_adv7393fb.h | 321 - drivers/video/broadsheetfb.c | 1223 -- drivers/video/bt431.h | 235 - drivers/video/bt455.h | 94 - drivers/video/bw2.c | 406 - drivers/video/c2p.h | 19 - drivers/video/c2p_core.h | 153 - drivers/video/c2p_iplan2.c | 153 - drivers/video/c2p_planar.c | 156 - drivers/video/carminefb.c | 788 -- drivers/video/carminefb.h | 64 - drivers/video/carminefb_regs.h | 159 - drivers/video/cfbcopyarea.c | 434 - drivers/video/cfbfillrect.c | 371 - drivers/video/cfbimgblt.c | 313 - drivers/video/cg14.c | 626 -- drivers/video/cg3.c | 492 - drivers/video/cg6.c | 885 -- drivers/video/chipsfb.c | 519 - drivers/video/cirrusfb.c | 2952 ----- drivers/video/clps711xfb.c | 315 - drivers/video/cobalt_lcdfb.c | 401 - drivers/video/console/sticon.c | 2 +- drivers/video/console/sticore.c | 2 +- drivers/video/controlfb.c | 1084 -- drivers/video/controlfb.h | 145 - drivers/video/cyber2000fb.c | 1901 ---- drivers/video/cyber2000fb.h | 497 - drivers/video/da8xx-fb.c | 1659 --- drivers/video/dnfb.c | 303 - drivers/video/edid.h | 138 - drivers/video/efifb.c | 360 - drivers/video/ep93xx-fb.c | 634 -- drivers/video/exynos/Kconfig | 32 - drivers/video/exynos/Makefile | 7 - drivers/video/exynos/exynos_mipi_dsi.c | 574 - drivers/video/exynos/exynos_mipi_dsi_common.c | 880 -- drivers/video/exynos/exynos_mipi_dsi_common.h | 46 - drivers/video/exynos/exynos_mipi_dsi_lowlevel.c | 618 -- drivers/video/exynos/exynos_mipi_dsi_lowlevel.h | 112 - drivers/video/exynos/exynos_mipi_dsi_regs.h | 149 - drivers/video/exynos/s6e8ax0.c | 898 -- drivers/video/fb-puv3.c | 838 -- drivers/video/fb_ddc.c | 119 - drivers/video/fb_defio.c | 245 - drivers/video/fb_draw.h | 186 - drivers/video/fb_notify.c | 47 - drivers/video/fb_sys_fops.c | 104 - drivers/video/fbcmap.c | 362 - drivers/video/fbcvt.c | 379 - drivers/video/fbdev/68328fb.c | 503 + drivers/video/fbdev/Kconfig | 2474 +++++ drivers/video/fbdev/Makefile | 166 + drivers/video/fbdev/acornfb.c | 1143 ++ drivers/video/fbdev/acornfb.h | 169 + drivers/video/fbdev/amba-clcd.c | 656 ++ drivers/video/fbdev/amifb.c | 3792 +++++++ drivers/video/fbdev/arcfb.c | 667 ++ drivers/video/fbdev/arkfb.c | 1231 +++ drivers/video/fbdev/asiliantfb.c | 624 ++ drivers/video/fbdev/atafb.c | 3266 ++++++ drivers/video/fbdev/atafb.h | 36 + drivers/video/fbdev/atafb_iplan2p2.c | 293 + drivers/video/fbdev/atafb_iplan2p4.c | 308 + drivers/video/fbdev/atafb_iplan2p8.c | 345 + drivers/video/fbdev/atafb_mfb.c | 112 + drivers/video/fbdev/atafb_utils.h | 400 + drivers/video/fbdev/atmel_lcdfb.c | 1453 +++ drivers/video/fbdev/aty/Makefile | 15 + drivers/video/fbdev/aty/ati_ids.h | 214 + drivers/video/fbdev/aty/aty128fb.c | 2591 +++++ drivers/video/fbdev/aty/atyfb.h | 369 + drivers/video/fbdev/aty/atyfb_base.c | 4029 +++++++ drivers/video/fbdev/aty/mach64_accel.c | 430 + drivers/video/fbdev/aty/mach64_ct.c | 649 ++ drivers/video/fbdev/aty/mach64_cursor.c | 225 + drivers/video/fbdev/aty/mach64_gx.c | 910 ++ drivers/video/fbdev/aty/radeon_accel.c | 328 + drivers/video/fbdev/aty/radeon_backlight.c | 221 + drivers/video/fbdev/aty/radeon_base.c | 2568 +++++ drivers/video/fbdev/aty/radeon_i2c.c | 167 + drivers/video/fbdev/aty/radeon_monitor.c | 1052 ++ drivers/video/fbdev/aty/radeon_pm.c | 2906 +++++ drivers/video/fbdev/aty/radeonfb.h | 634 ++ drivers/video/fbdev/au1100fb.c | 642 ++ drivers/video/fbdev/au1100fb.h | 377 + drivers/video/fbdev/au1200fb.c | 1859 ++++ drivers/video/fbdev/au1200fb.h | 572 + drivers/video/fbdev/auo_k1900fb.c | 205 + drivers/video/fbdev/auo_k1901fb.c | 258 + drivers/video/fbdev/auo_k190x.c | 1198 ++ drivers/video/fbdev/auo_k190x.h | 129 + drivers/video/fbdev/bf537-lq035.c | 915 ++ drivers/video/fbdev/bf54x-lq043fb.c | 767 ++ drivers/video/fbdev/bfin-lq035q1-fb.c | 864 ++ drivers/video/fbdev/bfin-t350mcqb-fb.c | 670 ++ drivers/video/fbdev/bfin_adv7393fb.c | 827 ++ drivers/video/fbdev/bfin_adv7393fb.h | 321 + drivers/video/fbdev/broadsheetfb.c | 1223 ++ drivers/video/fbdev/bt431.h | 235 + drivers/video/fbdev/bt455.h | 94 + drivers/video/fbdev/bw2.c | 406 + drivers/video/fbdev/c2p.h | 19 + drivers/video/fbdev/c2p_core.h | 153 + drivers/video/fbdev/c2p_iplan2.c | 153 + drivers/video/fbdev/c2p_planar.c | 156 + drivers/video/fbdev/carminefb.c | 788 ++ drivers/video/fbdev/carminefb.h | 64 + drivers/video/fbdev/carminefb_regs.h | 159 + drivers/video/fbdev/cfbcopyarea.c | 434 + drivers/video/fbdev/cfbfillrect.c | 371 + drivers/video/fbdev/cfbimgblt.c | 313 + drivers/video/fbdev/cg14.c | 626 ++ drivers/video/fbdev/cg3.c | 492 + drivers/video/fbdev/cg6.c | 885 ++ drivers/video/fbdev/chipsfb.c | 519 + drivers/video/fbdev/cirrusfb.c | 2952 +++++ drivers/video/fbdev/clps711xfb.c | 315 + drivers/video/fbdev/cobalt_lcdfb.c | 401 + drivers/video/fbdev/controlfb.c | 1084 ++ drivers/video/fbdev/controlfb.h | 145 + drivers/video/fbdev/cyber2000fb.c | 1901 ++++ drivers/video/fbdev/cyber2000fb.h | 497 + drivers/video/fbdev/da8xx-fb.c | 1659 +++ drivers/video/fbdev/dnfb.c | 303 + drivers/video/fbdev/edid.h | 138 + drivers/video/fbdev/efifb.c | 360 + drivers/video/fbdev/ep93xx-fb.c | 634 ++ drivers/video/fbdev/exynos/Kconfig | 32 + drivers/video/fbdev/exynos/Makefile | 7 + drivers/video/fbdev/exynos/exynos_mipi_dsi.c | 574 + .../video/fbdev/exynos/exynos_mipi_dsi_common.c | 880 ++ .../video/fbdev/exynos/exynos_mipi_dsi_common.h | 46 + .../video/fbdev/exynos/exynos_mipi_dsi_lowlevel.c | 618 ++ .../video/fbdev/exynos/exynos_mipi_dsi_lowlevel.h | 112 + drivers/video/fbdev/exynos/exynos_mipi_dsi_regs.h | 149 + drivers/video/fbdev/exynos/s6e8ax0.c | 898 ++ drivers/video/fbdev/fb-puv3.c | 838 ++ drivers/video/fbdev/fb_ddc.c | 119 + drivers/video/fbdev/fb_defio.c | 245 + drivers/video/fbdev/fb_draw.h | 186 + drivers/video/fbdev/fb_notify.c | 47 + drivers/video/fbdev/fb_sys_fops.c | 104 + drivers/video/fbdev/fbcmap.c | 362 + drivers/video/fbdev/fbcvt.c | 379 + drivers/video/fbdev/fbmem.c | 2002 ++++ drivers/video/fbdev/fbmon.c | 1592 +++ drivers/video/fbdev/fbsysfs.c | 586 + drivers/video/fbdev/ffb.c | 1081 ++ drivers/video/fbdev/fm2fb.c | 323 + drivers/video/fbdev/fsl-diu-fb.c | 1994 ++++ drivers/video/fbdev/g364fb.c | 255 + drivers/video/fbdev/gbefb.c | 1309 +++ drivers/video/fbdev/geode/Kconfig | 54 + drivers/video/fbdev/geode/Makefile | 9 + drivers/video/fbdev/geode/display_gx.c | 184 + drivers/video/fbdev/geode/display_gx1.c | 214 + drivers/video/fbdev/geode/display_gx1.h | 154 + drivers/video/fbdev/geode/geodefb.h | 38 + drivers/video/fbdev/geode/gx1fb_core.c | 476 + drivers/video/fbdev/geode/gxfb.h | 358 + drivers/video/fbdev/geode/gxfb_core.c | 547 + drivers/video/fbdev/geode/lxfb.h | 452 + drivers/video/fbdev/geode/lxfb_core.c | 683 ++ drivers/video/fbdev/geode/lxfb_ops.c | 845 ++ drivers/video/fbdev/geode/suspend_gx.c | 267 + drivers/video/fbdev/geode/video_cs5530.c | 193 + drivers/video/fbdev/geode/video_cs5530.h | 75 + drivers/video/fbdev/geode/video_gx.c | 349 + drivers/video/fbdev/goldfishfb.c | 318 + drivers/video/fbdev/grvga.c | 562 + drivers/video/fbdev/gxt4500.c | 783 ++ drivers/video/fbdev/hecubafb.c | 311 + drivers/video/fbdev/hgafb.c | 667 ++ drivers/video/fbdev/hitfb.c | 500 + drivers/video/fbdev/hpfb.c | 429 + drivers/video/fbdev/hyperv_fb.c | 907 ++ drivers/video/fbdev/i740_reg.h | 309 + drivers/video/fbdev/i740fb.c | 1333 +++ drivers/video/fbdev/i810/Makefile | 17 + drivers/video/fbdev/i810/i810-i2c.c | 175 + drivers/video/fbdev/i810/i810.h | 299 + drivers/video/fbdev/i810/i810_accel.c | 456 + drivers/video/fbdev/i810/i810_dvt.c | 312 + drivers/video/fbdev/i810/i810_gtf.c | 276 + drivers/video/fbdev/i810/i810_main.c | 2218 ++++ drivers/video/fbdev/i810/i810_main.h | 95 + drivers/video/fbdev/i810/i810_regs.h | 275 + drivers/video/fbdev/igafb.c | 579 + drivers/video/fbdev/imsttfb.c | 1626 +++ drivers/video/fbdev/imxfb.c | 1075 ++ drivers/video/fbdev/intelfb/Makefile | 7 + drivers/video/fbdev/intelfb/intelfb.h | 383 + drivers/video/fbdev/intelfb/intelfb_i2c.c | 209 + drivers/video/fbdev/intelfb/intelfbdrv.c | 1704 +++ drivers/video/fbdev/intelfb/intelfbhw.c | 2121 ++++ drivers/video/fbdev/intelfb/intelfbhw.h | 609 + drivers/video/fbdev/jz4740_fb.c | 806 ++ drivers/video/fbdev/kyro/Makefile | 8 + drivers/video/fbdev/kyro/STG4000InitDevice.c | 326 + drivers/video/fbdev/kyro/STG4000Interface.h | 61 + drivers/video/fbdev/kyro/STG4000OverlayDevice.c | 601 + drivers/video/fbdev/kyro/STG4000Ramdac.c | 163 + drivers/video/fbdev/kyro/STG4000Reg.h | 283 + drivers/video/fbdev/kyro/STG4000VTG.c | 170 + drivers/video/fbdev/kyro/fbdev.c | 808 ++ drivers/video/fbdev/leo.c | 691 ++ drivers/video/fbdev/macfb.c | 928 ++ drivers/video/fbdev/macmodes.c | 414 + drivers/video/fbdev/macmodes.h | 71 + drivers/video/fbdev/matrox/Makefile | 11 + drivers/video/fbdev/matrox/g450_pll.c | 539 + drivers/video/fbdev/matrox/g450_pll.h | 12 + drivers/video/fbdev/matrox/i2c-matroxfb.c | 238 + drivers/video/fbdev/matrox/matroxfb_DAC1064.c | 1107 ++ drivers/video/fbdev/matrox/matroxfb_DAC1064.h | 179 + drivers/video/fbdev/matrox/matroxfb_Ti3026.c | 745 ++ drivers/video/fbdev/matrox/matroxfb_Ti3026.h | 11 + drivers/video/fbdev/matrox/matroxfb_accel.c | 519 + drivers/video/fbdev/matrox/matroxfb_accel.h | 8 + drivers/video/fbdev/matrox/matroxfb_base.c | 2584 +++++ drivers/video/fbdev/matrox/matroxfb_base.h | 735 ++ drivers/video/fbdev/matrox/matroxfb_crtc2.c | 739 ++ drivers/video/fbdev/matrox/matroxfb_crtc2.h | 34 + drivers/video/fbdev/matrox/matroxfb_g450.c | 640 ++ drivers/video/fbdev/matrox/matroxfb_g450.h | 14 + drivers/video/fbdev/matrox/matroxfb_maven.c | 1301 +++ drivers/video/fbdev/matrox/matroxfb_maven.h | 20 + drivers/video/fbdev/matrox/matroxfb_misc.c | 815 ++ drivers/video/fbdev/matrox/matroxfb_misc.h | 21 + drivers/video/fbdev/maxinefb.c | 177 + drivers/video/fbdev/mb862xx/Makefile | 8 + drivers/video/fbdev/mb862xx/mb862xx-i2c.c | 179 + drivers/video/fbdev/mb862xx/mb862xx_reg.h | 188 + drivers/video/fbdev/mb862xx/mb862xxfb.h | 121 + drivers/video/fbdev/mb862xx/mb862xxfb_accel.c | 335 + drivers/video/fbdev/mb862xx/mb862xxfb_accel.h | 203 + drivers/video/fbdev/mb862xx/mb862xxfbdrv.c | 1206 ++ drivers/video/fbdev/mbx/Makefile | 4 + drivers/video/fbdev/mbx/mbxdebugfs.c | 251 + drivers/video/fbdev/mbx/mbxfb.c | 1053 ++ drivers/video/fbdev/mbx/reg_bits.h | 613 + drivers/video/fbdev/mbx/regs.h | 195 + drivers/video/fbdev/metronomefb.c | 780 ++ drivers/video/fbdev/mmp/Kconfig | 11 + drivers/video/fbdev/mmp/Makefile | 1 + drivers/video/fbdev/mmp/core.c | 251 + drivers/video/fbdev/mmp/fb/Kconfig | 13 + drivers/video/fbdev/mmp/fb/Makefile | 1 + drivers/video/fbdev/mmp/fb/mmpfb.c | 694 ++ drivers/video/fbdev/mmp/fb/mmpfb.h | 54 + drivers/video/fbdev/mmp/hw/Kconfig | 20 + drivers/video/fbdev/mmp/hw/Makefile | 2 + drivers/video/fbdev/mmp/hw/mmp_ctrl.c | 588 + drivers/video/fbdev/mmp/hw/mmp_ctrl.h | 1502 +++ drivers/video/fbdev/mmp/hw/mmp_spi.c | 180 + drivers/video/fbdev/mmp/panel/Kconfig | 6 + drivers/video/fbdev/mmp/panel/Makefile | 1 + drivers/video/fbdev/mmp/panel/tpo_tj032md01bw.c | 186 + drivers/video/fbdev/modedb.c | 1137 ++ drivers/video/fbdev/msm/Makefile | 19 + drivers/video/fbdev/msm/mddi.c | 821 ++ drivers/video/fbdev/msm/mddi_client_dummy.c | 98 + drivers/video/fbdev/msm/mddi_client_nt35399.c | 252 + drivers/video/fbdev/msm/mddi_client_toshiba.c | 280 + drivers/video/fbdev/msm/mddi_hw.h | 305 + drivers/video/fbdev/msm/mdp.c | 520 + drivers/video/fbdev/msm/mdp_csc_table.h | 582 + drivers/video/fbdev/msm/mdp_hw.h | 627 ++ drivers/video/fbdev/msm/mdp_ppp.c | 731 ++ drivers/video/fbdev/msm/mdp_scale_tables.c | 766 ++ drivers/video/fbdev/msm/mdp_scale_tables.h | 38 + drivers/video/fbdev/msm/msm_fb.c | 638 ++ drivers/video/fbdev/mx3fb.c | 1630 +++ drivers/video/fbdev/mxsfb.c | 960 ++ drivers/video/fbdev/n411.c | 202 + drivers/video/fbdev/neofb.c | 2247 ++++ drivers/video/fbdev/nuc900fb.c | 765 ++ drivers/video/fbdev/nuc900fb.h | 55 + drivers/video/fbdev/nvidia/Makefile | 13 + drivers/video/fbdev/nvidia/nv_accel.c | 416 + drivers/video/fbdev/nvidia/nv_backlight.c | 148 + drivers/video/fbdev/nvidia/nv_dma.h | 188 + drivers/video/fbdev/nvidia/nv_hw.c | 1687 +++ drivers/video/fbdev/nvidia/nv_i2c.c | 171 + drivers/video/fbdev/nvidia/nv_local.h | 114 + drivers/video/fbdev/nvidia/nv_of.c | 82 + drivers/video/fbdev/nvidia/nv_proto.h | 75 + drivers/video/fbdev/nvidia/nv_setup.c | 675 ++ drivers/video/fbdev/nvidia/nv_type.h | 180 + drivers/video/fbdev/nvidia/nvidia.c | 1607 +++ drivers/video/fbdev/ocfb.c | 440 + drivers/video/fbdev/offb.c | 687 ++ drivers/video/fbdev/omap/Kconfig | 52 + drivers/video/fbdev/omap/Makefile | 26 + drivers/video/fbdev/omap/hwa742.c | 1059 ++ drivers/video/fbdev/omap/lcd_ams_delta.c | 225 + drivers/video/fbdev/omap/lcd_h3.c | 127 + drivers/video/fbdev/omap/lcd_htcherald.c | 118 + drivers/video/fbdev/omap/lcd_inn1510.c | 113 + drivers/video/fbdev/omap/lcd_inn1610.c | 134 + drivers/video/fbdev/omap/lcd_mipid.c | 615 + drivers/video/fbdev/omap/lcd_osk.c | 133 + drivers/video/fbdev/omap/lcd_palmte.c | 110 + drivers/video/fbdev/omap/lcd_palmtt.c | 116 + drivers/video/fbdev/omap/lcd_palmz71.c | 112 + drivers/video/fbdev/omap/lcdc.c | 856 ++ drivers/video/fbdev/omap/lcdc.h | 9 + drivers/video/fbdev/omap/omapfb.h | 246 + drivers/video/fbdev/omap/omapfb_main.c | 1971 ++++ drivers/video/fbdev/omap/sossi.c | 693 ++ drivers/video/fbdev/omap2/Kconfig | 10 + drivers/video/fbdev/omap2/Makefile | 5 + drivers/video/fbdev/omap2/displays-new/Kconfig | 80 + drivers/video/fbdev/omap2/displays-new/Makefile | 13 + .../fbdev/omap2/displays-new/connector-analog-tv.c | 318 + .../video/fbdev/omap2/displays-new/connector-dvi.c | 401 + .../fbdev/omap2/displays-new/connector-hdmi.c | 405 + .../fbdev/omap2/displays-new/encoder-tfp410.c | 308 + .../fbdev/omap2/displays-new/encoder-tpd12s015.c | 451 + drivers/video/fbdev/omap2/displays-new/panel-dpi.c | 270 + .../video/fbdev/omap2/displays-new/panel-dsi-cm.c | 1388 +++ .../omap2/displays-new/panel-lgphilips-lb035q02.c | 358 + .../omap2/displays-new/panel-nec-nl8048hl11.c | 394 + .../omap2/displays-new/panel-sharp-ls037v7dw01.c | 324 + .../omap2/displays-new/panel-sony-acx565akm.c | 911 ++ .../omap2/displays-new/panel-tpo-td028ttec1.c | 480 + .../omap2/displays-new/panel-tpo-td043mtea1.c | 646 ++ drivers/video/fbdev/omap2/dss/Kconfig | 121 + drivers/video/fbdev/omap2/dss/Makefile | 15 + drivers/video/fbdev/omap2/dss/apply.c | 1700 +++ drivers/video/fbdev/omap2/dss/core.c | 360 + drivers/video/fbdev/omap2/dss/dispc-compat.c | 666 ++ drivers/video/fbdev/omap2/dss/dispc-compat.h | 30 + drivers/video/fbdev/omap2/dss/dispc.c | 3853 +++++++ drivers/video/fbdev/omap2/dss/dispc.h | 917 ++ drivers/video/fbdev/omap2/dss/dispc_coefs.c | 325 + drivers/video/fbdev/omap2/dss/display-sysfs.c | 345 + drivers/video/fbdev/omap2/dss/display.c | 338 + drivers/video/fbdev/omap2/dss/dpi.c | 774 ++ drivers/video/fbdev/omap2/dss/dsi.c | 5751 ++++++++++ drivers/video/fbdev/omap2/dss/dss-of.c | 159 + drivers/video/fbdev/omap2/dss/dss.c | 972 ++ drivers/video/fbdev/omap2/dss/dss.h | 438 + drivers/video/fbdev/omap2/dss/dss_features.c | 935 ++ drivers/video/fbdev/omap2/dss/dss_features.h | 117 + drivers/video/fbdev/omap2/dss/hdmi.h | 444 + drivers/video/fbdev/omap2/dss/hdmi4.c | 703 ++ drivers/video/fbdev/omap2/dss/hdmi4_core.c | 1036 ++ drivers/video/fbdev/omap2/dss/hdmi4_core.h | 276 + drivers/video/fbdev/omap2/dss/hdmi_common.c | 425 + drivers/video/fbdev/omap2/dss/hdmi_phy.c | 160 + drivers/video/fbdev/omap2/dss/hdmi_pll.c | 232 + drivers/video/fbdev/omap2/dss/hdmi_wp.c | 275 + drivers/video/fbdev/omap2/dss/manager-sysfs.c | 529 + drivers/video/fbdev/omap2/dss/manager.c | 263 + drivers/video/fbdev/omap2/dss/output.c | 254 + drivers/video/fbdev/omap2/dss/overlay-sysfs.c | 456 + drivers/video/fbdev/omap2/dss/overlay.c | 202 + drivers/video/fbdev/omap2/dss/rfbi.c | 1058 ++ drivers/video/fbdev/omap2/dss/sdi.c | 433 + drivers/video/fbdev/omap2/dss/venc.c | 980 ++ drivers/video/fbdev/omap2/dss/venc_panel.c | 232 + drivers/video/fbdev/omap2/omapfb/Kconfig | 27 + drivers/video/fbdev/omap2/omapfb/Makefile | 2 + drivers/video/fbdev/omap2/omapfb/omapfb-ioctl.c | 922 ++ drivers/video/fbdev/omap2/omapfb/omapfb-main.c | 2656 +++++ drivers/video/fbdev/omap2/omapfb/omapfb-sysfs.c | 605 + drivers/video/fbdev/omap2/omapfb/omapfb.h | 208 + drivers/video/fbdev/omap2/vrfb.c | 399 + drivers/video/fbdev/p9100.c | 382 + drivers/video/fbdev/platinumfb.c | 714 ++ drivers/video/fbdev/platinumfb.h | 368 + drivers/video/fbdev/pm2fb.c | 1858 ++++ drivers/video/fbdev/pm3fb.c | 1586 +++ drivers/video/fbdev/pmag-aa-fb.c | 510 + drivers/video/fbdev/pmag-ba-fb.c | 295 + drivers/video/fbdev/pmagb-b-fb.c | 413 + drivers/video/fbdev/ps3fb.c | 1307 +++ drivers/video/fbdev/pvr2fb.c | 1142 ++ drivers/video/fbdev/pxa168fb.c | 837 ++ drivers/video/fbdev/pxa168fb.h | 558 + drivers/video/fbdev/pxa3xx-gcu.c | 724 ++ drivers/video/fbdev/pxa3xx-gcu.h | 38 + drivers/video/fbdev/pxafb.c | 2332 ++++ drivers/video/fbdev/pxafb.h | 200 + drivers/video/fbdev/q40fb.c | 155 + drivers/video/fbdev/riva/Makefile | 11 + drivers/video/fbdev/riva/fbdev.c | 2230 ++++ drivers/video/fbdev/riva/nv_driver.c | 422 + drivers/video/fbdev/riva/nv_type.h | 58 + drivers/video/fbdev/riva/nvreg.h | 188 + drivers/video/fbdev/riva/riva_hw.c | 2268 ++++ drivers/video/fbdev/riva/riva_hw.h | 563 + drivers/video/fbdev/riva/riva_tbl.h | 1008 ++ drivers/video/fbdev/riva/rivafb-i2c.c | 166 + drivers/video/fbdev/riva/rivafb.h | 77 + drivers/video/fbdev/s1d13xxxfb.c | 1040 ++ drivers/video/fbdev/s3c-fb.c | 2049 ++++ drivers/video/fbdev/s3c2410fb.c | 1146 ++ drivers/video/fbdev/s3c2410fb.h | 48 + drivers/video/fbdev/s3fb.c | 1597 +++ drivers/video/fbdev/sa1100fb.c | 1340 +++ drivers/video/fbdev/sa1100fb.h | 96 + drivers/video/fbdev/savage/Makefile | 9 + drivers/video/fbdev/savage/savagefb-i2c.c | 241 + drivers/video/fbdev/savage/savagefb.h | 415 + drivers/video/fbdev/savage/savagefb_accel.c | 137 + drivers/video/fbdev/savage/savagefb_driver.c | 2571 +++++ drivers/video/fbdev/sbuslib.c | 267 + drivers/video/fbdev/sbuslib.h | 27 + drivers/video/fbdev/sh7760fb.c | 591 + drivers/video/fbdev/sh_mipi_dsi.c | 587 + drivers/video/fbdev/sh_mobile_hdmi.c | 1449 +++ drivers/video/fbdev/sh_mobile_lcdcfb.c | 2863 +++++ drivers/video/fbdev/sh_mobile_lcdcfb.h | 112 + drivers/video/fbdev/sh_mobile_meram.c | 759 ++ drivers/video/fbdev/simplefb.c | 280 + drivers/video/fbdev/sis/300vtbl.h | 1072 ++ drivers/video/fbdev/sis/310vtbl.h | 1339 +++ drivers/video/fbdev/sis/Makefile | 7 + drivers/video/fbdev/sis/init.c | 3655 ++++++ drivers/video/fbdev/sis/init.h | 1541 +++ drivers/video/fbdev/sis/init301.c | 11071 +++++++++++++++++++ drivers/video/fbdev/sis/init301.h | 456 + drivers/video/fbdev/sis/initdef.h | 708 ++ drivers/video/fbdev/sis/initextlfb.c | 231 + drivers/video/fbdev/sis/oem300.h | 840 ++ drivers/video/fbdev/sis/oem310.h | 430 + drivers/video/fbdev/sis/sis.h | 586 + drivers/video/fbdev/sis/sis_accel.c | 423 + drivers/video/fbdev/sis/sis_accel.h | 400 + drivers/video/fbdev/sis/sis_main.c | 6844 ++++++++++++ drivers/video/fbdev/sis/sis_main.h | 781 ++ drivers/video/fbdev/sis/vgatypes.h | 97 + drivers/video/fbdev/sis/vstruct.h | 551 + drivers/video/fbdev/skeletonfb.c | 1037 ++ drivers/video/fbdev/sm501fb.c | 2240 ++++ drivers/video/fbdev/smscufx.c | 1980 ++++ drivers/video/fbdev/ssd1307fb.c | 581 + drivers/video/fbdev/sstfb.c | 1532 +++ drivers/video/fbdev/sticore.h | 401 + drivers/video/fbdev/stifb.c | 1417 +++ drivers/video/fbdev/sunxvr1000.c | 229 + drivers/video/fbdev/sunxvr2500.c | 276 + drivers/video/fbdev/sunxvr500.c | 462 + drivers/video/fbdev/svgalib.c | 672 ++ drivers/video/fbdev/syscopyarea.c | 377 + drivers/video/fbdev/sysfillrect.c | 335 + drivers/video/fbdev/sysimgblt.c | 288 + drivers/video/fbdev/tcx.c | 541 + drivers/video/fbdev/tdfxfb.c | 1686 +++ drivers/video/fbdev/tgafb.c | 1611 +++ drivers/video/fbdev/tmiofb.c | 1048 ++ drivers/video/fbdev/tridentfb.c | 1659 +++ drivers/video/fbdev/udlfb.c | 1985 ++++ drivers/video/fbdev/uvesafb.c | 2028 ++++ drivers/video/fbdev/valkyriefb.c | 589 + drivers/video/fbdev/valkyriefb.h | 200 + drivers/video/fbdev/vermilion/Makefile | 5 + drivers/video/fbdev/vermilion/cr_pll.c | 208 + drivers/video/fbdev/vermilion/vermilion.c | 1175 ++ drivers/video/fbdev/vermilion/vermilion.h | 259 + drivers/video/fbdev/vesafb.c | 522 + drivers/video/fbdev/vfb.c | 610 + drivers/video/fbdev/vga16fb.c | 1464 +++ drivers/video/fbdev/via/Makefile | 12 + drivers/video/fbdev/via/accel.c | 547 + drivers/video/fbdev/via/accel.h | 211 + drivers/video/fbdev/via/chip.h | 176 + drivers/video/fbdev/via/debug.h | 41 + drivers/video/fbdev/via/dvi.c | 478 + drivers/video/fbdev/via/dvi.h | 65 + drivers/video/fbdev/via/global.c | 50 + drivers/video/fbdev/via/global.h | 80 + drivers/video/fbdev/via/hw.c | 2134 ++++ drivers/video/fbdev/via/hw.h | 676 ++ drivers/video/fbdev/via/ioctl.c | 116 + drivers/video/fbdev/via/ioctl.h | 203 + drivers/video/fbdev/via/lcd.c | 1005 ++ drivers/video/fbdev/via/lcd.h | 89 + drivers/video/fbdev/via/share.h | 332 + drivers/video/fbdev/via/tblDPASetting.c | 86 + drivers/video/fbdev/via/tblDPASetting.h | 45 + drivers/video/fbdev/via/via-core.c | 790 ++ drivers/video/fbdev/via/via-gpio.c | 316 + drivers/video/fbdev/via/via_aux.c | 88 + drivers/video/fbdev/via/via_aux.h | 93 + drivers/video/fbdev/via/via_aux_ch7301.c | 50 + drivers/video/fbdev/via/via_aux_edid.c | 100 + drivers/video/fbdev/via/via_aux_sii164.c | 54 + drivers/video/fbdev/via/via_aux_vt1621.c | 44 + drivers/video/fbdev/via/via_aux_vt1622.c | 50 + drivers/video/fbdev/via/via_aux_vt1625.c | 50 + drivers/video/fbdev/via/via_aux_vt1631.c | 46 + drivers/video/fbdev/via/via_aux_vt1632.c | 54 + drivers/video/fbdev/via/via_aux_vt1636.c | 46 + drivers/video/fbdev/via/via_clock.c | 368 + drivers/video/fbdev/via/via_clock.h | 76 + drivers/video/fbdev/via/via_i2c.c | 295 + drivers/video/fbdev/via/via_modesetting.c | 230 + drivers/video/fbdev/via/via_modesetting.h | 61 + drivers/video/fbdev/via/via_utility.c | 242 + drivers/video/fbdev/via/via_utility.h | 34 + drivers/video/fbdev/via/viafbdev.c | 2176 ++++ drivers/video/fbdev/via/viafbdev.h | 110 + drivers/video/fbdev/via/viamode.c | 383 + drivers/video/fbdev/via/viamode.h | 63 + drivers/video/fbdev/via/vt1636.c | 244 + drivers/video/fbdev/via/vt1636.h | 44 + drivers/video/fbdev/vt8500lcdfb.c | 502 + drivers/video/fbdev/vt8500lcdfb.h | 34 + drivers/video/fbdev/vt8623fb.c | 958 ++ drivers/video/fbdev/w100fb.c | 1637 +++ drivers/video/fbdev/w100fb.h | 928 ++ drivers/video/fbdev/wm8505fb.c | 421 + drivers/video/fbdev/wm8505fb_regs.h | 76 + drivers/video/fbdev/wmt_ge_rops.c | 182 + drivers/video/fbdev/wmt_ge_rops.h | 28 + drivers/video/fbdev/xen-fbfront.c | 719 ++ drivers/video/fbdev/xilinxfb.c | 509 + drivers/video/fbmem.c | 2002 ---- drivers/video/fbmon.c | 1592 --- drivers/video/fbsysfs.c | 586 - drivers/video/ffb.c | 1081 -- drivers/video/fm2fb.c | 323 - drivers/video/fsl-diu-fb.c | 1994 ---- drivers/video/g364fb.c | 255 - drivers/video/gbefb.c | 1309 --- drivers/video/geode/Kconfig | 54 - drivers/video/geode/Makefile | 9 - drivers/video/geode/display_gx.c | 184 - drivers/video/geode/display_gx1.c | 214 - drivers/video/geode/display_gx1.h | 154 - drivers/video/geode/geodefb.h | 38 - drivers/video/geode/gx1fb_core.c | 476 - drivers/video/geode/gxfb.h | 358 - drivers/video/geode/gxfb_core.c | 547 - drivers/video/geode/lxfb.h | 452 - drivers/video/geode/lxfb_core.c | 683 -- drivers/video/geode/lxfb_ops.c | 845 -- drivers/video/geode/suspend_gx.c | 267 - drivers/video/geode/video_cs5530.c | 193 - drivers/video/geode/video_cs5530.h | 75 - drivers/video/geode/video_gx.c | 349 - drivers/video/goldfishfb.c | 318 - drivers/video/grvga.c | 562 - drivers/video/gxt4500.c | 783 -- drivers/video/hecubafb.c | 311 - drivers/video/hgafb.c | 667 -- drivers/video/hitfb.c | 500 - drivers/video/hpfb.c | 429 - drivers/video/hyperv_fb.c | 907 -- drivers/video/i740_reg.h | 309 - drivers/video/i740fb.c | 1333 --- drivers/video/i810/Makefile | 17 - drivers/video/i810/i810-i2c.c | 175 - drivers/video/i810/i810.h | 299 - drivers/video/i810/i810_accel.c | 456 - drivers/video/i810/i810_dvt.c | 312 - drivers/video/i810/i810_gtf.c | 276 - drivers/video/i810/i810_main.c | 2218 ---- drivers/video/i810/i810_main.h | 95 - drivers/video/i810/i810_regs.h | 275 - drivers/video/igafb.c | 579 - drivers/video/imsttfb.c | 1626 --- drivers/video/imxfb.c | 1075 -- drivers/video/intelfb/Makefile | 7 - drivers/video/intelfb/intelfb.h | 383 - drivers/video/intelfb/intelfb_i2c.c | 209 - drivers/video/intelfb/intelfbdrv.c | 1704 --- drivers/video/intelfb/intelfbhw.c | 2121 ---- drivers/video/intelfb/intelfbhw.h | 609 - drivers/video/jz4740_fb.c | 806 -- drivers/video/kyro/Makefile | 8 - drivers/video/kyro/STG4000InitDevice.c | 326 - drivers/video/kyro/STG4000Interface.h | 61 - drivers/video/kyro/STG4000OverlayDevice.c | 601 - drivers/video/kyro/STG4000Ramdac.c | 163 - drivers/video/kyro/STG4000Reg.h | 283 - drivers/video/kyro/STG4000VTG.c | 170 - drivers/video/kyro/fbdev.c | 808 -- drivers/video/leo.c | 691 -- drivers/video/macfb.c | 928 -- drivers/video/macmodes.c | 414 - drivers/video/macmodes.h | 71 - drivers/video/matrox/Makefile | 11 - drivers/video/matrox/g450_pll.c | 539 - drivers/video/matrox/g450_pll.h | 12 - drivers/video/matrox/i2c-matroxfb.c | 238 - drivers/video/matrox/matroxfb_DAC1064.c | 1107 -- drivers/video/matrox/matroxfb_DAC1064.h | 179 - drivers/video/matrox/matroxfb_Ti3026.c | 745 -- drivers/video/matrox/matroxfb_Ti3026.h | 11 - drivers/video/matrox/matroxfb_accel.c | 519 - drivers/video/matrox/matroxfb_accel.h | 8 - drivers/video/matrox/matroxfb_base.c | 2584 ----- drivers/video/matrox/matroxfb_base.h | 735 -- drivers/video/matrox/matroxfb_crtc2.c | 739 -- drivers/video/matrox/matroxfb_crtc2.h | 34 - drivers/video/matrox/matroxfb_g450.c | 640 -- drivers/video/matrox/matroxfb_g450.h | 14 - drivers/video/matrox/matroxfb_maven.c | 1301 --- drivers/video/matrox/matroxfb_maven.h | 20 - drivers/video/matrox/matroxfb_misc.c | 815 -- drivers/video/matrox/matroxfb_misc.h | 21 - drivers/video/maxinefb.c | 177 - drivers/video/mb862xx/Makefile | 8 - drivers/video/mb862xx/mb862xx-i2c.c | 179 - drivers/video/mb862xx/mb862xx_reg.h | 188 - drivers/video/mb862xx/mb862xxfb.h | 121 - drivers/video/mb862xx/mb862xxfb_accel.c | 335 - drivers/video/mb862xx/mb862xxfb_accel.h | 203 - drivers/video/mb862xx/mb862xxfbdrv.c | 1206 -- drivers/video/mbx/Makefile | 4 - drivers/video/mbx/mbxdebugfs.c | 251 - drivers/video/mbx/mbxfb.c | 1053 -- drivers/video/mbx/reg_bits.h | 613 - drivers/video/mbx/regs.h | 195 - drivers/video/metronomefb.c | 780 -- drivers/video/mmp/Kconfig | 11 - drivers/video/mmp/Makefile | 1 - drivers/video/mmp/core.c | 251 - drivers/video/mmp/fb/Kconfig | 13 - drivers/video/mmp/fb/Makefile | 1 - drivers/video/mmp/fb/mmpfb.c | 694 -- drivers/video/mmp/fb/mmpfb.h | 54 - drivers/video/mmp/hw/Kconfig | 20 - drivers/video/mmp/hw/Makefile | 2 - drivers/video/mmp/hw/mmp_ctrl.c | 588 - drivers/video/mmp/hw/mmp_ctrl.h | 1502 --- drivers/video/mmp/hw/mmp_spi.c | 180 - drivers/video/mmp/panel/Kconfig | 6 - drivers/video/mmp/panel/Makefile | 1 - drivers/video/mmp/panel/tpo_tj032md01bw.c | 186 - drivers/video/modedb.c | 1137 -- drivers/video/msm/Makefile | 19 - drivers/video/msm/mddi.c | 821 -- drivers/video/msm/mddi_client_dummy.c | 98 - drivers/video/msm/mddi_client_nt35399.c | 252 - drivers/video/msm/mddi_client_toshiba.c | 280 - drivers/video/msm/mddi_hw.h | 305 - drivers/video/msm/mdp.c | 520 - drivers/video/msm/mdp_csc_table.h | 582 - drivers/video/msm/mdp_hw.h | 627 -- drivers/video/msm/mdp_ppp.c | 731 -- drivers/video/msm/mdp_scale_tables.c | 766 -- drivers/video/msm/mdp_scale_tables.h | 38 - drivers/video/msm/msm_fb.c | 638 -- drivers/video/mx3fb.c | 1630 --- drivers/video/mxsfb.c | 960 -- drivers/video/n411.c | 202 - drivers/video/neofb.c | 2247 ---- drivers/video/nuc900fb.c | 765 -- drivers/video/nuc900fb.h | 55 - drivers/video/nvidia/Makefile | 13 - drivers/video/nvidia/nv_accel.c | 416 - drivers/video/nvidia/nv_backlight.c | 148 - drivers/video/nvidia/nv_dma.h | 188 - drivers/video/nvidia/nv_hw.c | 1687 --- drivers/video/nvidia/nv_i2c.c | 171 - drivers/video/nvidia/nv_local.h | 114 - drivers/video/nvidia/nv_of.c | 82 - drivers/video/nvidia/nv_proto.h | 75 - drivers/video/nvidia/nv_setup.c | 675 -- drivers/video/nvidia/nv_type.h | 180 - drivers/video/nvidia/nvidia.c | 1607 --- drivers/video/ocfb.c | 440 - drivers/video/offb.c | 687 -- drivers/video/omap/Kconfig | 52 - drivers/video/omap/Makefile | 26 - drivers/video/omap/hwa742.c | 1059 -- drivers/video/omap/lcd_ams_delta.c | 225 - drivers/video/omap/lcd_h3.c | 127 - drivers/video/omap/lcd_htcherald.c | 118 - drivers/video/omap/lcd_inn1510.c | 113 - drivers/video/omap/lcd_inn1610.c | 134 - drivers/video/omap/lcd_mipid.c | 615 - drivers/video/omap/lcd_osk.c | 133 - drivers/video/omap/lcd_palmte.c | 110 - drivers/video/omap/lcd_palmtt.c | 116 - drivers/video/omap/lcd_palmz71.c | 112 - drivers/video/omap/lcdc.c | 856 -- drivers/video/omap/lcdc.h | 9 - drivers/video/omap/omapfb.h | 246 - drivers/video/omap/omapfb_main.c | 1971 ---- drivers/video/omap/sossi.c | 693 -- drivers/video/omap2/Kconfig | 10 - drivers/video/omap2/Makefile | 5 - drivers/video/omap2/displays-new/Kconfig | 80 - drivers/video/omap2/displays-new/Makefile | 13 - .../video/omap2/displays-new/connector-analog-tv.c | 318 - drivers/video/omap2/displays-new/connector-dvi.c | 401 - drivers/video/omap2/displays-new/connector-hdmi.c | 405 - drivers/video/omap2/displays-new/encoder-tfp410.c | 308 - .../video/omap2/displays-new/encoder-tpd12s015.c | 451 - drivers/video/omap2/displays-new/panel-dpi.c | 270 - drivers/video/omap2/displays-new/panel-dsi-cm.c | 1388 --- .../omap2/displays-new/panel-lgphilips-lb035q02.c | 358 - .../omap2/displays-new/panel-nec-nl8048hl11.c | 394 - .../omap2/displays-new/panel-sharp-ls037v7dw01.c | 324 - .../omap2/displays-new/panel-sony-acx565akm.c | 911 -- .../omap2/displays-new/panel-tpo-td028ttec1.c | 480 - .../omap2/displays-new/panel-tpo-td043mtea1.c | 646 -- drivers/video/omap2/dss/Kconfig | 121 - drivers/video/omap2/dss/Makefile | 15 - drivers/video/omap2/dss/apply.c | 1700 --- drivers/video/omap2/dss/core.c | 360 - drivers/video/omap2/dss/dispc-compat.c | 666 -- drivers/video/omap2/dss/dispc-compat.h | 30 - drivers/video/omap2/dss/dispc.c | 3853 ------- drivers/video/omap2/dss/dispc.h | 917 -- drivers/video/omap2/dss/dispc_coefs.c | 325 - drivers/video/omap2/dss/display-sysfs.c | 345 - drivers/video/omap2/dss/display.c | 338 - drivers/video/omap2/dss/dpi.c | 774 -- drivers/video/omap2/dss/dsi.c | 5751 ---------- drivers/video/omap2/dss/dss-of.c | 159 - drivers/video/omap2/dss/dss.c | 972 -- drivers/video/omap2/dss/dss.h | 438 - drivers/video/omap2/dss/dss_features.c | 935 -- drivers/video/omap2/dss/dss_features.h | 117 - drivers/video/omap2/dss/hdmi.h | 444 - drivers/video/omap2/dss/hdmi4.c | 703 -- drivers/video/omap2/dss/hdmi4_core.c | 1036 -- drivers/video/omap2/dss/hdmi4_core.h | 276 - drivers/video/omap2/dss/hdmi_common.c | 425 - drivers/video/omap2/dss/hdmi_phy.c | 160 - drivers/video/omap2/dss/hdmi_pll.c | 232 - drivers/video/omap2/dss/hdmi_wp.c | 275 - drivers/video/omap2/dss/manager-sysfs.c | 529 - drivers/video/omap2/dss/manager.c | 263 - drivers/video/omap2/dss/output.c | 254 - drivers/video/omap2/dss/overlay-sysfs.c | 456 - drivers/video/omap2/dss/overlay.c | 202 - drivers/video/omap2/dss/rfbi.c | 1058 -- drivers/video/omap2/dss/sdi.c | 433 - drivers/video/omap2/dss/venc.c | 980 -- drivers/video/omap2/dss/venc_panel.c | 232 - drivers/video/omap2/omapfb/Kconfig | 27 - drivers/video/omap2/omapfb/Makefile | 2 - drivers/video/omap2/omapfb/omapfb-ioctl.c | 922 -- drivers/video/omap2/omapfb/omapfb-main.c | 2656 ----- drivers/video/omap2/omapfb/omapfb-sysfs.c | 605 - drivers/video/omap2/omapfb/omapfb.h | 208 - drivers/video/omap2/vrfb.c | 399 - drivers/video/p9100.c | 382 - drivers/video/platinumfb.c | 714 -- drivers/video/platinumfb.h | 368 - drivers/video/pm2fb.c | 1858 ---- drivers/video/pm3fb.c | 1586 --- drivers/video/pmag-aa-fb.c | 510 - drivers/video/pmag-ba-fb.c | 295 - drivers/video/pmagb-b-fb.c | 413 - drivers/video/ps3fb.c | 1307 --- drivers/video/pvr2fb.c | 1142 -- drivers/video/pxa168fb.c | 837 -- drivers/video/pxa168fb.h | 558 - drivers/video/pxa3xx-gcu.c | 724 -- drivers/video/pxa3xx-gcu.h | 38 - drivers/video/pxafb.c | 2332 ---- drivers/video/pxafb.h | 200 - drivers/video/q40fb.c | 155 - drivers/video/riva/Makefile | 11 - drivers/video/riva/fbdev.c | 2230 ---- drivers/video/riva/nv_driver.c | 422 - drivers/video/riva/nv_type.h | 58 - drivers/video/riva/nvreg.h | 188 - drivers/video/riva/riva_hw.c | 2268 ---- drivers/video/riva/riva_hw.h | 563 - drivers/video/riva/riva_tbl.h | 1008 -- drivers/video/riva/rivafb-i2c.c | 166 - drivers/video/riva/rivafb.h | 77 - drivers/video/s1d13xxxfb.c | 1040 -- drivers/video/s3c-fb.c | 2049 ---- drivers/video/s3c2410fb.c | 1146 -- drivers/video/s3c2410fb.h | 48 - drivers/video/s3fb.c | 1597 --- drivers/video/sa1100fb.c | 1340 --- drivers/video/sa1100fb.h | 96 - drivers/video/savage/Makefile | 9 - drivers/video/savage/savagefb-i2c.c | 241 - drivers/video/savage/savagefb.h | 415 - drivers/video/savage/savagefb_accel.c | 137 - drivers/video/savage/savagefb_driver.c | 2571 ----- drivers/video/sbuslib.c | 267 - drivers/video/sbuslib.h | 27 - drivers/video/sh7760fb.c | 591 - drivers/video/sh_mipi_dsi.c | 587 - drivers/video/sh_mobile_hdmi.c | 1449 --- drivers/video/sh_mobile_lcdcfb.c | 2863 ----- drivers/video/sh_mobile_lcdcfb.h | 112 - drivers/video/sh_mobile_meram.c | 759 -- drivers/video/simplefb.c | 280 - drivers/video/sis/300vtbl.h | 1072 -- drivers/video/sis/310vtbl.h | 1339 --- drivers/video/sis/Makefile | 7 - drivers/video/sis/init.c | 3655 ------ drivers/video/sis/init.h | 1541 --- drivers/video/sis/init301.c | 11071 ------------------- drivers/video/sis/init301.h | 456 - drivers/video/sis/initdef.h | 708 -- drivers/video/sis/initextlfb.c | 231 - drivers/video/sis/oem300.h | 840 -- drivers/video/sis/oem310.h | 430 - drivers/video/sis/sis.h | 586 - drivers/video/sis/sis_accel.c | 423 - drivers/video/sis/sis_accel.h | 400 - drivers/video/sis/sis_main.c | 6844 ------------ drivers/video/sis/sis_main.h | 781 -- drivers/video/sis/vgatypes.h | 97 - drivers/video/sis/vstruct.h | 551 - drivers/video/skeletonfb.c | 1037 -- drivers/video/sm501fb.c | 2240 ---- drivers/video/smscufx.c | 1980 ---- drivers/video/ssd1307fb.c | 581 - drivers/video/sstfb.c | 1532 --- drivers/video/sticore.h | 401 - drivers/video/stifb.c | 1417 --- drivers/video/sunxvr1000.c | 229 - drivers/video/sunxvr2500.c | 276 - drivers/video/sunxvr500.c | 462 - drivers/video/svgalib.c | 672 -- drivers/video/syscopyarea.c | 377 - drivers/video/sysfillrect.c | 335 - drivers/video/sysimgblt.c | 288 - drivers/video/tcx.c | 541 - drivers/video/tdfxfb.c | 1686 --- drivers/video/tgafb.c | 1611 --- drivers/video/tmiofb.c | 1048 -- drivers/video/tridentfb.c | 1659 --- drivers/video/udlfb.c | 1985 ---- drivers/video/uvesafb.c | 2028 ---- drivers/video/valkyriefb.c | 589 - drivers/video/valkyriefb.h | 200 - drivers/video/vermilion/Makefile | 5 - drivers/video/vermilion/cr_pll.c | 208 - drivers/video/vermilion/vermilion.c | 1175 -- drivers/video/vermilion/vermilion.h | 259 - drivers/video/vesafb.c | 522 - drivers/video/vfb.c | 610 - drivers/video/vga16fb.c | 1464 --- drivers/video/via/Makefile | 12 - drivers/video/via/accel.c | 547 - drivers/video/via/accel.h | 211 - drivers/video/via/chip.h | 176 - drivers/video/via/debug.h | 41 - drivers/video/via/dvi.c | 478 - drivers/video/via/dvi.h | 65 - drivers/video/via/global.c | 50 - drivers/video/via/global.h | 80 - drivers/video/via/hw.c | 2134 ---- drivers/video/via/hw.h | 676 -- drivers/video/via/ioctl.c | 116 - drivers/video/via/ioctl.h | 203 - drivers/video/via/lcd.c | 1005 -- drivers/video/via/lcd.h | 89 - drivers/video/via/share.h | 332 - drivers/video/via/tblDPASetting.c | 86 - drivers/video/via/tblDPASetting.h | 45 - drivers/video/via/via-core.c | 790 -- drivers/video/via/via-gpio.c | 316 - drivers/video/via/via_aux.c | 88 - drivers/video/via/via_aux.h | 93 - drivers/video/via/via_aux_ch7301.c | 50 - drivers/video/via/via_aux_edid.c | 100 - drivers/video/via/via_aux_sii164.c | 54 - drivers/video/via/via_aux_vt1621.c | 44 - drivers/video/via/via_aux_vt1622.c | 50 - drivers/video/via/via_aux_vt1625.c | 50 - drivers/video/via/via_aux_vt1631.c | 46 - drivers/video/via/via_aux_vt1632.c | 54 - drivers/video/via/via_aux_vt1636.c | 46 - drivers/video/via/via_clock.c | 368 - drivers/video/via/via_clock.h | 76 - drivers/video/via/via_i2c.c | 295 - drivers/video/via/via_modesetting.c | 230 - drivers/video/via/via_modesetting.h | 61 - drivers/video/via/via_utility.c | 242 - drivers/video/via/via_utility.h | 34 - drivers/video/via/viafbdev.c | 2176 ---- drivers/video/via/viafbdev.h | 110 - drivers/video/via/viamode.c | 383 - drivers/video/via/viamode.h | 63 - drivers/video/via/vt1636.c | 244 - drivers/video/via/vt1636.h | 44 - drivers/video/vt8500lcdfb.c | 502 - drivers/video/vt8500lcdfb.h | 34 - drivers/video/vt8623fb.c | 958 -- drivers/video/w100fb.c | 1637 --- drivers/video/w100fb.h | 928 -- drivers/video/wm8505fb.c | 421 - drivers/video/wm8505fb_regs.h | 76 - drivers/video/wmt_ge_rops.c | 182 - drivers/video/wmt_ge_rops.h | 28 - drivers/video/xen-fbfront.c | 719 -- drivers/video/xilinxfb.c | 509 - 949 files changed, 302820 insertions(+), 302810 deletions(-) delete mode 100644 drivers/video/68328fb.c delete mode 100644 drivers/video/acornfb.c delete mode 100644 drivers/video/acornfb.h delete mode 100644 drivers/video/amba-clcd.c delete mode 100644 drivers/video/amifb.c delete mode 100644 drivers/video/arcfb.c delete mode 100644 drivers/video/arkfb.c delete mode 100644 drivers/video/asiliantfb.c delete mode 100644 drivers/video/atafb.c delete mode 100644 drivers/video/atafb.h delete mode 100644 drivers/video/atafb_iplan2p2.c delete mode 100644 drivers/video/atafb_iplan2p4.c delete mode 100644 drivers/video/atafb_iplan2p8.c delete mode 100644 drivers/video/atafb_mfb.c delete mode 100644 drivers/video/atafb_utils.h delete mode 100644 drivers/video/atmel_lcdfb.c delete mode 100644 drivers/video/aty/Makefile delete mode 100644 drivers/video/aty/ati_ids.h delete mode 100644 drivers/video/aty/aty128fb.c delete mode 100644 drivers/video/aty/atyfb.h delete mode 100644 drivers/video/aty/atyfb_base.c delete mode 100644 drivers/video/aty/mach64_accel.c delete mode 100644 drivers/video/aty/mach64_ct.c delete mode 100644 drivers/video/aty/mach64_cursor.c delete mode 100644 drivers/video/aty/mach64_gx.c delete mode 100644 drivers/video/aty/radeon_accel.c delete mode 100644 drivers/video/aty/radeon_backlight.c delete mode 100644 drivers/video/aty/radeon_base.c delete mode 100644 drivers/video/aty/radeon_i2c.c delete mode 100644 drivers/video/aty/radeon_monitor.c delete mode 100644 drivers/video/aty/radeon_pm.c delete mode 100644 drivers/video/aty/radeonfb.h delete mode 100644 drivers/video/au1100fb.c delete mode 100644 drivers/video/au1100fb.h delete mode 100644 drivers/video/au1200fb.c delete mode 100644 drivers/video/au1200fb.h delete mode 100644 drivers/video/auo_k1900fb.c delete mode 100644 drivers/video/auo_k1901fb.c delete mode 100644 drivers/video/auo_k190x.c delete mode 100644 drivers/video/auo_k190x.h delete mode 100644 drivers/video/bf537-lq035.c delete mode 100644 drivers/video/bf54x-lq043fb.c delete mode 100644 drivers/video/bfin-lq035q1-fb.c delete mode 100644 drivers/video/bfin-t350mcqb-fb.c delete mode 100644 drivers/video/bfin_adv7393fb.c delete mode 100644 drivers/video/bfin_adv7393fb.h delete mode 100644 drivers/video/broadsheetfb.c delete mode 100644 drivers/video/bt431.h delete mode 100644 drivers/video/bt455.h delete mode 100644 drivers/video/bw2.c delete mode 100644 drivers/video/c2p.h delete mode 100644 drivers/video/c2p_core.h delete mode 100644 drivers/video/c2p_iplan2.c delete mode 100644 drivers/video/c2p_planar.c delete mode 100644 drivers/video/carminefb.c delete mode 100644 drivers/video/carminefb.h delete mode 100644 drivers/video/carminefb_regs.h delete mode 100644 drivers/video/cfbcopyarea.c delete mode 100644 drivers/video/cfbfillrect.c delete mode 100644 drivers/video/cfbimgblt.c delete mode 100644 drivers/video/cg14.c delete mode 100644 drivers/video/cg3.c delete mode 100644 drivers/video/cg6.c delete mode 100644 drivers/video/chipsfb.c delete mode 100644 drivers/video/cirrusfb.c delete mode 100644 drivers/video/clps711xfb.c delete mode 100644 drivers/video/cobalt_lcdfb.c delete mode 100644 drivers/video/controlfb.c delete mode 100644 drivers/video/controlfb.h delete mode 100644 drivers/video/cyber2000fb.c delete mode 100644 drivers/video/cyber2000fb.h delete mode 100644 drivers/video/da8xx-fb.c delete mode 100644 drivers/video/dnfb.c delete mode 100644 drivers/video/edid.h delete mode 100644 drivers/video/efifb.c delete mode 100644 drivers/video/ep93xx-fb.c delete mode 100644 drivers/video/exynos/Kconfig delete mode 100644 drivers/video/exynos/Makefile delete mode 100644 drivers/video/exynos/exynos_mipi_dsi.c delete mode 100644 drivers/video/exynos/exynos_mipi_dsi_common.c delete mode 100644 drivers/video/exynos/exynos_mipi_dsi_common.h delete mode 100644 drivers/video/exynos/exynos_mipi_dsi_lowlevel.c delete mode 100644 drivers/video/exynos/exynos_mipi_dsi_lowlevel.h delete mode 100644 drivers/video/exynos/exynos_mipi_dsi_regs.h delete mode 100644 drivers/video/exynos/s6e8ax0.c delete mode 100644 drivers/video/fb-puv3.c delete mode 100644 drivers/video/fb_ddc.c delete mode 100644 drivers/video/fb_defio.c delete mode 100644 drivers/video/fb_draw.h delete mode 100644 drivers/video/fb_notify.c delete mode 100644 drivers/video/fb_sys_fops.c delete mode 100644 drivers/video/fbcmap.c delete mode 100644 drivers/video/fbcvt.c create mode 100644 drivers/video/fbdev/68328fb.c create mode 100644 drivers/video/fbdev/Kconfig create mode 100644 drivers/video/fbdev/Makefile create mode 100644 drivers/video/fbdev/acornfb.c create mode 100644 drivers/video/fbdev/acornfb.h create mode 100644 drivers/video/fbdev/amba-clcd.c create mode 100644 drivers/video/fbdev/amifb.c create mode 100644 drivers/video/fbdev/arcfb.c create mode 100644 drivers/video/fbdev/arkfb.c create mode 100644 drivers/video/fbdev/asiliantfb.c create mode 100644 drivers/video/fbdev/atafb.c create mode 100644 drivers/video/fbdev/atafb.h create mode 100644 drivers/video/fbdev/atafb_iplan2p2.c create mode 100644 drivers/video/fbdev/atafb_iplan2p4.c create mode 100644 drivers/video/fbdev/atafb_iplan2p8.c create mode 100644 drivers/video/fbdev/atafb_mfb.c create mode 100644 drivers/video/fbdev/atafb_utils.h create mode 100644 drivers/video/fbdev/atmel_lcdfb.c create mode 100644 drivers/video/fbdev/aty/Makefile create mode 100644 drivers/video/fbdev/aty/ati_ids.h create mode 100644 drivers/video/fbdev/aty/aty128fb.c create mode 100644 drivers/video/fbdev/aty/atyfb.h create mode 100644 drivers/video/fbdev/aty/atyfb_base.c create mode 100644 drivers/video/fbdev/aty/mach64_accel.c create mode 100644 drivers/video/fbdev/aty/mach64_ct.c create mode 100644 drivers/video/fbdev/aty/mach64_cursor.c create mode 100644 drivers/video/fbdev/aty/mach64_gx.c create mode 100644 drivers/video/fbdev/aty/radeon_accel.c create mode 100644 drivers/video/fbdev/aty/radeon_backlight.c create mode 100644 drivers/video/fbdev/aty/radeon_base.c create mode 100644 drivers/video/fbdev/aty/radeon_i2c.c create mode 100644 drivers/video/fbdev/aty/radeon_monitor.c create mode 100644 drivers/video/fbdev/aty/radeon_pm.c create mode 100644 drivers/video/fbdev/aty/radeonfb.h create mode 100644 drivers/video/fbdev/au1100fb.c create mode 100644 drivers/video/fbdev/au1100fb.h create mode 100644 drivers/video/fbdev/au1200fb.c create mode 100644 drivers/video/fbdev/au1200fb.h create mode 100644 drivers/video/fbdev/auo_k1900fb.c create mode 100644 drivers/video/fbdev/auo_k1901fb.c create mode 100644 drivers/video/fbdev/auo_k190x.c create mode 100644 drivers/video/fbdev/auo_k190x.h create mode 100644 drivers/video/fbdev/bf537-lq035.c create mode 100644 drivers/video/fbdev/bf54x-lq043fb.c create mode 100644 drivers/video/fbdev/bfin-lq035q1-fb.c create mode 100644 drivers/video/fbdev/bfin-t350mcqb-fb.c create mode 100644 drivers/video/fbdev/bfin_adv7393fb.c create mode 100644 drivers/video/fbdev/bfin_adv7393fb.h create mode 100644 drivers/video/fbdev/broadsheetfb.c create mode 100644 drivers/video/fbdev/bt431.h create mode 100644 drivers/video/fbdev/bt455.h create mode 100644 drivers/video/fbdev/bw2.c create mode 100644 drivers/video/fbdev/c2p.h create mode 100644 drivers/video/fbdev/c2p_core.h create mode 100644 drivers/video/fbdev/c2p_iplan2.c create mode 100644 drivers/video/fbdev/c2p_planar.c create mode 100644 drivers/video/fbdev/carminefb.c create mode 100644 drivers/video/fbdev/carminefb.h create mode 100644 drivers/video/fbdev/carminefb_regs.h create mode 100644 drivers/video/fbdev/cfbcopyarea.c create mode 100644 drivers/video/fbdev/cfbfillrect.c create mode 100644 drivers/video/fbdev/cfbimgblt.c create mode 100644 drivers/video/fbdev/cg14.c create mode 100644 drivers/video/fbdev/cg3.c create mode 100644 drivers/video/fbdev/cg6.c create mode 100644 drivers/video/fbdev/chipsfb.c create mode 100644 drivers/video/fbdev/cirrusfb.c create mode 100644 drivers/video/fbdev/clps711xfb.c create mode 100644 drivers/video/fbdev/cobalt_lcdfb.c create mode 100644 drivers/video/fbdev/controlfb.c create mode 100644 drivers/video/fbdev/controlfb.h create mode 100644 drivers/video/fbdev/cyber2000fb.c create mode 100644 drivers/video/fbdev/cyber2000fb.h create mode 100644 drivers/video/fbdev/da8xx-fb.c create mode 100644 drivers/video/fbdev/dnfb.c create mode 100644 drivers/video/fbdev/edid.h create mode 100644 drivers/video/fbdev/efifb.c create mode 100644 drivers/video/fbdev/ep93xx-fb.c create mode 100644 drivers/video/fbdev/exynos/Kconfig create mode 100644 drivers/video/fbdev/exynos/Makefile create mode 100644 drivers/video/fbdev/exynos/exynos_mipi_dsi.c create mode 100644 drivers/video/fbdev/exynos/exynos_mipi_dsi_common.c create mode 100644 drivers/video/fbdev/exynos/exynos_mipi_dsi_common.h create mode 100644 drivers/video/fbdev/exynos/exynos_mipi_dsi_lowlevel.c create mode 100644 drivers/video/fbdev/exynos/exynos_mipi_dsi_lowlevel.h create mode 100644 drivers/video/fbdev/exynos/exynos_mipi_dsi_regs.h create mode 100644 drivers/video/fbdev/exynos/s6e8ax0.c create mode 100644 drivers/video/fbdev/fb-puv3.c create mode 100644 drivers/video/fbdev/fb_ddc.c create mode 100644 drivers/video/fbdev/fb_defio.c create mode 100644 drivers/video/fbdev/fb_draw.h create mode 100644 drivers/video/fbdev/fb_notify.c create mode 100644 drivers/video/fbdev/fb_sys_fops.c create mode 100644 drivers/video/fbdev/fbcmap.c create mode 100644 drivers/video/fbdev/fbcvt.c create mode 100644 drivers/video/fbdev/fbmem.c create mode 100644 drivers/video/fbdev/fbmon.c create mode 100644 drivers/video/fbdev/fbsysfs.c create mode 100644 drivers/video/fbdev/ffb.c create mode 100644 drivers/video/fbdev/fm2fb.c create mode 100644 drivers/video/fbdev/fsl-diu-fb.c create mode 100644 drivers/video/fbdev/g364fb.c create mode 100644 drivers/video/fbdev/gbefb.c create mode 100644 drivers/video/fbdev/geode/Kconfig create mode 100644 drivers/video/fbdev/geode/Makefile create mode 100644 drivers/video/fbdev/geode/display_gx.c create mode 100644 drivers/video/fbdev/geode/display_gx1.c create mode 100644 drivers/video/fbdev/geode/display_gx1.h create mode 100644 drivers/video/fbdev/geode/geodefb.h create mode 100644 drivers/video/fbdev/geode/gx1fb_core.c create mode 100644 drivers/video/fbdev/geode/gxfb.h create mode 100644 drivers/video/fbdev/geode/gxfb_core.c create mode 100644 drivers/video/fbdev/geode/lxfb.h create mode 100644 drivers/video/fbdev/geode/lxfb_core.c create mode 100644 drivers/video/fbdev/geode/lxfb_ops.c create mode 100644 drivers/video/fbdev/geode/suspend_gx.c create mode 100644 drivers/video/fbdev/geode/video_cs5530.c create mode 100644 drivers/video/fbdev/geode/video_cs5530.h create mode 100644 drivers/video/fbdev/geode/video_gx.c create mode 100644 drivers/video/fbdev/goldfishfb.c create mode 100644 drivers/video/fbdev/grvga.c create mode 100644 drivers/video/fbdev/gxt4500.c create mode 100644 drivers/video/fbdev/hecubafb.c create mode 100644 drivers/video/fbdev/hgafb.c create mode 100644 drivers/video/fbdev/hitfb.c create mode 100644 drivers/video/fbdev/hpfb.c create mode 100644 drivers/video/fbdev/hyperv_fb.c create mode 100644 drivers/video/fbdev/i740_reg.h create mode 100644 drivers/video/fbdev/i740fb.c create mode 100644 drivers/video/fbdev/i810/Makefile create mode 100644 drivers/video/fbdev/i810/i810-i2c.c create mode 100644 drivers/video/fbdev/i810/i810.h create mode 100644 drivers/video/fbdev/i810/i810_accel.c create mode 100644 drivers/video/fbdev/i810/i810_dvt.c create mode 100644 drivers/video/fbdev/i810/i810_gtf.c create mode 100644 drivers/video/fbdev/i810/i810_main.c create mode 100644 drivers/video/fbdev/i810/i810_main.h create mode 100644 drivers/video/fbdev/i810/i810_regs.h create mode 100644 drivers/video/fbdev/igafb.c create mode 100644 drivers/video/fbdev/imsttfb.c create mode 100644 drivers/video/fbdev/imxfb.c create mode 100644 drivers/video/fbdev/intelfb/Makefile create mode 100644 drivers/video/fbdev/intelfb/intelfb.h create mode 100644 drivers/video/fbdev/intelfb/intelfb_i2c.c create mode 100644 drivers/video/fbdev/intelfb/intelfbdrv.c create mode 100644 drivers/video/fbdev/intelfb/intelfbhw.c create mode 100644 drivers/video/fbdev/intelfb/intelfbhw.h create mode 100644 drivers/video/fbdev/jz4740_fb.c create mode 100644 drivers/video/fbdev/kyro/Makefile create mode 100644 drivers/video/fbdev/kyro/STG4000InitDevice.c create mode 100644 drivers/video/fbdev/kyro/STG4000Interface.h create mode 100644 drivers/video/fbdev/kyro/STG4000OverlayDevice.c create mode 100644 drivers/video/fbdev/kyro/STG4000Ramdac.c create mode 100644 drivers/video/fbdev/kyro/STG4000Reg.h create mode 100644 drivers/video/fbdev/kyro/STG4000VTG.c create mode 100644 drivers/video/fbdev/kyro/fbdev.c create mode 100644 drivers/video/fbdev/leo.c create mode 100644 drivers/video/fbdev/macfb.c create mode 100644 drivers/video/fbdev/macmodes.c create mode 100644 drivers/video/fbdev/macmodes.h create mode 100644 drivers/video/fbdev/matrox/Makefile create mode 100644 drivers/video/fbdev/matrox/g450_pll.c create mode 100644 drivers/video/fbdev/matrox/g450_pll.h create mode 100644 drivers/video/fbdev/matrox/i2c-matroxfb.c create mode 100644 drivers/video/fbdev/matrox/matroxfb_DAC1064.c create mode 100644 drivers/video/fbdev/matrox/matroxfb_DAC1064.h create mode 100644 drivers/video/fbdev/matrox/matroxfb_Ti3026.c create mode 100644 drivers/video/fbdev/matrox/matroxfb_Ti3026.h create mode 100644 drivers/video/fbdev/matrox/matroxfb_accel.c create mode 100644 drivers/video/fbdev/matrox/matroxfb_accel.h create mode 100644 drivers/video/fbdev/matrox/matroxfb_base.c create mode 100644 drivers/video/fbdev/matrox/matroxfb_base.h create mode 100644 drivers/video/fbdev/matrox/matroxfb_crtc2.c create mode 100644 drivers/video/fbdev/matrox/matroxfb_crtc2.h create mode 100644 drivers/video/fbdev/matrox/matroxfb_g450.c create mode 100644 drivers/video/fbdev/matrox/matroxfb_g450.h create mode 100644 drivers/video/fbdev/matrox/matroxfb_maven.c create mode 100644 drivers/video/fbdev/matrox/matroxfb_maven.h create mode 100644 drivers/video/fbdev/matrox/matroxfb_misc.c create mode 100644 drivers/video/fbdev/matrox/matroxfb_misc.h create mode 100644 drivers/video/fbdev/maxinefb.c create mode 100644 drivers/video/fbdev/mb862xx/Makefile create mode 100644 drivers/video/fbdev/mb862xx/mb862xx-i2c.c create mode 100644 drivers/video/fbdev/mb862xx/mb862xx_reg.h create mode 100644 drivers/video/fbdev/mb862xx/mb862xxfb.h create mode 100644 drivers/video/fbdev/mb862xx/mb862xxfb_accel.c create mode 100644 drivers/video/fbdev/mb862xx/mb862xxfb_accel.h create mode 100644 drivers/video/fbdev/mb862xx/mb862xxfbdrv.c create mode 100644 drivers/video/fbdev/mbx/Makefile create mode 100644 drivers/video/fbdev/mbx/mbxdebugfs.c create mode 100644 drivers/video/fbdev/mbx/mbxfb.c create mode 100644 drivers/video/fbdev/mbx/reg_bits.h create mode 100644 drivers/video/fbdev/mbx/regs.h create mode 100644 drivers/video/fbdev/metronomefb.c create mode 100644 drivers/video/fbdev/mmp/Kconfig create mode 100644 drivers/video/fbdev/mmp/Makefile create mode 100644 drivers/video/fbdev/mmp/core.c create mode 100644 drivers/video/fbdev/mmp/fb/Kconfig create mode 100644 drivers/video/fbdev/mmp/fb/Makefile create mode 100644 drivers/video/fbdev/mmp/fb/mmpfb.c create mode 100644 drivers/video/fbdev/mmp/fb/mmpfb.h create mode 100644 drivers/video/fbdev/mmp/hw/Kconfig create mode 100644 drivers/video/fbdev/mmp/hw/Makefile create mode 100644 drivers/video/fbdev/mmp/hw/mmp_ctrl.c create mode 100644 drivers/video/fbdev/mmp/hw/mmp_ctrl.h create mode 100644 drivers/video/fbdev/mmp/hw/mmp_spi.c create mode 100644 drivers/video/fbdev/mmp/panel/Kconfig create mode 100644 drivers/video/fbdev/mmp/panel/Makefile create mode 100644 drivers/video/fbdev/mmp/panel/tpo_tj032md01bw.c create mode 100644 drivers/video/fbdev/modedb.c create mode 100644 drivers/video/fbdev/msm/Makefile create mode 100644 drivers/video/fbdev/msm/mddi.c create mode 100644 drivers/video/fbdev/msm/mddi_client_dummy.c create mode 100644 drivers/video/fbdev/msm/mddi_client_nt35399.c create mode 100644 drivers/video/fbdev/msm/mddi_client_toshiba.c create mode 100644 drivers/video/fbdev/msm/mddi_hw.h create mode 100644 drivers/video/fbdev/msm/mdp.c create mode 100644 drivers/video/fbdev/msm/mdp_csc_table.h create mode 100644 drivers/video/fbdev/msm/mdp_hw.h create mode 100644 drivers/video/fbdev/msm/mdp_ppp.c create mode 100644 drivers/video/fbdev/msm/mdp_scale_tables.c create mode 100644 drivers/video/fbdev/msm/mdp_scale_tables.h create mode 100644 drivers/video/fbdev/msm/msm_fb.c create mode 100644 drivers/video/fbdev/mx3fb.c create mode 100644 drivers/video/fbdev/mxsfb.c create mode 100644 drivers/video/fbdev/n411.c create mode 100644 drivers/video/fbdev/neofb.c create mode 100644 drivers/video/fbdev/nuc900fb.c create mode 100644 drivers/video/fbdev/nuc900fb.h create mode 100644 drivers/video/fbdev/nvidia/Makefile create mode 100644 drivers/video/fbdev/nvidia/nv_accel.c create mode 100644 drivers/video/fbdev/nvidia/nv_backlight.c create mode 100644 drivers/video/fbdev/nvidia/nv_dma.h create mode 100644 drivers/video/fbdev/nvidia/nv_hw.c create mode 100644 drivers/video/fbdev/nvidia/nv_i2c.c create mode 100644 drivers/video/fbdev/nvidia/nv_local.h create mode 100644 drivers/video/fbdev/nvidia/nv_of.c create mode 100644 drivers/video/fbdev/nvidia/nv_proto.h create mode 100644 drivers/video/fbdev/nvidia/nv_setup.c create mode 100644 drivers/video/fbdev/nvidia/nv_type.h create mode 100644 drivers/video/fbdev/nvidia/nvidia.c create mode 100644 drivers/video/fbdev/ocfb.c create mode 100644 drivers/video/fbdev/offb.c create mode 100644 drivers/video/fbdev/omap/Kconfig create mode 100644 drivers/video/fbdev/omap/Makefile create mode 100644 drivers/video/fbdev/omap/hwa742.c create mode 100644 drivers/video/fbdev/omap/lcd_ams_delta.c create mode 100644 drivers/video/fbdev/omap/lcd_h3.c create mode 100644 drivers/video/fbdev/omap/lcd_htcherald.c create mode 100644 drivers/video/fbdev/omap/lcd_inn1510.c create mode 100644 drivers/video/fbdev/omap/lcd_inn1610.c create mode 100644 drivers/video/fbdev/omap/lcd_mipid.c create mode 100644 drivers/video/fbdev/omap/lcd_osk.c create mode 100644 drivers/video/fbdev/omap/lcd_palmte.c create mode 100644 drivers/video/fbdev/omap/lcd_palmtt.c create mode 100644 drivers/video/fbdev/omap/lcd_palmz71.c create mode 100644 drivers/video/fbdev/omap/lcdc.c create mode 100644 drivers/video/fbdev/omap/lcdc.h create mode 100644 drivers/video/fbdev/omap/omapfb.h create mode 100644 drivers/video/fbdev/omap/omapfb_main.c create mode 100644 drivers/video/fbdev/omap/sossi.c create mode 100644 drivers/video/fbdev/omap2/Kconfig create mode 100644 drivers/video/fbdev/omap2/Makefile create mode 100644 drivers/video/fbdev/omap2/displays-new/Kconfig create mode 100644 drivers/video/fbdev/omap2/displays-new/Makefile create mode 100644 drivers/video/fbdev/omap2/displays-new/connector-analog-tv.c create mode 100644 drivers/video/fbdev/omap2/displays-new/connector-dvi.c create mode 100644 drivers/video/fbdev/omap2/displays-new/connector-hdmi.c create mode 100644 drivers/video/fbdev/omap2/displays-new/encoder-tfp410.c create mode 100644 drivers/video/fbdev/omap2/displays-new/encoder-tpd12s015.c create mode 100644 drivers/video/fbdev/omap2/displays-new/panel-dpi.c create mode 100644 drivers/video/fbdev/omap2/displays-new/panel-dsi-cm.c create mode 100644 drivers/video/fbdev/omap2/displays-new/panel-lgphilips-lb035q02.c create mode 100644 drivers/video/fbdev/omap2/displays-new/panel-nec-nl8048hl11.c create mode 100644 drivers/video/fbdev/omap2/displays-new/panel-sharp-ls037v7dw01.c create mode 100644 drivers/video/fbdev/omap2/displays-new/panel-sony-acx565akm.c create mode 100644 drivers/video/fbdev/omap2/displays-new/panel-tpo-td028ttec1.c create mode 100644 drivers/video/fbdev/omap2/displays-new/panel-tpo-td043mtea1.c create mode 100644 drivers/video/fbdev/omap2/dss/Kconfig create mode 100644 drivers/video/fbdev/omap2/dss/Makefile create mode 100644 drivers/video/fbdev/omap2/dss/apply.c create mode 100644 drivers/video/fbdev/omap2/dss/core.c create mode 100644 drivers/video/fbdev/omap2/dss/dispc-compat.c create mode 100644 drivers/video/fbdev/omap2/dss/dispc-compat.h create mode 100644 drivers/video/fbdev/omap2/dss/dispc.c create mode 100644 drivers/video/fbdev/omap2/dss/dispc.h create mode 100644 drivers/video/fbdev/omap2/dss/dispc_coefs.c create mode 100644 drivers/video/fbdev/omap2/dss/display-sysfs.c create mode 100644 drivers/video/fbdev/omap2/dss/display.c create mode 100644 drivers/video/fbdev/omap2/dss/dpi.c create mode 100644 drivers/video/fbdev/omap2/dss/dsi.c create mode 100644 drivers/video/fbdev/omap2/dss/dss-of.c create mode 100644 drivers/video/fbdev/omap2/dss/dss.c create mode 100644 drivers/video/fbdev/omap2/dss/dss.h create mode 100644 drivers/video/fbdev/omap2/dss/dss_features.c create mode 100644 drivers/video/fbdev/omap2/dss/dss_features.h create mode 100644 drivers/video/fbdev/omap2/dss/hdmi.h create mode 100644 drivers/video/fbdev/omap2/dss/hdmi4.c create mode 100644 drivers/video/fbdev/omap2/dss/hdmi4_core.c create mode 100644 drivers/video/fbdev/omap2/dss/hdmi4_core.h create mode 100644 drivers/video/fbdev/omap2/dss/hdmi_common.c create mode 100644 drivers/video/fbdev/omap2/dss/hdmi_phy.c create mode 100644 drivers/video/fbdev/omap2/dss/hdmi_pll.c create mode 100644 drivers/video/fbdev/omap2/dss/hdmi_wp.c create mode 100644 drivers/video/fbdev/omap2/dss/manager-sysfs.c create mode 100644 drivers/video/fbdev/omap2/dss/manager.c create mode 100644 drivers/video/fbdev/omap2/dss/output.c create mode 100644 drivers/video/fbdev/omap2/dss/overlay-sysfs.c create mode 100644 drivers/video/fbdev/omap2/dss/overlay.c create mode 100644 drivers/video/fbdev/omap2/dss/rfbi.c create mode 100644 drivers/video/fbdev/omap2/dss/sdi.c create mode 100644 drivers/video/fbdev/omap2/dss/venc.c create mode 100644 drivers/video/fbdev/omap2/dss/venc_panel.c create mode 100644 drivers/video/fbdev/omap2/omapfb/Kconfig create mode 100644 drivers/video/fbdev/omap2/omapfb/Makefile create mode 100644 drivers/video/fbdev/omap2/omapfb/omapfb-ioctl.c create mode 100644 drivers/video/fbdev/omap2/omapfb/omapfb-main.c create mode 100644 drivers/video/fbdev/omap2/omapfb/omapfb-sysfs.c create mode 100644 drivers/video/fbdev/omap2/omapfb/omapfb.h create mode 100644 drivers/video/fbdev/omap2/vrfb.c create mode 100644 drivers/video/fbdev/p9100.c create mode 100644 drivers/video/fbdev/platinumfb.c create mode 100644 drivers/video/fbdev/platinumfb.h create mode 100644 drivers/video/fbdev/pm2fb.c create mode 100644 drivers/video/fbdev/pm3fb.c create mode 100644 drivers/video/fbdev/pmag-aa-fb.c create mode 100644 drivers/video/fbdev/pmag-ba-fb.c create mode 100644 drivers/video/fbdev/pmagb-b-fb.c create mode 100644 drivers/video/fbdev/ps3fb.c create mode 100644 drivers/video/fbdev/pvr2fb.c create mode 100644 drivers/video/fbdev/pxa168fb.c create mode 100644 drivers/video/fbdev/pxa168fb.h create mode 100644 drivers/video/fbdev/pxa3xx-gcu.c create mode 100644 drivers/video/fbdev/pxa3xx-gcu.h create mode 100644 drivers/video/fbdev/pxafb.c create mode 100644 drivers/video/fbdev/pxafb.h create mode 100644 drivers/video/fbdev/q40fb.c create mode 100644 drivers/video/fbdev/riva/Makefile create mode 100644 drivers/video/fbdev/riva/fbdev.c create mode 100644 drivers/video/fbdev/riva/nv_driver.c create mode 100644 drivers/video/fbdev/riva/nv_type.h create mode 100644 drivers/video/fbdev/riva/nvreg.h create mode 100644 drivers/video/fbdev/riva/riva_hw.c create mode 100644 drivers/video/fbdev/riva/riva_hw.h create mode 100644 drivers/video/fbdev/riva/riva_tbl.h create mode 100644 drivers/video/fbdev/riva/rivafb-i2c.c create mode 100644 drivers/video/fbdev/riva/rivafb.h create mode 100644 drivers/video/fbdev/s1d13xxxfb.c create mode 100644 drivers/video/fbdev/s3c-fb.c create mode 100644 drivers/video/fbdev/s3c2410fb.c create mode 100644 drivers/video/fbdev/s3c2410fb.h create mode 100644 drivers/video/fbdev/s3fb.c create mode 100644 drivers/video/fbdev/sa1100fb.c create mode 100644 drivers/video/fbdev/sa1100fb.h create mode 100644 drivers/video/fbdev/savage/Makefile create mode 100644 drivers/video/fbdev/savage/savagefb-i2c.c create mode 100644 drivers/video/fbdev/savage/savagefb.h create mode 100644 drivers/video/fbdev/savage/savagefb_accel.c create mode 100644 drivers/video/fbdev/savage/savagefb_driver.c create mode 100644 drivers/video/fbdev/sbuslib.c create mode 100644 drivers/video/fbdev/sbuslib.h create mode 100644 drivers/video/fbdev/sh7760fb.c create mode 100644 drivers/video/fbdev/sh_mipi_dsi.c create mode 100644 drivers/video/fbdev/sh_mobile_hdmi.c create mode 100644 drivers/video/fbdev/sh_mobile_lcdcfb.c create mode 100644 drivers/video/fbdev/sh_mobile_lcdcfb.h create mode 100644 drivers/video/fbdev/sh_mobile_meram.c create mode 100644 drivers/video/fbdev/simplefb.c create mode 100644 drivers/video/fbdev/sis/300vtbl.h create mode 100644 drivers/video/fbdev/sis/310vtbl.h create mode 100644 drivers/video/fbdev/sis/Makefile create mode 100644 drivers/video/fbdev/sis/init.c create mode 100644 drivers/video/fbdev/sis/init.h create mode 100644 drivers/video/fbdev/sis/init301.c create mode 100644 drivers/video/fbdev/sis/init301.h create mode 100644 drivers/video/fbdev/sis/initdef.h create mode 100644 drivers/video/fbdev/sis/initextlfb.c create mode 100644 drivers/video/fbdev/sis/oem300.h create mode 100644 drivers/video/fbdev/sis/oem310.h create mode 100644 drivers/video/fbdev/sis/sis.h create mode 100644 drivers/video/fbdev/sis/sis_accel.c create mode 100644 drivers/video/fbdev/sis/sis_accel.h create mode 100644 drivers/video/fbdev/sis/sis_main.c create mode 100644 drivers/video/fbdev/sis/sis_main.h create mode 100644 drivers/video/fbdev/sis/vgatypes.h create mode 100644 drivers/video/fbdev/sis/vstruct.h create mode 100644 drivers/video/fbdev/skeletonfb.c create mode 100644 drivers/video/fbdev/sm501fb.c create mode 100644 drivers/video/fbdev/smscufx.c create mode 100644 drivers/video/fbdev/ssd1307fb.c create mode 100644 drivers/video/fbdev/sstfb.c create mode 100644 drivers/video/fbdev/sticore.h create mode 100644 drivers/video/fbdev/stifb.c create mode 100644 drivers/video/fbdev/sunxvr1000.c create mode 100644 drivers/video/fbdev/sunxvr2500.c create mode 100644 drivers/video/fbdev/sunxvr500.c create mode 100644 drivers/video/fbdev/svgalib.c create mode 100644 drivers/video/fbdev/syscopyarea.c create mode 100644 drivers/video/fbdev/sysfillrect.c create mode 100644 drivers/video/fbdev/sysimgblt.c create mode 100644 drivers/video/fbdev/tcx.c create mode 100644 drivers/video/fbdev/tdfxfb.c create mode 100644 drivers/video/fbdev/tgafb.c create mode 100644 drivers/video/fbdev/tmiofb.c create mode 100644 drivers/video/fbdev/tridentfb.c create mode 100644 drivers/video/fbdev/udlfb.c create mode 100644 drivers/video/fbdev/uvesafb.c create mode 100644 drivers/video/fbdev/valkyriefb.c create mode 100644 drivers/video/fbdev/valkyriefb.h create mode 100644 drivers/video/fbdev/vermilion/Makefile create mode 100644 drivers/video/fbdev/vermilion/cr_pll.c create mode 100644 drivers/video/fbdev/vermilion/vermilion.c create mode 100644 drivers/video/fbdev/vermilion/vermilion.h create mode 100644 drivers/video/fbdev/vesafb.c create mode 100644 drivers/video/fbdev/vfb.c create mode 100644 drivers/video/fbdev/vga16fb.c create mode 100644 drivers/video/fbdev/via/Makefile create mode 100644 drivers/video/fbdev/via/accel.c create mode 100644 drivers/video/fbdev/via/accel.h create mode 100644 drivers/video/fbdev/via/chip.h create mode 100644 drivers/video/fbdev/via/debug.h create mode 100644 drivers/video/fbdev/via/dvi.c create mode 100644 drivers/video/fbdev/via/dvi.h create mode 100644 drivers/video/fbdev/via/global.c create mode 100644 drivers/video/fbdev/via/global.h create mode 100644 drivers/video/fbdev/via/hw.c create mode 100644 drivers/video/fbdev/via/hw.h create mode 100644 drivers/video/fbdev/via/ioctl.c create mode 100644 drivers/video/fbdev/via/ioctl.h create mode 100644 drivers/video/fbdev/via/lcd.c create mode 100644 drivers/video/fbdev/via/lcd.h create mode 100644 drivers/video/fbdev/via/share.h create mode 100644 drivers/video/fbdev/via/tblDPASetting.c create mode 100644 drivers/video/fbdev/via/tblDPASetting.h create mode 100644 drivers/video/fbdev/via/via-core.c create mode 100644 drivers/video/fbdev/via/via-gpio.c create mode 100644 drivers/video/fbdev/via/via_aux.c create mode 100644 drivers/video/fbdev/via/via_aux.h create mode 100644 drivers/video/fbdev/via/via_aux_ch7301.c create mode 100644 drivers/video/fbdev/via/via_aux_edid.c create mode 100644 drivers/video/fbdev/via/via_aux_sii164.c create mode 100644 drivers/video/fbdev/via/via_aux_vt1621.c create mode 100644 drivers/video/fbdev/via/via_aux_vt1622.c create mode 100644 drivers/video/fbdev/via/via_aux_vt1625.c create mode 100644 drivers/video/fbdev/via/via_aux_vt1631.c create mode 100644 drivers/video/fbdev/via/via_aux_vt1632.c create mode 100644 drivers/video/fbdev/via/via_aux_vt1636.c create mode 100644 drivers/video/fbdev/via/via_clock.c create mode 100644 drivers/video/fbdev/via/via_clock.h create mode 100644 drivers/video/fbdev/via/via_i2c.c create mode 100644 drivers/video/fbdev/via/via_modesetting.c create mode 100644 drivers/video/fbdev/via/via_modesetting.h create mode 100644 drivers/video/fbdev/via/via_utility.c create mode 100644 drivers/video/fbdev/via/via_utility.h create mode 100644 drivers/video/fbdev/via/viafbdev.c create mode 100644 drivers/video/fbdev/via/viafbdev.h create mode 100644 drivers/video/fbdev/via/viamode.c create mode 100644 drivers/video/fbdev/via/viamode.h create mode 100644 drivers/video/fbdev/via/vt1636.c create mode 100644 drivers/video/fbdev/via/vt1636.h create mode 100644 drivers/video/fbdev/vt8500lcdfb.c create mode 100644 drivers/video/fbdev/vt8500lcdfb.h create mode 100644 drivers/video/fbdev/vt8623fb.c create mode 100644 drivers/video/fbdev/w100fb.c create mode 100644 drivers/video/fbdev/w100fb.h create mode 100644 drivers/video/fbdev/wm8505fb.c create mode 100644 drivers/video/fbdev/wm8505fb_regs.h create mode 100644 drivers/video/fbdev/wmt_ge_rops.c create mode 100644 drivers/video/fbdev/wmt_ge_rops.h create mode 100644 drivers/video/fbdev/xen-fbfront.c create mode 100644 drivers/video/fbdev/xilinxfb.c delete mode 100644 drivers/video/fbmem.c delete mode 100644 drivers/video/fbmon.c delete mode 100644 drivers/video/fbsysfs.c delete mode 100644 drivers/video/ffb.c delete mode 100644 drivers/video/fm2fb.c delete mode 100644 drivers/video/fsl-diu-fb.c delete mode 100644 drivers/video/g364fb.c delete mode 100644 drivers/video/gbefb.c delete mode 100644 drivers/video/geode/Kconfig delete mode 100644 drivers/video/geode/Makefile delete mode 100644 drivers/video/geode/display_gx.c delete mode 100644 drivers/video/geode/display_gx1.c delete mode 100644 drivers/video/geode/display_gx1.h delete mode 100644 drivers/video/geode/geodefb.h delete mode 100644 drivers/video/geode/gx1fb_core.c delete mode 100644 drivers/video/geode/gxfb.h delete mode 100644 drivers/video/geode/gxfb_core.c delete mode 100644 drivers/video/geode/lxfb.h delete mode 100644 drivers/video/geode/lxfb_core.c delete mode 100644 drivers/video/geode/lxfb_ops.c delete mode 100644 drivers/video/geode/suspend_gx.c delete mode 100644 drivers/video/geode/video_cs5530.c delete mode 100644 drivers/video/geode/video_cs5530.h delete mode 100644 drivers/video/geode/video_gx.c delete mode 100644 drivers/video/goldfishfb.c delete mode 100644 drivers/video/grvga.c delete mode 100644 drivers/video/gxt4500.c delete mode 100644 drivers/video/hecubafb.c delete mode 100644 drivers/video/hgafb.c delete mode 100644 drivers/video/hitfb.c delete mode 100644 drivers/video/hpfb.c delete mode 100644 drivers/video/hyperv_fb.c delete mode 100644 drivers/video/i740_reg.h delete mode 100644 drivers/video/i740fb.c delete mode 100644 drivers/video/i810/Makefile delete mode 100644 drivers/video/i810/i810-i2c.c delete mode 100644 drivers/video/i810/i810.h delete mode 100644 drivers/video/i810/i810_accel.c delete mode 100644 drivers/video/i810/i810_dvt.c delete mode 100644 drivers/video/i810/i810_gtf.c delete mode 100644 drivers/video/i810/i810_main.c delete mode 100644 drivers/video/i810/i810_main.h delete mode 100644 drivers/video/i810/i810_regs.h delete mode 100644 drivers/video/igafb.c delete mode 100644 drivers/video/imsttfb.c delete mode 100644 drivers/video/imxfb.c delete mode 100644 drivers/video/intelfb/Makefile delete mode 100644 drivers/video/intelfb/intelfb.h delete mode 100644 drivers/video/intelfb/intelfb_i2c.c delete mode 100644 drivers/video/intelfb/intelfbdrv.c delete mode 100644 drivers/video/intelfb/intelfbhw.c delete mode 100644 drivers/video/intelfb/intelfbhw.h delete mode 100644 drivers/video/jz4740_fb.c delete mode 100644 drivers/video/kyro/Makefile delete mode 100644 drivers/video/kyro/STG4000InitDevice.c delete mode 100644 drivers/video/kyro/STG4000Interface.h delete mode 100644 drivers/video/kyro/STG4000OverlayDevice.c delete mode 100644 drivers/video/kyro/STG4000Ramdac.c delete mode 100644 drivers/video/kyro/STG4000Reg.h delete mode 100644 drivers/video/kyro/STG4000VTG.c delete mode 100644 drivers/video/kyro/fbdev.c delete mode 100644 drivers/video/leo.c delete mode 100644 drivers/video/macfb.c delete mode 100644 drivers/video/macmodes.c delete mode 100644 drivers/video/macmodes.h delete mode 100644 drivers/video/matrox/Makefile delete mode 100644 drivers/video/matrox/g450_pll.c delete mode 100644 drivers/video/matrox/g450_pll.h delete mode 100644 drivers/video/matrox/i2c-matroxfb.c delete mode 100644 drivers/video/matrox/matroxfb_DAC1064.c delete mode 100644 drivers/video/matrox/matroxfb_DAC1064.h delete mode 100644 drivers/video/matrox/matroxfb_Ti3026.c delete mode 100644 drivers/video/matrox/matroxfb_Ti3026.h delete mode 100644 drivers/video/matrox/matroxfb_accel.c delete mode 100644 drivers/video/matrox/matroxfb_accel.h delete mode 100644 drivers/video/matrox/matroxfb_base.c delete mode 100644 drivers/video/matrox/matroxfb_base.h delete mode 100644 drivers/video/matrox/matroxfb_crtc2.c delete mode 100644 drivers/video/matrox/matroxfb_crtc2.h delete mode 100644 drivers/video/matrox/matroxfb_g450.c delete mode 100644 drivers/video/matrox/matroxfb_g450.h delete mode 100644 drivers/video/matrox/matroxfb_maven.c delete mode 100644 drivers/video/matrox/matroxfb_maven.h delete mode 100644 drivers/video/matrox/matroxfb_misc.c delete mode 100644 drivers/video/matrox/matroxfb_misc.h delete mode 100644 drivers/video/maxinefb.c delete mode 100644 drivers/video/mb862xx/Makefile delete mode 100644 drivers/video/mb862xx/mb862xx-i2c.c delete mode 100644 drivers/video/mb862xx/mb862xx_reg.h delete mode 100644 drivers/video/mb862xx/mb862xxfb.h delete mode 100644 drivers/video/mb862xx/mb862xxfb_accel.c delete mode 100644 drivers/video/mb862xx/mb862xxfb_accel.h delete mode 100644 drivers/video/mb862xx/mb862xxfbdrv.c delete mode 100644 drivers/video/mbx/Makefile delete mode 100644 drivers/video/mbx/mbxdebugfs.c delete mode 100644 drivers/video/mbx/mbxfb.c delete mode 100644 drivers/video/mbx/reg_bits.h delete mode 100644 drivers/video/mbx/regs.h delete mode 100644 drivers/video/metronomefb.c delete mode 100644 drivers/video/mmp/Kconfig delete mode 100644 drivers/video/mmp/Makefile delete mode 100644 drivers/video/mmp/core.c delete mode 100644 drivers/video/mmp/fb/Kconfig delete mode 100644 drivers/video/mmp/fb/Makefile delete mode 100644 drivers/video/mmp/fb/mmpfb.c delete mode 100644 drivers/video/mmp/fb/mmpfb.h delete mode 100644 drivers/video/mmp/hw/Kconfig delete mode 100644 drivers/video/mmp/hw/Makefile delete mode 100644 drivers/video/mmp/hw/mmp_ctrl.c delete mode 100644 drivers/video/mmp/hw/mmp_ctrl.h delete mode 100644 drivers/video/mmp/hw/mmp_spi.c delete mode 100644 drivers/video/mmp/panel/Kconfig delete mode 100644 drivers/video/mmp/panel/Makefile delete mode 100644 drivers/video/mmp/panel/tpo_tj032md01bw.c delete mode 100644 drivers/video/modedb.c delete mode 100644 drivers/video/msm/Makefile delete mode 100644 drivers/video/msm/mddi.c delete mode 100644 drivers/video/msm/mddi_client_dummy.c delete mode 100644 drivers/video/msm/mddi_client_nt35399.c delete mode 100644 drivers/video/msm/mddi_client_toshiba.c delete mode 100644 drivers/video/msm/mddi_hw.h delete mode 100644 drivers/video/msm/mdp.c delete mode 100644 drivers/video/msm/mdp_csc_table.h delete mode 100644 drivers/video/msm/mdp_hw.h delete mode 100644 drivers/video/msm/mdp_ppp.c delete mode 100644 drivers/video/msm/mdp_scale_tables.c delete mode 100644 drivers/video/msm/mdp_scale_tables.h delete mode 100644 drivers/video/msm/msm_fb.c delete mode 100644 drivers/video/mx3fb.c delete mode 100644 drivers/video/mxsfb.c delete mode 100644 drivers/video/n411.c delete mode 100644 drivers/video/neofb.c delete mode 100644 drivers/video/nuc900fb.c delete mode 100644 drivers/video/nuc900fb.h delete mode 100644 drivers/video/nvidia/Makefile delete mode 100644 drivers/video/nvidia/nv_accel.c delete mode 100644 drivers/video/nvidia/nv_backlight.c delete mode 100644 drivers/video/nvidia/nv_dma.h delete mode 100644 drivers/video/nvidia/nv_hw.c delete mode 100644 drivers/video/nvidia/nv_i2c.c delete mode 100644 drivers/video/nvidia/nv_local.h delete mode 100644 drivers/video/nvidia/nv_of.c delete mode 100644 drivers/video/nvidia/nv_proto.h delete mode 100644 drivers/video/nvidia/nv_setup.c delete mode 100644 drivers/video/nvidia/nv_type.h delete mode 100644 drivers/video/nvidia/nvidia.c delete mode 100644 drivers/video/ocfb.c delete mode 100644 drivers/video/offb.c delete mode 100644 drivers/video/omap/Kconfig delete mode 100644 drivers/video/omap/Makefile delete mode 100644 drivers/video/omap/hwa742.c delete mode 100644 drivers/video/omap/lcd_ams_delta.c delete mode 100644 drivers/video/omap/lcd_h3.c delete mode 100644 drivers/video/omap/lcd_htcherald.c delete mode 100644 drivers/video/omap/lcd_inn1510.c delete mode 100644 drivers/video/omap/lcd_inn1610.c delete mode 100644 drivers/video/omap/lcd_mipid.c delete mode 100644 drivers/video/omap/lcd_osk.c delete mode 100644 drivers/video/omap/lcd_palmte.c delete mode 100644 drivers/video/omap/lcd_palmtt.c delete mode 100644 drivers/video/omap/lcd_palmz71.c delete mode 100644 drivers/video/omap/lcdc.c delete mode 100644 drivers/video/omap/lcdc.h delete mode 100644 drivers/video/omap/omapfb.h delete mode 100644 drivers/video/omap/omapfb_main.c delete mode 100644 drivers/video/omap/sossi.c delete mode 100644 drivers/video/omap2/Kconfig delete mode 100644 drivers/video/omap2/Makefile delete mode 100644 drivers/video/omap2/displays-new/Kconfig delete mode 100644 drivers/video/omap2/displays-new/Makefile delete mode 100644 drivers/video/omap2/displays-new/connector-analog-tv.c delete mode 100644 drivers/video/omap2/displays-new/connector-dvi.c delete mode 100644 drivers/video/omap2/displays-new/connector-hdmi.c delete mode 100644 drivers/video/omap2/displays-new/encoder-tfp410.c delete mode 100644 drivers/video/omap2/displays-new/encoder-tpd12s015.c delete mode 100644 drivers/video/omap2/displays-new/panel-dpi.c delete mode 100644 drivers/video/omap2/displays-new/panel-dsi-cm.c delete mode 100644 drivers/video/omap2/displays-new/panel-lgphilips-lb035q02.c delete mode 100644 drivers/video/omap2/displays-new/panel-nec-nl8048hl11.c delete mode 100644 drivers/video/omap2/displays-new/panel-sharp-ls037v7dw01.c delete mode 100644 drivers/video/omap2/displays-new/panel-sony-acx565akm.c delete mode 100644 drivers/video/omap2/displays-new/panel-tpo-td028ttec1.c delete mode 100644 drivers/video/omap2/displays-new/panel-tpo-td043mtea1.c delete mode 100644 drivers/video/omap2/dss/Kconfig delete mode 100644 drivers/video/omap2/dss/Makefile delete mode 100644 drivers/video/omap2/dss/apply.c delete mode 100644 drivers/video/omap2/dss/core.c delete mode 100644 drivers/video/omap2/dss/dispc-compat.c delete mode 100644 drivers/video/omap2/dss/dispc-compat.h delete mode 100644 drivers/video/omap2/dss/dispc.c delete mode 100644 drivers/video/omap2/dss/dispc.h delete mode 100644 drivers/video/omap2/dss/dispc_coefs.c delete mode 100644 drivers/video/omap2/dss/display-sysfs.c delete mode 100644 drivers/video/omap2/dss/display.c delete mode 100644 drivers/video/omap2/dss/dpi.c delete mode 100644 drivers/video/omap2/dss/dsi.c delete mode 100644 drivers/video/omap2/dss/dss-of.c delete mode 100644 drivers/video/omap2/dss/dss.c delete mode 100644 drivers/video/omap2/dss/dss.h delete mode 100644 drivers/video/omap2/dss/dss_features.c delete mode 100644 drivers/video/omap2/dss/dss_features.h delete mode 100644 drivers/video/omap2/dss/hdmi.h delete mode 100644 drivers/video/omap2/dss/hdmi4.c delete mode 100644 drivers/video/omap2/dss/hdmi4_core.c delete mode 100644 drivers/video/omap2/dss/hdmi4_core.h delete mode 100644 drivers/video/omap2/dss/hdmi_common.c delete mode 100644 drivers/video/omap2/dss/hdmi_phy.c delete mode 100644 drivers/video/omap2/dss/hdmi_pll.c delete mode 100644 drivers/video/omap2/dss/hdmi_wp.c delete mode 100644 drivers/video/omap2/dss/manager-sysfs.c delete mode 100644 drivers/video/omap2/dss/manager.c delete mode 100644 drivers/video/omap2/dss/output.c delete mode 100644 drivers/video/omap2/dss/overlay-sysfs.c delete mode 100644 drivers/video/omap2/dss/overlay.c delete mode 100644 drivers/video/omap2/dss/rfbi.c delete mode 100644 drivers/video/omap2/dss/sdi.c delete mode 100644 drivers/video/omap2/dss/venc.c delete mode 100644 drivers/video/omap2/dss/venc_panel.c delete mode 100644 drivers/video/omap2/omapfb/Kconfig delete mode 100644 drivers/video/omap2/omapfb/Makefile delete mode 100644 drivers/video/omap2/omapfb/omapfb-ioctl.c delete mode 100644 drivers/video/omap2/omapfb/omapfb-main.c delete mode 100644 drivers/video/omap2/omapfb/omapfb-sysfs.c delete mode 100644 drivers/video/omap2/omapfb/omapfb.h delete mode 100644 drivers/video/omap2/vrfb.c delete mode 100644 drivers/video/p9100.c delete mode 100644 drivers/video/platinumfb.c delete mode 100644 drivers/video/platinumfb.h delete mode 100644 drivers/video/pm2fb.c delete mode 100644 drivers/video/pm3fb.c delete mode 100644 drivers/video/pmag-aa-fb.c delete mode 100644 drivers/video/pmag-ba-fb.c delete mode 100644 drivers/video/pmagb-b-fb.c delete mode 100644 drivers/video/ps3fb.c delete mode 100644 drivers/video/pvr2fb.c delete mode 100644 drivers/video/pxa168fb.c delete mode 100644 drivers/video/pxa168fb.h delete mode 100644 drivers/video/pxa3xx-gcu.c delete mode 100644 drivers/video/pxa3xx-gcu.h delete mode 100644 drivers/video/pxafb.c delete mode 100644 drivers/video/pxafb.h delete mode 100644 drivers/video/q40fb.c delete mode 100644 drivers/video/riva/Makefile delete mode 100644 drivers/video/riva/fbdev.c delete mode 100644 drivers/video/riva/nv_driver.c delete mode 100644 drivers/video/riva/nv_type.h delete mode 100644 drivers/video/riva/nvreg.h delete mode 100644 drivers/video/riva/riva_hw.c delete mode 100644 drivers/video/riva/riva_hw.h delete mode 100644 drivers/video/riva/riva_tbl.h delete mode 100644 drivers/video/riva/rivafb-i2c.c delete mode 100644 drivers/video/riva/rivafb.h delete mode 100644 drivers/video/s1d13xxxfb.c delete mode 100644 drivers/video/s3c-fb.c delete mode 100644 drivers/video/s3c2410fb.c delete mode 100644 drivers/video/s3c2410fb.h delete mode 100644 drivers/video/s3fb.c delete mode 100644 drivers/video/sa1100fb.c delete mode 100644 drivers/video/sa1100fb.h delete mode 100644 drivers/video/savage/Makefile delete mode 100644 drivers/video/savage/savagefb-i2c.c delete mode 100644 drivers/video/savage/savagefb.h delete mode 100644 drivers/video/savage/savagefb_accel.c delete mode 100644 drivers/video/savage/savagefb_driver.c delete mode 100644 drivers/video/sbuslib.c delete mode 100644 drivers/video/sbuslib.h delete mode 100644 drivers/video/sh7760fb.c delete mode 100644 drivers/video/sh_mipi_dsi.c delete mode 100644 drivers/video/sh_mobile_hdmi.c delete mode 100644 drivers/video/sh_mobile_lcdcfb.c delete mode 100644 drivers/video/sh_mobile_lcdcfb.h delete mode 100644 drivers/video/sh_mobile_meram.c delete mode 100644 drivers/video/simplefb.c delete mode 100644 drivers/video/sis/300vtbl.h delete mode 100644 drivers/video/sis/310vtbl.h delete mode 100644 drivers/video/sis/Makefile delete mode 100644 drivers/video/sis/init.c delete mode 100644 drivers/video/sis/init.h delete mode 100644 drivers/video/sis/init301.c delete mode 100644 drivers/video/sis/init301.h delete mode 100644 drivers/video/sis/initdef.h delete mode 100644 drivers/video/sis/initextlfb.c delete mode 100644 drivers/video/sis/oem300.h delete mode 100644 drivers/video/sis/oem310.h delete mode 100644 drivers/video/sis/sis.h delete mode 100644 drivers/video/sis/sis_accel.c delete mode 100644 drivers/video/sis/sis_accel.h delete mode 100644 drivers/video/sis/sis_main.c delete mode 100644 drivers/video/sis/sis_main.h delete mode 100644 drivers/video/sis/vgatypes.h delete mode 100644 drivers/video/sis/vstruct.h delete mode 100644 drivers/video/skeletonfb.c delete mode 100644 drivers/video/sm501fb.c delete mode 100644 drivers/video/smscufx.c delete mode 100644 drivers/video/ssd1307fb.c delete mode 100644 drivers/video/sstfb.c delete mode 100644 drivers/video/sticore.h delete mode 100644 drivers/video/stifb.c delete mode 100644 drivers/video/sunxvr1000.c delete mode 100644 drivers/video/sunxvr2500.c delete mode 100644 drivers/video/sunxvr500.c delete mode 100644 drivers/video/svgalib.c delete mode 100644 drivers/video/syscopyarea.c delete mode 100644 drivers/video/sysfillrect.c delete mode 100644 drivers/video/sysimgblt.c delete mode 100644 drivers/video/tcx.c delete mode 100644 drivers/video/tdfxfb.c delete mode 100644 drivers/video/tgafb.c delete mode 100644 drivers/video/tmiofb.c delete mode 100644 drivers/video/tridentfb.c delete mode 100644 drivers/video/udlfb.c delete mode 100644 drivers/video/uvesafb.c delete mode 100644 drivers/video/valkyriefb.c delete mode 100644 drivers/video/valkyriefb.h delete mode 100644 drivers/video/vermilion/Makefile delete mode 100644 drivers/video/vermilion/cr_pll.c delete mode 100644 drivers/video/vermilion/vermilion.c delete mode 100644 drivers/video/vermilion/vermilion.h delete mode 100644 drivers/video/vesafb.c delete mode 100644 drivers/video/vfb.c delete mode 100644 drivers/video/vga16fb.c delete mode 100644 drivers/video/via/Makefile delete mode 100644 drivers/video/via/accel.c delete mode 100644 drivers/video/via/accel.h delete mode 100644 drivers/video/via/chip.h delete mode 100644 drivers/video/via/debug.h delete mode 100644 drivers/video/via/dvi.c delete mode 100644 drivers/video/via/dvi.h delete mode 100644 drivers/video/via/global.c delete mode 100644 drivers/video/via/global.h delete mode 100644 drivers/video/via/hw.c delete mode 100644 drivers/video/via/hw.h delete mode 100644 drivers/video/via/ioctl.c delete mode 100644 drivers/video/via/ioctl.h delete mode 100644 drivers/video/via/lcd.c delete mode 100644 drivers/video/via/lcd.h delete mode 100644 drivers/video/via/share.h delete mode 100644 drivers/video/via/tblDPASetting.c delete mode 100644 drivers/video/via/tblDPASetting.h delete mode 100644 drivers/video/via/via-core.c delete mode 100644 drivers/video/via/via-gpio.c delete mode 100644 drivers/video/via/via_aux.c delete mode 100644 drivers/video/via/via_aux.h delete mode 100644 drivers/video/via/via_aux_ch7301.c delete mode 100644 drivers/video/via/via_aux_edid.c delete mode 100644 drivers/video/via/via_aux_sii164.c delete mode 100644 drivers/video/via/via_aux_vt1621.c delete mode 100644 drivers/video/via/via_aux_vt1622.c delete mode 100644 drivers/video/via/via_aux_vt1625.c delete mode 100644 drivers/video/via/via_aux_vt1631.c delete mode 100644 drivers/video/via/via_aux_vt1632.c delete mode 100644 drivers/video/via/via_aux_vt1636.c delete mode 100644 drivers/video/via/via_clock.c delete mode 100644 drivers/video/via/via_clock.h delete mode 100644 drivers/video/via/via_i2c.c delete mode 100644 drivers/video/via/via_modesetting.c delete mode 100644 drivers/video/via/via_modesetting.h delete mode 100644 drivers/video/via/via_utility.c delete mode 100644 drivers/video/via/via_utility.h delete mode 100644 drivers/video/via/viafbdev.c delete mode 100644 drivers/video/via/viafbdev.h delete mode 100644 drivers/video/via/viamode.c delete mode 100644 drivers/video/via/viamode.h delete mode 100644 drivers/video/via/vt1636.c delete mode 100644 drivers/video/via/vt1636.h delete mode 100644 drivers/video/vt8500lcdfb.c delete mode 100644 drivers/video/vt8500lcdfb.h delete mode 100644 drivers/video/vt8623fb.c delete mode 100644 drivers/video/w100fb.c delete mode 100644 drivers/video/w100fb.h delete mode 100644 drivers/video/wm8505fb.c delete mode 100644 drivers/video/wm8505fb_regs.h delete mode 100644 drivers/video/wmt_ge_rops.c delete mode 100644 drivers/video/wmt_ge_rops.h delete mode 100644 drivers/video/xen-fbfront.c delete mode 100644 drivers/video/xilinxfb.c (limited to 'drivers') diff --git a/Documentation/DocBook/device-drivers.tmpl b/Documentation/DocBook/device-drivers.tmpl index f5170082bdb..4d1aa8b44be 100644 --- a/Documentation/DocBook/device-drivers.tmpl +++ b/Documentation/DocBook/device-drivers.tmpl @@ -276,7 +276,7 @@ X!Isound/sound_firmware.c Frame Buffer Memory -!Edrivers/video/fbmem.c +!Edrivers/video/fbdev/fbmem.c Frame Buffer Colormap -!Edrivers/video/fbcmap.c +!Edrivers/video/fbdev/fbcmap.c Frame Buffer Video Mode Database -!Idrivers/video/modedb.c -!Edrivers/video/modedb.c +!Idrivers/video/fbdev/modedb.c +!Edrivers/video/fbdev/modedb.c Frame Buffer Macintosh Video Mode Database -!Edrivers/video/macmodes.c +!Edrivers/video/fbdev/macmodes.c Frame Buffer Fonts diff --git a/drivers/Makefile b/drivers/Makefile index e3ced91b178..d05d81b19b5 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -53,8 +53,8 @@ obj-y += gpu/ obj-$(CONFIG_CONNECTOR) += connector/ # i810fb and intelfb depend on char/agp/ -obj-$(CONFIG_FB_I810) += video/i810/ -obj-$(CONFIG_FB_INTEL) += video/intelfb/ +obj-$(CONFIG_FB_I810) += video/fbdev/i810/ +obj-$(CONFIG_FB_INTEL) += video/fbdev/intelfb/ obj-$(CONFIG_PARPORT) += parport/ obj-y += base/ block/ misc/ mfd/ nfc/ diff --git a/drivers/staging/xgifb/vb_def.h b/drivers/staging/xgifb/vb_def.h index 5c739bebd8a..949f0e5eed8 100644 --- a/drivers/staging/xgifb/vb_def.h +++ b/drivers/staging/xgifb/vb_def.h @@ -1,6 +1,6 @@ #ifndef _VB_DEF_ #define _VB_DEF_ -#include "../../video/sis/initdef.h" +#include "../../video/fbdev/sis/initdef.h" #define VB_XGI301C 0x0020 /* for 301C */ diff --git a/drivers/staging/xgifb/vb_struct.h b/drivers/staging/xgifb/vb_struct.h index c08ff5b2d6e..0d27594554c 100644 --- a/drivers/staging/xgifb/vb_struct.h +++ b/drivers/staging/xgifb/vb_struct.h @@ -1,6 +1,6 @@ #ifndef _VB_STRUCT_ #define _VB_STRUCT_ -#include "../../video/sis/vstruct.h" +#include "../../video/fbdev/sis/vstruct.h" struct XGI_LVDSCRT1HDataStruct { unsigned char Reg[8]; diff --git a/drivers/staging/xgifb/vgatypes.h b/drivers/staging/xgifb/vgatypes.h index ddf7776c295..264351441f9 100644 --- a/drivers/staging/xgifb/vgatypes.h +++ b/drivers/staging/xgifb/vgatypes.h @@ -2,8 +2,8 @@ #define _VGATYPES_ #include /* for struct fb_var_screeninfo for sis.h */ -#include "../../video/sis/vgatypes.h" -#include "../../video/sis/sis.h" /* for LCD_TYPE */ +#include "../../video/fbdev/sis/vgatypes.h" +#include "../../video/fbdev/sis/sis.h" /* for LCD_TYPE */ #ifndef XGI_VB_CHIP_TYPE enum XGI_VB_CHIP_TYPE { diff --git a/drivers/video/68328fb.c b/drivers/video/68328fb.c deleted file mode 100644 index 552258c8f99..00000000000 --- a/drivers/video/68328fb.c +++ /dev/null @@ -1,503 +0,0 @@ -/* - * linux/drivers/video/68328fb.c -- Low level implementation of the - * mc68x328 LCD frame buffer device - * - * Copyright (C) 2003 Georges Menie - * - * This driver assumes an already configured controller (e.g. from config.c) - * Keep the code clean of board specific initialization. - * - * This code has not been tested with colors, colormap management functions - * are minimal (no colormap data written to the 68328 registers...) - * - * initial version of this driver: - * Copyright (C) 1998,1999 Kenneth Albanowski , - * The Silver Hammer Group, Ltd. - * - * this version is based on : - * - * linux/drivers/video/vfb.c -- Virtual frame buffer device - * - * Copyright (C) 2002 James Simmons - * - * Copyright (C) 1997 Geert Uytterhoeven - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive for - * more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(CONFIG_M68VZ328) -#include -#elif defined(CONFIG_M68EZ328) -#include -#elif defined(CONFIG_M68328) -#include -#else -#error wrong architecture for the MC68x328 frame buffer device -#endif - -#if defined(CONFIG_FB_68328_INVERT) -#define MC68X328FB_MONO_VISUAL FB_VISUAL_MONO01 -#else -#define MC68X328FB_MONO_VISUAL FB_VISUAL_MONO10 -#endif - -static u_long videomemory; -static u_long videomemorysize; - -static struct fb_info fb_info; -static u32 mc68x328fb_pseudo_palette[16]; - -static struct fb_var_screeninfo mc68x328fb_default __initdata = { - .red = { 0, 8, 0 }, - .green = { 0, 8, 0 }, - .blue = { 0, 8, 0 }, - .activate = FB_ACTIVATE_TEST, - .height = -1, - .width = -1, - .pixclock = 20000, - .left_margin = 64, - .right_margin = 64, - .upper_margin = 32, - .lower_margin = 32, - .hsync_len = 64, - .vsync_len = 2, - .vmode = FB_VMODE_NONINTERLACED, -}; - -static struct fb_fix_screeninfo mc68x328fb_fix __initdata = { - .id = "68328fb", - .type = FB_TYPE_PACKED_PIXELS, - .xpanstep = 1, - .ypanstep = 1, - .ywrapstep = 1, - .accel = FB_ACCEL_NONE, -}; - - /* - * Interface used by the world - */ -int mc68x328fb_init(void); -int mc68x328fb_setup(char *); - -static int mc68x328fb_check_var(struct fb_var_screeninfo *var, - struct fb_info *info); -static int mc68x328fb_set_par(struct fb_info *info); -static int mc68x328fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int transp, struct fb_info *info); -static int mc68x328fb_pan_display(struct fb_var_screeninfo *var, - struct fb_info *info); -static int mc68x328fb_mmap(struct fb_info *info, struct vm_area_struct *vma); - -static struct fb_ops mc68x328fb_ops = { - .fb_check_var = mc68x328fb_check_var, - .fb_set_par = mc68x328fb_set_par, - .fb_setcolreg = mc68x328fb_setcolreg, - .fb_pan_display = mc68x328fb_pan_display, - .fb_fillrect = cfb_fillrect, - .fb_copyarea = cfb_copyarea, - .fb_imageblit = cfb_imageblit, - .fb_mmap = mc68x328fb_mmap, -}; - - /* - * Internal routines - */ - -static u_long get_line_length(int xres_virtual, int bpp) -{ - u_long length; - - length = xres_virtual * bpp; - length = (length + 31) & ~31; - length >>= 3; - return (length); -} - - /* - * Setting the video mode has been split into two parts. - * First part, xxxfb_check_var, must not write anything - * to hardware, it should only verify and adjust var. - * This means it doesn't alter par but it does use hardware - * data from it to check this var. - */ - -static int mc68x328fb_check_var(struct fb_var_screeninfo *var, - struct fb_info *info) -{ - u_long line_length; - - /* - * FB_VMODE_CONUPDATE and FB_VMODE_SMOOTH_XPAN are equal! - * as FB_VMODE_SMOOTH_XPAN is only used internally - */ - - if (var->vmode & FB_VMODE_CONUPDATE) { - var->vmode |= FB_VMODE_YWRAP; - var->xoffset = info->var.xoffset; - var->yoffset = info->var.yoffset; - } - - /* - * Some very basic checks - */ - if (!var->xres) - var->xres = 1; - if (!var->yres) - var->yres = 1; - if (var->xres > var->xres_virtual) - var->xres_virtual = var->xres; - if (var->yres > var->yres_virtual) - var->yres_virtual = var->yres; - if (var->bits_per_pixel <= 1) - var->bits_per_pixel = 1; - else if (var->bits_per_pixel <= 8) - var->bits_per_pixel = 8; - else if (var->bits_per_pixel <= 16) - var->bits_per_pixel = 16; - else if (var->bits_per_pixel <= 24) - var->bits_per_pixel = 24; - else if (var->bits_per_pixel <= 32) - var->bits_per_pixel = 32; - else - return -EINVAL; - - if (var->xres_virtual < var->xoffset + var->xres) - var->xres_virtual = var->xoffset + var->xres; - if (var->yres_virtual < var->yoffset + var->yres) - var->yres_virtual = var->yoffset + var->yres; - - /* - * Memory limit - */ - line_length = - get_line_length(var->xres_virtual, var->bits_per_pixel); - if (line_length * var->yres_virtual > videomemorysize) - return -ENOMEM; - - /* - * Now that we checked it we alter var. The reason being is that the video - * mode passed in might not work but slight changes to it might make it - * work. This way we let the user know what is acceptable. - */ - switch (var->bits_per_pixel) { - case 1: - var->red.offset = 0; - var->red.length = 1; - var->green.offset = 0; - var->green.length = 1; - var->blue.offset = 0; - var->blue.length = 1; - var->transp.offset = 0; - var->transp.length = 0; - break; - case 8: - var->red.offset = 0; - var->red.length = 8; - var->green.offset = 0; - var->green.length = 8; - var->blue.offset = 0; - var->blue.length = 8; - var->transp.offset = 0; - var->transp.length = 0; - break; - case 16: /* RGBA 5551 */ - if (var->transp.length) { - var->red.offset = 0; - var->red.length = 5; - var->green.offset = 5; - var->green.length = 5; - var->blue.offset = 10; - var->blue.length = 5; - var->transp.offset = 15; - var->transp.length = 1; - } else { /* RGB 565 */ - var->red.offset = 0; - var->red.length = 5; - var->green.offset = 5; - var->green.length = 6; - var->blue.offset = 11; - var->blue.length = 5; - var->transp.offset = 0; - var->transp.length = 0; - } - break; - case 24: /* RGB 888 */ - var->red.offset = 0; - var->red.length = 8; - var->green.offset = 8; - var->green.length = 8; - var->blue.offset = 16; - var->blue.length = 8; - var->transp.offset = 0; - var->transp.length = 0; - break; - case 32: /* RGBA 8888 */ - var->red.offset = 0; - var->red.length = 8; - var->green.offset = 8; - var->green.length = 8; - var->blue.offset = 16; - var->blue.length = 8; - var->transp.offset = 24; - var->transp.length = 8; - break; - } - var->red.msb_right = 0; - var->green.msb_right = 0; - var->blue.msb_right = 0; - var->transp.msb_right = 0; - - return 0; -} - -/* This routine actually sets the video mode. It's in here where we - * the hardware state info->par and fix which can be affected by the - * change in par. For this driver it doesn't do much. - */ -static int mc68x328fb_set_par(struct fb_info *info) -{ - info->fix.line_length = get_line_length(info->var.xres_virtual, - info->var.bits_per_pixel); - return 0; -} - - /* - * Set a single color register. The values supplied are already - * rounded down to the hardware's capabilities (according to the - * entries in the var structure). Return != 0 for invalid regno. - */ - -static int mc68x328fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int transp, struct fb_info *info) -{ - if (regno >= 256) /* no. of hw registers */ - return 1; - /* - * Program hardware... do anything you want with transp - */ - - /* grayscale works only partially under directcolor */ - if (info->var.grayscale) { - /* grayscale = 0.30*R + 0.59*G + 0.11*B */ - red = green = blue = - (red * 77 + green * 151 + blue * 28) >> 8; - } - - /* Directcolor: - * var->{color}.offset contains start of bitfield - * var->{color}.length contains length of bitfield - * {hardwarespecific} contains width of RAMDAC - * cmap[X] is programmed to (X << red.offset) | (X << green.offset) | (X << blue.offset) - * RAMDAC[X] is programmed to (red, green, blue) - * - * Pseudocolor: - * uses offset = 0 && length = RAMDAC register width. - * var->{color}.offset is 0 - * var->{color}.length contains width of DAC - * cmap is not used - * RAMDAC[X] is programmed to (red, green, blue) - * Truecolor: - * does not use DAC. Usually 3 are present. - * var->{color}.offset contains start of bitfield - * var->{color}.length contains length of bitfield - * cmap is programmed to (red << red.offset) | (green << green.offset) | - * (blue << blue.offset) | (transp << transp.offset) - * RAMDAC does not exist - */ -#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16) - switch (info->fix.visual) { - case FB_VISUAL_TRUECOLOR: - case FB_VISUAL_PSEUDOCOLOR: - red = CNVT_TOHW(red, info->var.red.length); - green = CNVT_TOHW(green, info->var.green.length); - blue = CNVT_TOHW(blue, info->var.blue.length); - transp = CNVT_TOHW(transp, info->var.transp.length); - break; - case FB_VISUAL_DIRECTCOLOR: - red = CNVT_TOHW(red, 8); /* expect 8 bit DAC */ - green = CNVT_TOHW(green, 8); - blue = CNVT_TOHW(blue, 8); - /* hey, there is bug in transp handling... */ - transp = CNVT_TOHW(transp, 8); - break; - } -#undef CNVT_TOHW - /* Truecolor has hardware independent palette */ - if (info->fix.visual == FB_VISUAL_TRUECOLOR) { - u32 v; - - if (regno >= 16) - return 1; - - v = (red << info->var.red.offset) | - (green << info->var.green.offset) | - (blue << info->var.blue.offset) | - (transp << info->var.transp.offset); - switch (info->var.bits_per_pixel) { - case 8: - break; - case 16: - ((u32 *) (info->pseudo_palette))[regno] = v; - break; - case 24: - case 32: - ((u32 *) (info->pseudo_palette))[regno] = v; - break; - } - return 0; - } - return 0; -} - - /* - * Pan or Wrap the Display - * - * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag - */ - -static int mc68x328fb_pan_display(struct fb_var_screeninfo *var, - struct fb_info *info) -{ - if (var->vmode & FB_VMODE_YWRAP) { - if (var->yoffset < 0 - || var->yoffset >= info->var.yres_virtual - || var->xoffset) - return -EINVAL; - } else { - if (var->xoffset + info->var.xres > info->var.xres_virtual || - var->yoffset + info->var.yres > info->var.yres_virtual) - return -EINVAL; - } - info->var.xoffset = var->xoffset; - info->var.yoffset = var->yoffset; - if (var->vmode & FB_VMODE_YWRAP) - info->var.vmode |= FB_VMODE_YWRAP; - else - info->var.vmode &= ~FB_VMODE_YWRAP; - return 0; -} - - /* - * Most drivers don't need their own mmap function - */ - -static int mc68x328fb_mmap(struct fb_info *info, struct vm_area_struct *vma) -{ -#ifndef MMU - /* this is uClinux (no MMU) specific code */ - - vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP; - vma->vm_start = videomemory; - - return 0; -#else - return -EINVAL; -#endif -} - -int __init mc68x328fb_setup(char *options) -{ -#if 0 - char *this_opt; -#endif - - if (!options || !*options) - return 1; -#if 0 - while ((this_opt = strsep(&options, ",")) != NULL) { - if (!*this_opt) - continue; - if (!strncmp(this_opt, "disable", 7)) - mc68x328fb_enable = 0; - } -#endif - return 1; -} - - /* - * Initialisation - */ - -int __init mc68x328fb_init(void) -{ -#ifndef MODULE - char *option = NULL; - - if (fb_get_options("68328fb", &option)) - return -ENODEV; - mc68x328fb_setup(option); -#endif - /* - * initialize the default mode from the LCD controller registers - */ - mc68x328fb_default.xres = LXMAX; - mc68x328fb_default.yres = LYMAX+1; - mc68x328fb_default.xres_virtual = mc68x328fb_default.xres; - mc68x328fb_default.yres_virtual = mc68x328fb_default.yres; - mc68x328fb_default.bits_per_pixel = 1 + (LPICF & 0x01); - videomemory = LSSA; - videomemorysize = (mc68x328fb_default.xres_virtual+7) / 8 * - mc68x328fb_default.yres_virtual * mc68x328fb_default.bits_per_pixel; - - fb_info.screen_base = (void *)videomemory; - fb_info.fbops = &mc68x328fb_ops; - fb_info.var = mc68x328fb_default; - fb_info.fix = mc68x328fb_fix; - fb_info.fix.smem_start = videomemory; - fb_info.fix.smem_len = videomemorysize; - fb_info.fix.line_length = - get_line_length(mc68x328fb_default.xres_virtual, mc68x328fb_default.bits_per_pixel); - fb_info.fix.visual = (mc68x328fb_default.bits_per_pixel) == 1 ? - MC68X328FB_MONO_VISUAL : FB_VISUAL_PSEUDOCOLOR; - if (fb_info.var.bits_per_pixel == 1) { - fb_info.var.red.length = fb_info.var.green.length = fb_info.var.blue.length = 1; - fb_info.var.red.offset = fb_info.var.green.offset = fb_info.var.blue.offset = 0; - } - fb_info.pseudo_palette = &mc68x328fb_pseudo_palette; - fb_info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; - - if (fb_alloc_cmap(&fb_info.cmap, 256, 0)) - return -ENOMEM; - - if (register_framebuffer(&fb_info) < 0) { - fb_dealloc_cmap(&fb_info.cmap); - return -EINVAL; - } - - fb_info(&fb_info, "%s frame buffer device\n", fb_info.fix.id); - fb_info(&fb_info, "%dx%dx%d at 0x%08lx\n", - mc68x328fb_default.xres_virtual, - mc68x328fb_default.yres_virtual, - 1 << mc68x328fb_default.bits_per_pixel, videomemory); - - return 0; -} - -module_init(mc68x328fb_init); - -#ifdef MODULE - -static void __exit mc68x328fb_cleanup(void) -{ - unregister_framebuffer(&fb_info); - fb_dealloc_cmap(&fb_info.cmap); -} - -module_exit(mc68x328fb_cleanup); - -MODULE_LICENSE("GPL"); -#endif /* MODULE */ diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 3ad7ebe2a96..ab05d6cb079 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -23,6 +23,10 @@ source "drivers/gpu/host1x/Kconfig" source "drivers/gpu/drm/Kconfig" +source "drivers/video/fbdev/Kconfig" + +source "drivers/video/backlight/Kconfig" + config VGASTATE tristate default n @@ -33,2484 +37,14 @@ config VIDEOMODE_HELPERS config HDMI bool -menuconfig FB - tristate "Support for frame buffer devices" - ---help--- - The frame buffer device provides an abstraction for the graphics - hardware. It represents the frame buffer of some video hardware and - allows application software to access the graphics hardware through - a well-defined interface, so the software doesn't need to know - anything about the low-level (hardware register) stuff. - - Frame buffer devices work identically across the different - architectures supported by Linux and make the implementation of - application programs easier and more portable; at this point, an X - server exists which uses the frame buffer device exclusively. - On several non-X86 architectures, the frame buffer device is the - only way to use the graphics hardware. - - The device is accessed through special device nodes, usually located - in the /dev directory, i.e. /dev/fb*. - - You need an utility program called fbset to make full use of frame - buffer devices. Please read - and the Framebuffer-HOWTO at - for more - information. - - Say Y here and to the driver for your graphics board below if you - are compiling a kernel for a non-x86 architecture. - - If you are compiling for the x86 architecture, you can say Y if you - want to play with it, but it is not essential. Please note that - running graphical applications that directly touch the hardware - (e.g. an accelerated X server) and that are not frame buffer - device-aware may cause unexpected results. If unsure, say N. - -config FIRMWARE_EDID - bool "Enable firmware EDID" - depends on FB - default n - ---help--- - This enables access to the EDID transferred from the firmware. - On the i386, this is from the Video BIOS. Enable this if DDC/I2C - transfers do not work for your driver and if you are using - nvidiafb, i810fb or savagefb. - - In general, choosing Y for this option is safe. If you - experience extremely long delays while booting before you get - something on your display, try setting this to N. Matrox cards in - combination with certain motherboards and monitors are known to - suffer from this problem. - -config FB_DDC - tristate - depends on FB - select I2C_ALGOBIT - select I2C - default n - -config FB_BOOT_VESA_SUPPORT - bool - depends on FB - default n - ---help--- - If true, at least one selected framebuffer driver can take advantage - of VESA video modes set at an early boot stage via the vga= parameter. - -config FB_CFB_FILLRECT - tristate - depends on FB - default n - ---help--- - Include the cfb_fillrect function for generic software rectangle - filling. This is used by drivers that don't provide their own - (accelerated) version. - -config FB_CFB_COPYAREA - tristate - depends on FB - default n - ---help--- - Include the cfb_copyarea function for generic software area copying. - This is used by drivers that don't provide their own (accelerated) - version. - -config FB_CFB_IMAGEBLIT - tristate - depends on FB - default n - ---help--- - Include the cfb_imageblit function for generic software image - blitting. This is used by drivers that don't provide their own - (accelerated) version. - -config FB_CFB_REV_PIXELS_IN_BYTE - bool - depends on FB - default n - ---help--- - Allow generic frame-buffer functions to work on displays with 1, 2 - and 4 bits per pixel depths which has opposite order of pixels in - byte order to bytes in long order. - -config FB_SYS_FILLRECT - tristate - depends on FB - default n - ---help--- - Include the sys_fillrect function for generic software rectangle - filling. This is used by drivers that don't provide their own - (accelerated) version and the framebuffer is in system RAM. - -config FB_SYS_COPYAREA - tristate - depends on FB - default n - ---help--- - Include the sys_copyarea function for generic software area copying. - This is used by drivers that don't provide their own (accelerated) - version and the framebuffer is in system RAM. - -config FB_SYS_IMAGEBLIT - tristate - depends on FB - default n - ---help--- - Include the sys_imageblit function for generic software image - blitting. This is used by drivers that don't provide their own - (accelerated) version and the framebuffer is in system RAM. - -menuconfig FB_FOREIGN_ENDIAN - bool "Framebuffer foreign endianness support" - depends on FB - ---help--- - This menu will let you enable support for the framebuffers with - non-native endianness (e.g. Little-Endian framebuffer on a - Big-Endian machine). Most probably you don't have such hardware, - so it's safe to say "n" here. - -choice - prompt "Choice endianness support" - depends on FB_FOREIGN_ENDIAN - -config FB_BOTH_ENDIAN - bool "Support for Big- and Little-Endian framebuffers" - -config FB_BIG_ENDIAN - bool "Support for Big-Endian framebuffers only" - -config FB_LITTLE_ENDIAN - bool "Support for Little-Endian framebuffers only" - -endchoice - -config FB_SYS_FOPS - tristate - depends on FB - default n - -config FB_DEFERRED_IO - bool - depends on FB - -config FB_HECUBA - tristate - depends on FB - depends on FB_DEFERRED_IO - -config FB_SVGALIB - tristate - depends on FB - default n - ---help--- - Common utility functions useful to fbdev drivers of VGA-based - cards. - -config FB_MACMODES - tristate - depends on FB - default n - -config FB_BACKLIGHT - bool - depends on FB - select BACKLIGHT_LCD_SUPPORT - select BACKLIGHT_CLASS_DEVICE - default n - -config FB_MODE_HELPERS - bool "Enable Video Mode Handling Helpers" - depends on FB - default n - ---help--- - This enables functions for handling video modes using the - Generalized Timing Formula and the EDID parser. A few drivers rely - on this feature such as the radeonfb, rivafb, and the i810fb. If - your driver does not take advantage of this feature, choosing Y will - just increase the kernel size by about 5K. - -config FB_TILEBLITTING - bool "Enable Tile Blitting Support" - depends on FB - default n - ---help--- - This enables tile blitting. Tile blitting is a drawing technique - where the screen is divided into rectangular sections (tiles), whereas - the standard blitting divides the screen into pixels. Because the - default drawing element is a tile, drawing functions will be passed - parameters in terms of number of tiles instead of number of pixels. - For example, to draw a single character, instead of using bitmaps, - an index to an array of bitmaps will be used. To clear or move a - rectangular section of a screen, the rectangle will be described in - terms of number of tiles in the x- and y-axis. - - This is particularly important to one driver, matroxfb. If - unsure, say N. - -comment "Frame buffer hardware drivers" - depends on FB - -config FB_GRVGA - tristate "Aeroflex Gaisler framebuffer support" - depends on FB && SPARC - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - ---help--- - This enables support for the SVGACTRL framebuffer in the GRLIB IP library from Aeroflex Gaisler. - -config FB_CIRRUS - tristate "Cirrus Logic support" - depends on FB && (ZORRO || PCI) - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - ---help--- - This enables support for Cirrus Logic GD542x/543x based boards on - Amiga: SD64, Piccolo, Picasso II/II+, Picasso IV, or EGS Spectrum. - - If you have a PCI-based system, this enables support for these - chips: GD-543x, GD-544x, GD-5480. - - Please read the file . - - Say N unless you have such a graphics board or plan to get one - before you next recompile the kernel. - -config FB_PM2 - tristate "Permedia2 support" - depends on FB && ((AMIGA && BROKEN) || PCI) - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This is the frame buffer device driver for cards based on - the 3D Labs Permedia, Permedia 2 and Permedia 2V chips. - The driver was tested on the following cards: - Diamond FireGL 1000 PRO AGP - ELSA Gloria Synergy PCI - Appian Jeronimo PRO (both heads) PCI - 3DLabs Oxygen ACX aka EONtronics Picasso P2 PCI - Techsource Raptor GFX-8P (aka Sun PGX-32) on SPARC - ASK Graphic Blaster Exxtreme AGP - - To compile this driver as a module, choose M here: the - module will be called pm2fb. - -config FB_PM2_FIFO_DISCONNECT - bool "enable FIFO disconnect feature" - depends on FB_PM2 && PCI - help - Support the Permedia2 FIFO disconnect feature. - -config FB_ARMCLCD - tristate "ARM PrimeCell PL110 support" - depends on ARM || ARM64 || COMPILE_TEST - depends on FB && ARM_AMBA - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This framebuffer device driver is for the ARM PrimeCell PL110 - Colour LCD controller. ARM PrimeCells provide the building - blocks for System on a Chip devices. - - If you want to compile this as a module (=code which can be - inserted into and removed from the running kernel), say M - here and read . The module - will be called amba-clcd. - -config FB_ACORN - bool "Acorn VIDC support" - depends on (FB = y) && ARM && ARCH_ACORN - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This is the frame buffer device driver for the Acorn VIDC graphics - hardware found in Acorn RISC PCs and other ARM-based machines. If - unsure, say N. - -config FB_CLPS711X - bool "CLPS711X LCD support" - depends on (FB = y) && ARM && ARCH_CLPS711X - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - Say Y to enable the Framebuffer driver for the CLPS7111 and - EP7212 processors. - -config FB_SA1100 - bool "SA-1100 LCD support" - depends on (FB = y) && ARM && ARCH_SA1100 - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This is a framebuffer device for the SA-1100 LCD Controller. - See for information on framebuffer - devices. - - If you plan to use the LCD display with your SA-1100 system, say - Y here. - -config FB_IMX - tristate "Freescale i.MX1/21/25/27 LCD support" - depends on FB && ARCH_MXC - select BACKLIGHT_LCD_SUPPORT - select LCD_CLASS_DEVICE - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select FB_MODE_HELPERS - select VIDEOMODE_HELPERS - -config FB_CYBER2000 - tristate "CyberPro 2000/2010/5000 support" - depends on FB && PCI && (BROKEN || !SPARC64) - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This enables support for the Integraphics CyberPro 20x0 and 5000 - VGA chips used in the Rebel.com Netwinder and other machines. - Say Y if you have a NetWinder or a graphics card containing this - device, otherwise say N. - -config FB_CYBER2000_DDC - bool "DDC for CyberPro support" - depends on FB_CYBER2000 - select FB_DDC - default y - help - Say Y here if you want DDC support for your CyberPro graphics - card. This is only I2C bus support, driver does not use EDID. - -config FB_CYBER2000_I2C - bool "CyberPro 2000/2010/5000 I2C support" - depends on FB_CYBER2000 && I2C && ARCH_NETWINDER - select I2C_ALGOBIT - help - Enable support for the I2C video decoder interface on the - Integraphics CyberPro 20x0 and 5000 VGA chips. This is used - on the Netwinder machines for the SAA7111 video capture. - -config FB_APOLLO - bool - depends on (FB = y) && APOLLO - default y - select FB_CFB_FILLRECT - select FB_CFB_IMAGEBLIT - -config FB_Q40 - bool - depends on (FB = y) && Q40 - default y - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - -config FB_AMIGA - tristate "Amiga native chipset support" - depends on FB && AMIGA - help - This is the frame buffer device driver for the builtin graphics - chipset found in Amigas. - - To compile this driver as a module, choose M here: the - module will be called amifb. - -config FB_AMIGA_OCS - bool "Amiga OCS chipset support" - depends on FB_AMIGA - help - This enables support for the original Agnus and Denise video chips, - found in the Amiga 1000 and most A500's and A2000's. If you intend - to run Linux on any of these systems, say Y; otherwise say N. - -config FB_AMIGA_ECS - bool "Amiga ECS chipset support" - depends on FB_AMIGA - help - This enables support for the Enhanced Chip Set, found in later - A500's, later A2000's, the A600, the A3000, the A3000T and CDTV. If - you intend to run Linux on any of these systems, say Y; otherwise - say N. - -config FB_AMIGA_AGA - bool "Amiga AGA chipset support" - depends on FB_AMIGA - help - This enables support for the Advanced Graphics Architecture (also - known as the AGA or AA) Chip Set, found in the A1200, A4000, A4000T - and CD32. If you intend to run Linux on any of these systems, say Y; - otherwise say N. - -config FB_FM2 - bool "Amiga FrameMaster II/Rainbow II support" - depends on (FB = y) && ZORRO - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This is the frame buffer device driver for the Amiga FrameMaster - card from BSC (exhibited 1992 but not shipped as a CBM product). - -config FB_ARC - tristate "Arc Monochrome LCD board support" - depends on FB && X86 - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT - select FB_SYS_FOPS - help - This enables support for the Arc Monochrome LCD board. The board - is based on the KS-108 lcd controller and is typically a matrix - of 2*n chips. This driver was tested with a 128x64 panel. This - driver supports it for use with x86 SBCs through a 16 bit GPIO - interface (8 bit data, 8 bit control). If you anticipate using - this driver, say Y or M; otherwise say N. You must specify the - GPIO IO address to be used for setting control and data. - -config FB_ATARI - bool "Atari native chipset support" - depends on (FB = y) && ATARI - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This is the frame buffer device driver for the builtin graphics - chipset found in Ataris. - -config FB_OF - bool "Open Firmware frame buffer device support" - depends on (FB = y) && (PPC64 || PPC_OF) && (!PPC_PSERIES || PCI) - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select FB_MACMODES - help - Say Y if you want support with Open Firmware for your graphics - board. - -config FB_CONTROL - bool "Apple \"control\" display support" - depends on (FB = y) && PPC_PMAC && PPC32 - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select FB_MACMODES - help - This driver supports a frame buffer for the graphics adapter in the - Power Macintosh 7300 and others. - -config FB_PLATINUM - bool "Apple \"platinum\" display support" - depends on (FB = y) && PPC_PMAC && PPC32 - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select FB_MACMODES - help - This driver supports a frame buffer for the "platinum" graphics - adapter in some Power Macintoshes. - -config FB_VALKYRIE - bool "Apple \"valkyrie\" display support" - depends on (FB = y) && (MAC || (PPC_PMAC && PPC32)) - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select FB_MACMODES - help - This driver supports a frame buffer for the "valkyrie" graphics - adapter in some Power Macintoshes. - -config FB_CT65550 - bool "Chips 65550 display support" - depends on (FB = y) && PPC32 && PCI - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This is the frame buffer device driver for the Chips & Technologies - 65550 graphics chip in PowerBooks. - -config FB_ASILIANT - bool "Asiliant (Chips) 69000 display support" - depends on (FB = y) && PCI - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This is the frame buffer device driver for the Asiliant 69030 chipset - -config FB_IMSTT - bool "IMS Twin Turbo display support" - depends on (FB = y) && PCI - select FB_CFB_IMAGEBLIT - select FB_MACMODES if PPC - help - The IMS Twin Turbo is a PCI-based frame buffer card bundled with - many Macintosh and compatible computers. - -config FB_VGA16 - tristate "VGA 16-color graphics support" - depends on FB && (X86 || PPC) - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select VGASTATE - select FONT_8x16 if FRAMEBUFFER_CONSOLE - help - This is the frame buffer device driver for VGA 16 color graphic - cards. Say Y if you have such a card. - - To compile this driver as a module, choose M here: the - module will be called vga16fb. - -config FB_BF54X_LQ043 - tristate "SHARP LQ043 TFT LCD (BF548 EZKIT)" - depends on FB && (BF54x) && !BF542 - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This is the framebuffer device driver for a SHARP LQ043T1DG01 TFT LCD - -config FB_BFIN_T350MCQB - tristate "Varitronix COG-T350MCQB TFT LCD display (BF527 EZKIT)" - depends on FB && BLACKFIN - select BFIN_GPTIMERS - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This is the framebuffer device driver for a Varitronix VL-PS-COG-T350MCQB-01 display TFT LCD - This display is a QVGA 320x240 24-bit RGB display interfaced by an 8-bit wide PPI - It uses PPI[0..7] PPI_FS1, PPI_FS2 and PPI_CLK. - -config FB_BFIN_LQ035Q1 - tristate "SHARP LQ035Q1DH02 TFT LCD" - depends on FB && BLACKFIN && SPI - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select BFIN_GPTIMERS - help - This is the framebuffer device driver for a SHARP LQ035Q1DH02 TFT display found on - the Blackfin Landscape LCD EZ-Extender Card. - This display is a QVGA 320x240 18-bit RGB display interfaced by an 16-bit wide PPI - It uses PPI[0..15] PPI_FS1, PPI_FS2 and PPI_CLK. - - To compile this driver as a module, choose M here: the - module will be called bfin-lq035q1-fb. - -config FB_BF537_LQ035 - tristate "SHARP LQ035 TFT LCD (BF537 STAMP)" - depends on FB && (BF534 || BF536 || BF537) && I2C_BLACKFIN_TWI - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select BFIN_GPTIMERS - help - This is the framebuffer device for a SHARP LQ035Q7DB03 TFT LCD - attached to a BF537. - - To compile this driver as a module, choose M here: the - module will be called bf537-lq035. - -config FB_BFIN_7393 - tristate "Blackfin ADV7393 Video encoder" - depends on FB && BLACKFIN - select I2C - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This is the framebuffer device for a ADV7393 video encoder - attached to a Blackfin on the PPI port. - If your Blackfin board has a ADV7393 select Y. - - To compile this driver as a module, choose M here: the - module will be called bfin_adv7393fb. - -choice - prompt "Video mode support" - depends on FB_BFIN_7393 - default NTSC - -config NTSC - bool 'NTSC 720x480' - -config PAL - bool 'PAL 720x576' - -config NTSC_640x480 - bool 'NTSC 640x480 (Experimental)' - -config PAL_640x480 - bool 'PAL 640x480 (Experimental)' - -config NTSC_YCBCR - bool 'NTSC 720x480 YCbCR input' - -config PAL_YCBCR - bool 'PAL 720x576 YCbCR input' - -endchoice - -choice - prompt "Size of ADV7393 frame buffer memory Single/Double Size" - depends on (FB_BFIN_7393) - default ADV7393_1XMEM - -config ADV7393_1XMEM - bool 'Single' - -config ADV7393_2XMEM - bool 'Double' -endchoice - -config FB_STI - tristate "HP STI frame buffer device support" - depends on FB && PARISC - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select STI_CONSOLE - select VT - default y - ---help--- - STI refers to the HP "Standard Text Interface" which is a set of - BIOS routines contained in a ROM chip in HP PA-RISC based machines. - Enabling this option will implement the linux framebuffer device - using calls to the STI BIOS routines for initialisation. - - If you enable this option, you will get a planar framebuffer device - /dev/fb which will work on the most common HP graphic cards of the - NGLE family, including the artist chips (in the 7xx and Bxxx series), - HCRX, HCRX24, CRX, CRX24 and VisEG series. - - It is safe to enable this option, so you should probably say "Y". - -config FB_MAC - bool "Generic Macintosh display support" - depends on (FB = y) && MAC - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select FB_MACMODES - -config FB_HP300 - bool - depends on (FB = y) && DIO - select FB_CFB_IMAGEBLIT - default y - -config FB_TGA - tristate "TGA/SFB+ framebuffer support" - depends on FB && (ALPHA || TC) - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select BITREVERSE - ---help--- - This is the frame buffer device driver for generic TGA and SFB+ - graphic cards. These include DEC ZLXp-E1, -E2 and -E3 PCI cards, - also known as PBXGA-A, -B and -C, and DEC ZLX-E1, -E2 and -E3 - TURBOchannel cards, also known as PMAGD-A, -B and -C. - - Due to hardware limitations ZLX-E2 and E3 cards are not supported - for DECstation 5000/200 systems. Additionally due to firmware - limitations these cards may cause troubles with booting DECstation - 5000/240 and /260 systems, but are fully supported under Linux if - you manage to get it going. ;-) - - Say Y if you have one of those. - -config FB_UVESA - tristate "Userspace VESA VGA graphics support" - depends on FB && CONNECTOR - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select FB_MODE_HELPERS - help - This is the frame buffer driver for generic VBE 2.0 compliant - graphic cards. It can also take advantage of VBE 3.0 features, - such as refresh rate adjustment. - - This driver generally provides more features than vesafb but - requires a userspace helper application called 'v86d'. See - for more information. - - If unsure, say N. - -config FB_VESA - bool "VESA VGA graphics support" - depends on (FB = y) && X86 - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select FB_BOOT_VESA_SUPPORT - help - This is the frame buffer device driver for generic VESA 2.0 - compliant graphic cards. The older VESA 1.2 cards are not supported. - You will get a boot time penguin logo at no additional cost. Please - read . If unsure, say Y. - -config FB_EFI - bool "EFI-based Framebuffer Support" - depends on (FB = y) && X86 && EFI - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This is the EFI frame buffer device driver. If the firmware on - your platform is EFI 1.10 or UEFI 2.0, select Y to add support for - using the EFI framebuffer as your console. - -config FB_N411 - tristate "N411 Apollo/Hecuba devkit support" - depends on FB && X86 && MMU - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT - select FB_SYS_FOPS - select FB_DEFERRED_IO - select FB_HECUBA - help - This enables support for the Apollo display controller in its - Hecuba form using the n411 devkit. - -config FB_HGA - tristate "Hercules mono graphics support" - depends on FB && X86 - help - Say Y here if you have a Hercules mono graphics card. - - To compile this driver as a module, choose M here: the - module will be called hgafb. - - As this card technology is at least 25 years old, - most people will answer N here. - -config FB_GBE - bool "SGI Graphics Backend frame buffer support" - depends on (FB = y) && SGI_IP32 - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This is the frame buffer device driver for SGI Graphics Backend. - This chip is used in SGI O2 and Visual Workstation 320/540. - -config FB_GBE_MEM - int "Video memory size in MB" - depends on FB_GBE - default 4 - help - This is the amount of memory reserved for the framebuffer, - which can be any value between 1MB and 8MB. - -config FB_SBUS - bool "SBUS and UPA framebuffers" - depends on (FB = y) && SPARC - help - Say Y if you want support for SBUS or UPA based frame buffer device. - -config FB_BW2 - bool "BWtwo support" - depends on (FB = y) && (SPARC && FB_SBUS) - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This is the frame buffer device driver for the BWtwo frame buffer. - -config FB_CG3 - bool "CGthree support" - depends on (FB = y) && (SPARC && FB_SBUS) - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This is the frame buffer device driver for the CGthree frame buffer. - -config FB_CG6 - bool "CGsix (GX,TurboGX) support" - depends on (FB = y) && (SPARC && FB_SBUS) - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This is the frame buffer device driver for the CGsix (GX, TurboGX) - frame buffer. - -config FB_FFB - bool "Creator/Creator3D/Elite3D support" - depends on FB_SBUS && SPARC64 - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This is the frame buffer device driver for the Creator, Creator3D, - and Elite3D graphics boards. - -config FB_TCX - bool "TCX (SS4/SS5 only) support" - depends on FB_SBUS - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This is the frame buffer device driver for the TCX 24/8bit frame - buffer. - -config FB_CG14 - bool "CGfourteen (SX) support" - depends on FB_SBUS - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This is the frame buffer device driver for the CGfourteen frame - buffer on Desktop SPARCsystems with the SX graphics option. - -config FB_P9100 - bool "P9100 (Sparcbook 3 only) support" - depends on FB_SBUS - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This is the frame buffer device driver for the P9100 card - supported on Sparcbook 3 machines. - -config FB_LEO - bool "Leo (ZX) support" - depends on FB_SBUS - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This is the frame buffer device driver for the SBUS-based Sun ZX - (leo) frame buffer cards. - -config FB_IGA - bool "IGA 168x display support" - depends on (FB = y) && SPARC32 - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This is the framebuffer device for the INTERGRAPHICS 1680 and - successor frame buffer cards. - -config FB_XVR500 - bool "Sun XVR-500 3DLABS Wildcat support" - depends on (FB = y) && PCI && SPARC64 - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This is the framebuffer device for the Sun XVR-500 and similar - graphics cards based upon the 3DLABS Wildcat chipset. The driver - only works on sparc64 systems where the system firmware has - mostly initialized the card already. It is treated as a - completely dumb framebuffer device. - -config FB_XVR2500 - bool "Sun XVR-2500 3DLABS Wildcat support" - depends on (FB = y) && PCI && SPARC64 - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This is the framebuffer device for the Sun XVR-2500 and similar - graphics cards based upon the 3DLABS Wildcat chipset. The driver - only works on sparc64 systems where the system firmware has - mostly initialized the card already. It is treated as a - completely dumb framebuffer device. - -config FB_XVR1000 - bool "Sun XVR-1000 support" - depends on (FB = y) && SPARC64 - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This is the framebuffer device for the Sun XVR-1000 and similar - graphics cards. The driver only works on sparc64 systems where - the system firmware has mostly initialized the card already. It - is treated as a completely dumb framebuffer device. - -config FB_PVR2 - tristate "NEC PowerVR 2 display support" - depends on FB && SH_DREAMCAST - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - ---help--- - Say Y here if you have a PowerVR 2 card in your box. If you plan to - run linux on your Dreamcast, you will have to say Y here. - This driver may or may not work on other PowerVR 2 cards, but is - totally untested. Use at your own risk. If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called pvr2fb. - - You can pass several parameters to the driver at boot time or at - module load time. The parameters look like "video=pvr2:XXX", where - the meaning of XXX can be found at the end of the main source file - (). Please see the file - . - -config FB_OPENCORES - tristate "OpenCores VGA/LCD core 2.0 framebuffer support" - depends on FB && HAS_DMA - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This enables support for the OpenCores VGA/LCD core. - - The OpenCores VGA/LCD core is typically used together with - softcore CPUs (e.g. OpenRISC or Microblaze) or hard processor - systems (e.g. Altera socfpga or Xilinx Zynq) on FPGAs. - - The source code and specification for the core is available at - - -config FB_S1D13XXX - tristate "Epson S1D13XXX framebuffer support" - depends on FB - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - Support for S1D13XXX framebuffer device family (currently only - working with S1D13806). Product specs at - - -config FB_ATMEL - tristate "AT91/AT32 LCD Controller support" - depends on FB && HAVE_FB_ATMEL - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select FB_MODE_HELPERS - select VIDEOMODE_HELPERS - help - This enables support for the AT91/AT32 LCD Controller. - -config FB_INTSRAM - bool "Frame Buffer in internal SRAM" - depends on FB_ATMEL && ARCH_AT91SAM9261 - help - Say Y if you want to map Frame Buffer in internal SRAM. Say N if you want - to let frame buffer in external SDRAM. - -config FB_ATMEL_STN - bool "Use a STN display with AT91/AT32 LCD Controller" - depends on FB_ATMEL && (MACH_AT91SAM9261EK || MACH_AT91SAM9G10EK) - default n - help - Say Y if you want to connect a STN LCD display to the AT91/AT32 LCD - Controller. Say N if you want to connect a TFT. - - If unsure, say N. - -config FB_NVIDIA - tristate "nVidia Framebuffer Support" - depends on FB && PCI - select FB_BACKLIGHT if FB_NVIDIA_BACKLIGHT - select FB_MODE_HELPERS - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select BITREVERSE - select VGASTATE - help - This driver supports graphics boards with the nVidia chips, TNT - and newer. For very old chipsets, such as the RIVA128, then use - the rivafb. - Say Y if you have such a graphics board. - - To compile this driver as a module, choose M here: the - module will be called nvidiafb. - -config FB_NVIDIA_I2C - bool "Enable DDC Support" - depends on FB_NVIDIA - select FB_DDC - help - This enables I2C support for nVidia Chipsets. This is used - only for getting EDID information from the attached display - allowing for robust video mode handling and switching. - - Because fbdev-2.6 requires that drivers must be able to - independently validate video mode parameters, you should say Y - here. - -config FB_NVIDIA_DEBUG - bool "Lots of debug output" - depends on FB_NVIDIA - default n - help - Say Y here if you want the nVidia driver to output all sorts - of debugging information to provide to the maintainer when - something goes wrong. - -config FB_NVIDIA_BACKLIGHT - bool "Support for backlight control" - depends on FB_NVIDIA - default y - help - Say Y here if you want to control the backlight of your display. - -config FB_RIVA - tristate "nVidia Riva support" - depends on FB && PCI - select FB_BACKLIGHT if FB_RIVA_BACKLIGHT - select FB_MODE_HELPERS - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select BITREVERSE - select VGASTATE - help - This driver supports graphics boards with the nVidia Riva/Geforce - chips. - Say Y if you have such a graphics board. - - To compile this driver as a module, choose M here: the - module will be called rivafb. - -config FB_RIVA_I2C - bool "Enable DDC Support" - depends on FB_RIVA - select FB_DDC - help - This enables I2C support for nVidia Chipsets. This is used - only for getting EDID information from the attached display - allowing for robust video mode handling and switching. - - Because fbdev-2.6 requires that drivers must be able to - independently validate video mode parameters, you should say Y - here. - -config FB_RIVA_DEBUG - bool "Lots of debug output" - depends on FB_RIVA - default n - help - Say Y here if you want the Riva driver to output all sorts - of debugging information to provide to the maintainer when - something goes wrong. - -config FB_RIVA_BACKLIGHT - bool "Support for backlight control" - depends on FB_RIVA - default y - help - Say Y here if you want to control the backlight of your display. - -config FB_I740 - tristate "Intel740 support" - depends on FB && PCI - select FB_MODE_HELPERS - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select VGASTATE - select FB_DDC - help - This driver supports graphics cards based on Intel740 chip. - -config FB_I810 - tristate "Intel 810/815 support" - depends on FB && PCI && X86_32 && AGP_INTEL - select FB_MODE_HELPERS - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select VGASTATE - help - This driver supports the on-board graphics built in to the Intel 810 - and 815 chipsets. Say Y if you have and plan to use such a board. - - To compile this driver as a module, choose M here: the - module will be called i810fb. - - For more information, please read - - -config FB_I810_GTF - bool "use VESA Generalized Timing Formula" - depends on FB_I810 - help - If you say Y, then the VESA standard, Generalized Timing Formula - or GTF, will be used to calculate the required video timing values - per video mode. Since the GTF allows nondiscrete timings - (nondiscrete being a range of values as opposed to discrete being a - set of values), you'll be able to use any combination of horizontal - and vertical resolutions, and vertical refresh rates without having - to specify your own timing parameters. This is especially useful - to maximize the performance of an aging display, or if you just - have a display with nonstandard dimensions. A VESA compliant - monitor is recommended, but can still work with non-compliant ones. - If you need or want this, then select this option. The timings may - not be compliant with Intel's recommended values. Use at your own - risk. - - If you say N, the driver will revert to discrete video timings - using a set recommended by Intel in their documentation. - - If unsure, say N. - -config FB_I810_I2C - bool "Enable DDC Support" - depends on FB_I810 && FB_I810_GTF - select FB_DDC - help - -config FB_LE80578 - tristate "Intel LE80578 (Vermilion) support" - depends on FB && PCI && X86 - select FB_MODE_HELPERS - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This driver supports the LE80578 (Vermilion Range) chipset - -config FB_CARILLO_RANCH - tristate "Intel Carillo Ranch support" - depends on FB_LE80578 && FB && PCI && X86 - help - This driver supports the LE80578 (Carillo Ranch) board - -config FB_INTEL - tristate "Intel 830M/845G/852GM/855GM/865G/915G/945G/945GM/965G/965GM support" - depends on FB && PCI && X86 && AGP_INTEL && EXPERT - select FB_MODE_HELPERS - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select FB_BOOT_VESA_SUPPORT if FB_INTEL = y - depends on !DRM_I915 - help - This driver supports the on-board graphics built in to the Intel - 830M/845G/852GM/855GM/865G/915G/915GM/945G/945GM/965G/965GM chipsets. - Say Y if you have and plan to use such a board. - - To make FB_INTELFB=Y work you need to say AGP_INTEL=y too. - - To compile this driver as a module, choose M here: the - module will be called intelfb. - - For more information, please read - -config FB_INTEL_DEBUG - bool "Intel driver Debug Messages" - depends on FB_INTEL - ---help--- - Say Y here if you want the Intel driver to output all sorts - of debugging information to provide to the maintainer when - something goes wrong. - -config FB_INTEL_I2C - bool "DDC/I2C for Intel framebuffer support" - depends on FB_INTEL - select FB_DDC - default y - help - Say Y here if you want DDC/I2C support for your on-board Intel graphics. - -config FB_MATROX - tristate "Matrox acceleration" - depends on FB && PCI - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select FB_TILEBLITTING - select FB_MACMODES if PPC_PMAC - ---help--- - Say Y here if you have a Matrox Millennium, Matrox Millennium II, - Matrox Mystique, Matrox Mystique 220, Matrox Productiva G100, Matrox - Mystique G200, Matrox Millennium G200, Matrox Marvel G200 video, - Matrox G400, G450 or G550 card in your box. - - To compile this driver as a module, choose M here: the - module will be called matroxfb. - - You can pass several parameters to the driver at boot time or at - module load time. The parameters look like "video=matroxfb:XXX", and - are described in . - -config FB_MATROX_MILLENIUM - bool "Millennium I/II support" - depends on FB_MATROX - help - Say Y here if you have a Matrox Millennium or Matrox Millennium II - video card. If you select "Advanced lowlevel driver options" below, - you should check 4 bpp packed pixel, 8 bpp packed pixel, 16 bpp - packed pixel, 24 bpp packed pixel and 32 bpp packed pixel. You can - also use font widths different from 8. - -config FB_MATROX_MYSTIQUE - bool "Mystique support" - depends on FB_MATROX - help - Say Y here if you have a Matrox Mystique or Matrox Mystique 220 - video card. If you select "Advanced lowlevel driver options" below, - you should check 8 bpp packed pixel, 16 bpp packed pixel, 24 bpp - packed pixel and 32 bpp packed pixel. You can also use font widths - different from 8. - -config FB_MATROX_G - bool "G100/G200/G400/G450/G550 support" - depends on FB_MATROX - ---help--- - Say Y here if you have a Matrox G100, G200, G400, G450 or G550 based - video card. If you select "Advanced lowlevel driver options", you - should check 8 bpp packed pixel, 16 bpp packed pixel, 24 bpp packed - pixel and 32 bpp packed pixel. You can also use font widths - different from 8. - - If you need support for G400 secondary head, you must say Y to - "Matrox I2C support" and "G400 second head support" right below. - G450/G550 secondary head and digital output are supported without - additional modules. - - The driver starts in monitor mode. You must use the matroxset tool - (available at ) to - swap primary and secondary head outputs, or to change output mode. - Secondary head driver always start in 640x480 resolution and you - must use fbset to change it. - - Do not forget that second head supports only 16 and 32 bpp - packed pixels, so it is a good idea to compile them into the kernel - too. You can use only some font widths, as the driver uses generic - painting procedures (the secondary head does not use acceleration - engine). - - G450/G550 hardware can display TV picture only from secondary CRTC, - and it performs no scaling, so picture must have 525 or 625 lines. - -config FB_MATROX_I2C - tristate "Matrox I2C support" - depends on FB_MATROX - select FB_DDC - ---help--- - This drivers creates I2C buses which are needed for accessing the - DDC (I2C) bus present on all Matroxes, an I2C bus which - interconnects Matrox optional devices, like MGA-TVO on G200 and - G400, and the secondary head DDC bus, present on G400 only. - - You can say Y or M here if you want to experiment with monitor - detection code. You must say Y or M here if you want to use either - second head of G400 or MGA-TVO on G200 or G400. - - If you compile it as module, it will create a module named - i2c-matroxfb. - -config FB_MATROX_MAVEN - tristate "G400 second head support" - depends on FB_MATROX_G && FB_MATROX_I2C - ---help--- - WARNING !!! This support does not work with G450 !!! - - Say Y or M here if you want to use a secondary head (meaning two - monitors in parallel) on G400 or MGA-TVO add-on on G200. Secondary - head is not compatible with accelerated XFree 3.3.x SVGA servers - - secondary head output is blanked while you are in X. With XFree - 3.9.17 preview you can use both heads if you use SVGA over fbdev or - the fbdev driver on first head and the fbdev driver on second head. - - If you compile it as module, two modules are created, - matroxfb_crtc2 and matroxfb_maven. Matroxfb_maven is needed for - both G200 and G400, matroxfb_crtc2 is needed only by G400. You must - also load i2c-matroxfb to get it to run. - - The driver starts in monitor mode and you must use the matroxset - tool (available at - ) to switch it to - PAL or NTSC or to swap primary and secondary head outputs. - Secondary head driver also always start in 640x480 resolution, you - must use fbset to change it. - - Also do not forget that second head supports only 16 and 32 bpp - packed pixels, so it is a good idea to compile them into the kernel - too. You can use only some font widths, as the driver uses generic - painting procedures (the secondary head does not use acceleration - engine). - -config FB_RADEON - tristate "ATI Radeon display support" - depends on FB && PCI - select FB_BACKLIGHT if FB_RADEON_BACKLIGHT - select FB_MODE_HELPERS - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select FB_MACMODES if PPC_OF - help - Choose this option if you want to use an ATI Radeon graphics card as - a framebuffer device. There are both PCI and AGP versions. You - don't need to choose this to run the Radeon in plain VGA mode. - - There is a product page at - http://products.amd.com/en-us/GraphicCardResult.aspx - -config FB_RADEON_I2C - bool "DDC/I2C for ATI Radeon support" - depends on FB_RADEON - select FB_DDC - default y - help - Say Y here if you want DDC/I2C support for your Radeon board. - -config FB_RADEON_BACKLIGHT - bool "Support for backlight control" - depends on FB_RADEON - default y - help - Say Y here if you want to control the backlight of your display. - -config FB_RADEON_DEBUG - bool "Lots of debug output from Radeon driver" - depends on FB_RADEON - default n - help - Say Y here if you want the Radeon driver to output all sorts - of debugging information to provide to the maintainer when - something goes wrong. - -config FB_ATY128 - tristate "ATI Rage128 display support" - depends on FB && PCI - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select FB_BACKLIGHT if FB_ATY128_BACKLIGHT - select FB_MACMODES if PPC_PMAC - help - This driver supports graphics boards with the ATI Rage128 chips. - Say Y if you have such a graphics board and read - . - - To compile this driver as a module, choose M here: the - module will be called aty128fb. - -config FB_ATY128_BACKLIGHT - bool "Support for backlight control" - depends on FB_ATY128 - default y - help - Say Y here if you want to control the backlight of your display. - -config FB_ATY - tristate "ATI Mach64 display support" if PCI || ATARI - depends on FB && !SPARC32 - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select FB_BACKLIGHT if FB_ATY_BACKLIGHT - select FB_MACMODES if PPC - help - This driver supports graphics boards with the ATI Mach64 chips. - Say Y if you have such a graphics board. - - To compile this driver as a module, choose M here: the - module will be called atyfb. - -config FB_ATY_CT - bool "Mach64 CT/VT/GT/LT (incl. 3D RAGE) support" - depends on PCI && FB_ATY - default y if SPARC64 && PCI - help - Say Y here to support use of ATI's 64-bit Rage boards (or other - boards based on the Mach64 CT, VT, GT, and LT chipsets) as a - framebuffer device. The ATI product support page for these boards - is at . - -config FB_ATY_GENERIC_LCD - bool "Mach64 generic LCD support" - depends on FB_ATY_CT - help - Say Y if you have a laptop with an ATI Rage LT PRO, Rage Mobility, - Rage XC, or Rage XL chipset. - -config FB_ATY_GX - bool "Mach64 GX support" if PCI - depends on FB_ATY - default y if ATARI - help - Say Y here to support use of the ATI Mach64 Graphics Expression - board (or other boards based on the Mach64 GX chipset) as a - framebuffer device. The ATI product support page for these boards - is at - . - -config FB_ATY_BACKLIGHT - bool "Support for backlight control" - depends on FB_ATY - default y - help - Say Y here if you want to control the backlight of your display. - -config FB_S3 - tristate "S3 Trio/Virge support" - depends on FB && PCI - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select FB_TILEBLITTING - select FB_SVGALIB - select VGASTATE - select FONT_8x16 if FRAMEBUFFER_CONSOLE - ---help--- - Driver for graphics boards with S3 Trio / S3 Virge chip. - -config FB_S3_DDC - bool "DDC for S3 support" - depends on FB_S3 - select FB_DDC - default y - help - Say Y here if you want DDC support for your S3 graphics card. - -config FB_SAVAGE - tristate "S3 Savage support" - depends on FB && PCI - select FB_MODE_HELPERS - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select VGASTATE - help - This driver supports notebooks and computers with S3 Savage PCI/AGP - chips. - - Say Y if you have such a graphics card. - - To compile this driver as a module, choose M here; the module - will be called savagefb. - -config FB_SAVAGE_I2C - bool "Enable DDC2 Support" - depends on FB_SAVAGE - select FB_DDC - help - This enables I2C support for S3 Savage Chipsets. This is used - only for getting EDID information from the attached display - allowing for robust video mode handling and switching. - - Because fbdev-2.6 requires that drivers must be able to - independently validate video mode parameters, you should say Y - here. - -config FB_SAVAGE_ACCEL - bool "Enable Console Acceleration" - depends on FB_SAVAGE - default n - help - This option will compile in console acceleration support. If - the resulting framebuffer console has bothersome glitches, then - choose N here. - -config FB_SIS - tristate "SiS/XGI display support" - depends on FB && PCI - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select FB_BOOT_VESA_SUPPORT if FB_SIS = y - help - This is the frame buffer device driver for the SiS 300, 315, 330 - and 340 series as well as XGI V3XT, V5, V8, Z7 graphics chipsets. - Specs available at and . - - To compile this driver as a module, choose M here; the module - will be called sisfb. - -config FB_SIS_300 - bool "SiS 300 series support" - depends on FB_SIS - help - Say Y here to support use of the SiS 300/305, 540, 630 and 730. - -config FB_SIS_315 - bool "SiS 315/330/340 series and XGI support" - depends on FB_SIS - help - Say Y here to support use of the SiS 315, 330 and 340 series - (315/H/PRO, 55x, 650, 651, 740, 330, 661, 741, 760, 761) as well - as XGI V3XT, V5, V8 and Z7. - -config FB_VIA - tristate "VIA UniChrome (Pro) and Chrome9 display support" - depends on FB && PCI && X86 - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select I2C_ALGOBIT - select I2C - select GPIOLIB - help - This is the frame buffer device driver for Graphics chips of VIA - UniChrome (Pro) Family (CLE266,PM800/CN400,P4M800CE/P4M800Pro/ - CN700/VN800,CX700/VX700,P4M890) and Chrome9 Family (K8M890,CN896 - /P4M900,VX800) - Say Y if you have a VIA UniChrome graphics board. - - To compile this driver as a module, choose M here: the - module will be called viafb. - -if FB_VIA - -config FB_VIA_DIRECT_PROCFS - bool "direct hardware access via procfs (DEPRECATED)(DANGEROUS)" - depends on FB_VIA - default n - help - Allow direct hardware access to some output registers via procfs. - This is dangerous but may provide the only chance to get the - correct output device configuration. - Its use is strongly discouraged. - -config FB_VIA_X_COMPATIBILITY - bool "X server compatibility" - depends on FB_VIA - default n - help - This option reduces the functionality (power saving, ...) of the - framebuffer to avoid negative impact on the OpenChrome X server. - If you use any X server other than fbdev you should enable this - otherwise it should be safe to disable it and allow using all - features. - -endif - -config FB_NEOMAGIC - tristate "NeoMagic display support" - depends on FB && PCI - select FB_MODE_HELPERS - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select VGASTATE - help - This driver supports notebooks with NeoMagic PCI chips. - Say Y if you have such a graphics card. - - To compile this driver as a module, choose M here: the - module will be called neofb. - -config FB_KYRO - tristate "IMG Kyro support" - depends on FB && PCI - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - Say Y here if you have a STG4000 / Kyro / PowerVR 3 based - graphics board. - - To compile this driver as a module, choose M here: the - module will be called kyrofb. - -config FB_3DFX - tristate "3Dfx Banshee/Voodoo3/Voodoo5 display support" - depends on FB && PCI - select FB_CFB_IMAGEBLIT - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_MODE_HELPERS - help - This driver supports graphics boards with the 3Dfx Banshee, - Voodoo3 or VSA-100 (aka Voodoo4/5) chips. Say Y if you have - such a graphics board. - - To compile this driver as a module, choose M here: the - module will be called tdfxfb. - -config FB_3DFX_ACCEL - bool "3Dfx Acceleration functions" - depends on FB_3DFX - ---help--- - This will compile the 3Dfx Banshee/Voodoo3/VSA-100 frame buffer - device driver with acceleration functions. - -config FB_3DFX_I2C - bool "Enable DDC/I2C support" - depends on FB_3DFX - select FB_DDC - default y - help - Say Y here if you want DDC/I2C support for your 3dfx Voodoo3. - -config FB_VOODOO1 - tristate "3Dfx Voodoo Graphics (sst1) support" - depends on FB && PCI - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - ---help--- - Say Y here if you have a 3Dfx Voodoo Graphics (Voodoo1/sst1) or - Voodoo2 (cvg) based graphics card. - - To compile this driver as a module, choose M here: the - module will be called sstfb. - - WARNING: Do not use any application that uses the 3D engine - (namely glide) while using this driver. - Please read the for supported - options and other important info support. - -config FB_VT8623 - tristate "VIA VT8623 support" - depends on FB && PCI - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select FB_TILEBLITTING - select FB_SVGALIB - select VGASTATE - select FONT_8x16 if FRAMEBUFFER_CONSOLE - ---help--- - Driver for CastleRock integrated graphics core in the - VIA VT8623 [Apollo CLE266] chipset. - -config FB_TRIDENT - tristate "Trident/CyberXXX/CyberBlade support" - depends on FB && PCI - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - ---help--- - This is the frame buffer device driver for Trident PCI/AGP chipsets. - Supported chipset families are TGUI 9440/96XX, 3DImage, Blade3D - and Blade XP. - There are also integrated versions of these chips called CyberXXXX, - CyberImage or CyberBlade. These chips are mostly found in laptops - but also on some motherboards including early VIA EPIA motherboards. - For more information, read - - Say Y if you have such a graphics board. - - To compile this driver as a module, choose M here: the - module will be called tridentfb. - -config FB_ARK - tristate "ARK 2000PV support" - depends on FB && PCI - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select FB_TILEBLITTING - select FB_SVGALIB - select VGASTATE - select FONT_8x16 if FRAMEBUFFER_CONSOLE - ---help--- - Driver for PCI graphics boards with ARK 2000PV chip - and ICS 5342 RAMDAC. - -config FB_PM3 - tristate "Permedia3 support" - depends on FB && PCI - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This is the frame buffer device driver for the 3DLabs Permedia3 - chipset, used in Formac ProFormance III, 3DLabs Oxygen VX1 & - similar boards, 3DLabs Permedia3 Create!, Appian Jeronimo 2000 - and maybe other boards. - -config FB_CARMINE - tristate "Fujitsu carmine frame buffer support" - depends on FB && PCI - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This is the frame buffer device driver for the Fujitsu Carmine chip. - The driver provides two independent frame buffer devices. - -choice - depends on FB_CARMINE - prompt "DRAM timing" - default FB_CARMINE_DRAM_EVAL - -config FB_CARMINE_DRAM_EVAL - bool "Eval board timings" - help - Use timings which work on the eval card. - -config CARMINE_DRAM_CUSTOM - bool "Custom board timings" - help - Use custom board timings. -endchoice - -config FB_AU1100 - bool "Au1100 LCD Driver" - depends on (FB = y) && MIPS_ALCHEMY - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This is the framebuffer driver for the AMD Au1100 SOC. It can drive - various panels and CRTs by passing in kernel cmd line option - au1100fb:panel=. - -config FB_AU1200 - bool "Au1200/Au1300 LCD Driver" - depends on (FB = y) && MIPS_ALCHEMY - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT - select FB_SYS_FOPS - help - This is the framebuffer driver for the Au1200/Au1300 SOCs. - It can drive various panels and CRTs by passing in kernel cmd line - option au1200fb:panel=. - -config FB_VT8500 - bool "VIA VT8500 framebuffer support" - depends on (FB = y) && ARM && ARCH_VT8500 - select FB_SYS_FILLRECT if (!FB_WMT_GE_ROPS) - select FB_SYS_COPYAREA if (!FB_WMT_GE_ROPS) - select FB_SYS_IMAGEBLIT - select FB_MODE_HELPERS - select VIDEOMODE_HELPERS - help - This is the framebuffer driver for VIA VT8500 integrated LCD - controller. - -config FB_WM8505 - bool "Wondermedia WM8xxx-series frame buffer support" - depends on (FB = y) && ARM && ARCH_VT8500 - select FB_SYS_FILLRECT if (!FB_WMT_GE_ROPS) - select FB_SYS_COPYAREA if (!FB_WMT_GE_ROPS) - select FB_SYS_IMAGEBLIT - select FB_MODE_HELPERS - select VIDEOMODE_HELPERS - help - This is the framebuffer driver for WonderMedia WM8xxx-series - integrated LCD controller. This driver covers the WM8505, WM8650 - and WM8850 SoCs. - -config FB_WMT_GE_ROPS - bool "VT8500/WM8xxx accelerated raster ops support" - depends on (FB = y) && (FB_VT8500 || FB_WM8505) - default n - help - This adds support for accelerated raster operations on the - VIA VT8500 and Wondermedia 85xx series SoCs. - -source "drivers/video/geode/Kconfig" - -config FB_HIT - tristate "HD64461 Frame Buffer support" - depends on FB && HD64461 - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This is the frame buffer device driver for the Hitachi HD64461 LCD - frame buffer card. - -config FB_PMAG_AA - bool "PMAG-AA TURBOchannel framebuffer support" - depends on (FB = y) && TC - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - Support for the PMAG-AA TURBOchannel framebuffer card (1280x1024x1) - used mainly in the MIPS-based DECstation series. - -config FB_PMAG_BA - tristate "PMAG-BA TURBOchannel framebuffer support" - depends on FB && TC - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - Support for the PMAG-BA TURBOchannel framebuffer card (1024x864x8) - used mainly in the MIPS-based DECstation series. - -config FB_PMAGB_B - tristate "PMAGB-B TURBOchannel framebuffer support" - depends on FB && TC - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - Support for the PMAGB-B TURBOchannel framebuffer card used mainly - in the MIPS-based DECstation series. The card is currently only - supported in 1280x1024x8 mode. - -config FB_MAXINE - bool "Maxine (Personal DECstation) onboard framebuffer support" - depends on (FB = y) && MACH_DECSTATION - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - Support for the onboard framebuffer (1024x768x8) in the Personal - DECstation series (Personal DECstation 5000/20, /25, /33, /50, - Codename "Maxine"). - -config FB_G364 - bool "G364 frame buffer support" - depends on (FB = y) && (MIPS_MAGNUM_4000 || OLIVETTI_M700) - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - The G364 driver is the framebuffer used in MIPS Magnum 4000 and - Olivetti M700-10 systems. - -config FB_68328 - bool "Motorola 68328 native frame buffer support" - depends on (FB = y) && (M68328 || M68EZ328 || M68VZ328) - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - Say Y here if you want to support the built-in frame buffer of - the Motorola 68328 CPU family. - -config FB_PXA168 - tristate "PXA168/910 LCD framebuffer support" - depends on FB && (CPU_PXA168 || CPU_PXA910) - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - ---help--- - Frame buffer driver for the built-in LCD controller in the Marvell - MMP processor. - -config FB_PXA - tristate "PXA LCD framebuffer support" - depends on FB && ARCH_PXA - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - ---help--- - Frame buffer driver for the built-in LCD controller in the Intel - PXA2x0 processor. - - This driver is also available as a module ( = code which can be - inserted and removed from the running kernel whenever you want). The - module will be called pxafb. If you want to compile it as a module, - say M here and read . - - If unsure, say N. - -config FB_PXA_OVERLAY - bool "Support PXA27x/PXA3xx Overlay(s) as framebuffer" - default n - depends on FB_PXA && (PXA27x || PXA3xx) - -config FB_PXA_SMARTPANEL - bool "PXA Smartpanel LCD support" - default n - depends on FB_PXA - -config FB_PXA_PARAMETERS - bool "PXA LCD command line parameters" - default n - depends on FB_PXA - ---help--- - Enable the use of kernel command line or module parameters - to configure the physical properties of the LCD panel when - using the PXA LCD driver. - - This option allows you to override the panel parameters - supplied by the platform in order to support multiple - different models of flatpanel. If you will only be using a - single model of flatpanel then you can safely leave this - option disabled. - - describes the available parameters. - -config PXA3XX_GCU - tristate "PXA3xx 2D graphics accelerator driver" - depends on FB_PXA - help - Kernelspace driver for the 2D graphics controller unit (GCU) - found on PXA3xx processors. There is a counterpart driver in the - DirectFB suite, see http://www.directfb.org/ - - If you compile this as a module, it will be called pxa3xx_gcu. - -config FB_MBX - tristate "2700G LCD framebuffer support" - depends on FB && ARCH_PXA - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - ---help--- - Framebuffer driver for the Intel 2700G (Marathon) Graphics - Accelerator - -config FB_MBX_DEBUG - bool "Enable debugging info via debugfs" - depends on FB_MBX && DEBUG_FS - default n - ---help--- - Enable this if you want debugging information using the debug - filesystem (debugfs) - - If unsure, say N. - -config FB_FSL_DIU - tristate "Freescale DIU framebuffer support" - depends on FB && FSL_SOC - select FB_MODE_HELPERS - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select PPC_LIB_RHEAP - ---help--- - Framebuffer driver for the Freescale SoC DIU - -config FB_W100 - tristate "W100 frame buffer support" - depends on FB && ARCH_PXA - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - ---help--- - Frame buffer driver for the w100 as found on the Sharp SL-Cxx series. - It can also drive the w3220 chip found on iPAQ hx4700. - - This driver is also available as a module ( = code which can be - inserted and removed from the running kernel whenever you want). The - module will be called w100fb. If you want to compile it as a module, - say M here and read . - - If unsure, say N. - -config FB_SH_MOBILE_LCDC - tristate "SuperH Mobile LCDC framebuffer support" - depends on FB && (SUPERH || ARCH_SHMOBILE) && HAVE_CLK - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT - select FB_SYS_FOPS - select FB_DEFERRED_IO - select FB_BACKLIGHT - select SH_MIPI_DSI if SH_LCD_MIPI_DSI - ---help--- - Frame buffer driver for the on-chip SH-Mobile LCD controller. - -config FB_SH_MOBILE_HDMI - tristate "SuperH Mobile HDMI controller support" - depends on FB_SH_MOBILE_LCDC - select FB_MODE_HELPERS - select SOUND - select SND - select SND_SOC - ---help--- - Driver for the on-chip SH-Mobile HDMI controller. - -config FB_TMIO - tristate "Toshiba Mobile IO FrameBuffer support" - depends on FB && MFD_CORE - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - ---help--- - Frame buffer driver for the Toshiba Mobile IO integrated as found - on the Sharp SL-6000 series - - This driver is also available as a module ( = code which can be - inserted and removed from the running kernel whenever you want). The - module will be called tmiofb. If you want to compile it as a module, - say M here and read . - - If unsure, say N. - -config FB_TMIO_ACCELL - bool "tmiofb acceleration" - depends on FB_TMIO - default y - -config FB_S3C - tristate "Samsung S3C framebuffer support" - depends on FB && (CPU_S3C2416 || ARCH_S3C64XX || ARCH_S5P64X0 || \ - ARCH_S5PC100 || ARCH_S5PV210 || ARCH_EXYNOS) - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - ---help--- - Frame buffer driver for the built-in FB controller in the Samsung - SoC line from the S3C2443 onwards, including the S3C2416, S3C2450, - and the S3C64XX series such as the S3C6400 and S3C6410. - - These chips all have the same basic framebuffer design with the - actual capabilities depending on the chip. For instance the S3C6400 - and S3C6410 support 4 hardware windows whereas the S3C24XX series - currently only have two. - - Currently the support is only for the S3C6400 and S3C6410 SoCs. - -config FB_S3C_DEBUG_REGWRITE - bool "Debug register writes" - depends on FB_S3C - ---help--- - Show all register writes via pr_debug() - -config FB_S3C2410 - tristate "S3C2410 LCD framebuffer support" - depends on FB && ARCH_S3C24XX - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - ---help--- - Frame buffer driver for the built-in LCD controller in the Samsung - S3C2410 processor. - - This driver is also available as a module ( = code which can be - inserted and removed from the running kernel whenever you want). The - module will be called s3c2410fb. If you want to compile it as a module, - say M here and read . - - If unsure, say N. -config FB_S3C2410_DEBUG - bool "S3C2410 lcd debug messages" - depends on FB_S3C2410 - help - Turn on debugging messages. Note that you can set/unset at run time - through sysfs - -config FB_NUC900 - bool "NUC900 LCD framebuffer support" - depends on FB && ARCH_W90X900 - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - ---help--- - Frame buffer driver for the built-in LCD controller in the Nuvoton - NUC900 processor - -config GPM1040A0_320X240 - bool "Giantplus Technology GPM1040A0 320x240 Color TFT LCD" - depends on FB_NUC900 - -config FB_SM501 - tristate "Silicon Motion SM501 framebuffer support" - depends on FB && MFD_SM501 - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - ---help--- - Frame buffer driver for the CRT and LCD controllers in the Silicon - Motion SM501. - - This driver is also available as a module ( = code which can be - inserted and removed from the running kernel whenever you want). The - module will be called sm501fb. If you want to compile it as a module, - say M here and read . - - If unsure, say N. - -config FB_SMSCUFX - tristate "SMSC UFX6000/7000 USB Framebuffer support" - depends on FB && USB - select FB_MODE_HELPERS - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT - select FB_SYS_FOPS - select FB_DEFERRED_IO - ---help--- - This is a kernel framebuffer driver for SMSC UFX USB devices. - Supports fbdev clients like xf86-video-fbdev, kdrive, fbi, and - mplayer -vo fbdev. Supports both UFX6000 (USB 2.0) and UFX7000 - (USB 3.0) devices. - To compile as a module, choose M here: the module name is smscufx. - -config FB_UDL - tristate "Displaylink USB Framebuffer support" - depends on FB && USB - select FB_MODE_HELPERS - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT - select FB_SYS_FOPS - select FB_DEFERRED_IO - ---help--- - This is a kernel framebuffer driver for DisplayLink USB devices. - Supports fbdev clients like xf86-video-fbdev, kdrive, fbi, and - mplayer -vo fbdev. Supports all USB 2.0 era DisplayLink devices. - To compile as a module, choose M here: the module name is udlfb. - -config FB_IBM_GXT4500 - tristate "Framebuffer support for IBM GXT4000P/4500P/6000P/6500P adaptors" - depends on FB && PPC - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - ---help--- - Say Y here to enable support for the IBM GXT4000P/6000P and - GXT4500P/6500P display adaptor based on Raster Engine RC1000, - found on some IBM System P (pSeries) machines. This driver - doesn't use Geometry Engine GT1000. - -config FB_PS3 - tristate "PS3 GPU framebuffer driver" - depends on FB && PS3_PS3AV - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT - select FB_SYS_FOPS - select VT_HW_CONSOLE_BINDING if FRAMEBUFFER_CONSOLE - ---help--- - Include support for the virtual frame buffer in the PS3 platform. - -config FB_PS3_DEFAULT_SIZE_M - int "PS3 default frame buffer size (in MiB)" - depends on FB_PS3 - default 9 - ---help--- - This is the default size (in MiB) of the virtual frame buffer in - the PS3. - The default value can be overridden on the kernel command line - using the "ps3fb" option (e.g. "ps3fb=9M"); - -config FB_XILINX - tristate "Xilinx frame buffer support" - depends on FB && (XILINX_VIRTEX || MICROBLAZE || ARCH_ZYNQ) - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - ---help--- - Include support for the Xilinx ML300/ML403 reference design - framebuffer. ML300 carries a 640*480 LCD display on the board, - ML403 uses a standard DB15 VGA connector. - -config FB_GOLDFISH - tristate "Goldfish Framebuffer" - depends on FB && HAS_DMA - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - ---help--- - Framebuffer driver for Goldfish Virtual Platform - -config FB_COBALT - tristate "Cobalt server LCD frame buffer support" - depends on FB && (MIPS_COBALT || MIPS_SEAD3) - -config FB_SH7760 - bool "SH7760/SH7763/SH7720/SH7721 LCDC support" - depends on FB && (CPU_SUBTYPE_SH7760 || CPU_SUBTYPE_SH7763 \ - || CPU_SUBTYPE_SH7720 || CPU_SUBTYPE_SH7721) - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - ---help--- - Support for the SH7760/SH7763/SH7720/SH7721 integrated - (D)STN/TFT LCD Controller. - Supports display resolutions up to 1024x1024 pixel, grayscale and - color operation, with depths ranging from 1 bpp to 8 bpp monochrome - and 8, 15 or 16 bpp color; 90 degrees clockwise display rotation for - panels <= 320 pixel horizontal resolution. - -config FB_DA8XX - tristate "DA8xx/OMAP-L1xx/AM335x Framebuffer support" - depends on FB && (ARCH_DAVINCI_DA8XX || SOC_AM33XX) - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select FB_CFB_REV_PIXELS_IN_BYTE - select FB_MODE_HELPERS - select VIDEOMODE_HELPERS - ---help--- - This is the frame buffer device driver for the TI LCD controller - found on DA8xx/OMAP-L1xx/AM335x SoCs. - If unsure, say N. - -config FB_VIRTUAL - tristate "Virtual Frame Buffer support (ONLY FOR TESTING!)" - depends on FB - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT - select FB_SYS_FOPS - ---help--- - This is a `virtual' frame buffer device. It operates on a chunk of - unswappable kernel memory instead of on the memory of a graphics - board. This means you cannot see any output sent to this frame - buffer device, while it does consume precious memory. The main use - of this frame buffer device is testing and debugging the frame - buffer subsystem. Do NOT enable it for normal systems! To protect - the innocent, it has to be enabled explicitly at boot time using the - kernel option `video=vfb:'. - - To compile this driver as a module, choose M here: the - module will be called vfb. In order to load it, you must use - the vfb_enable=1 option. - - If unsure, say N. - -config XEN_FBDEV_FRONTEND - tristate "Xen virtual frame buffer support" - depends on FB && XEN - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT - select FB_SYS_FOPS - select FB_DEFERRED_IO - select INPUT_XEN_KBDDEV_FRONTEND if INPUT_MISC - select XEN_XENBUS_FRONTEND - default y - help - This driver implements the front-end of the Xen virtual - frame buffer driver. It communicates with a back-end - in another domain. - -config FB_METRONOME - tristate "E-Ink Metronome/8track controller support" - depends on FB - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT - select FB_SYS_FOPS - select FB_DEFERRED_IO - help - This driver implements support for the E-Ink Metronome - controller. The pre-release name for this device was 8track - and could also have been called by some vendors as PVI-nnnn. - -config FB_MB862XX - tristate "Fujitsu MB862xx GDC support" - depends on FB - depends on PCI || (OF && PPC) - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - ---help--- - Frame buffer driver for Fujitsu Carmine/Coral-P(A)/Lime controllers. - -choice - prompt "GDC variant" - depends on FB_MB862XX - -config FB_MB862XX_PCI_GDC - bool "Carmine/Coral-P(A) GDC" - depends on PCI - ---help--- - This enables framebuffer support for Fujitsu Carmine/Coral-P(A) - PCI graphics controller devices. - -config FB_MB862XX_LIME - bool "Lime GDC" - depends on OF && PPC - select FB_FOREIGN_ENDIAN - select FB_LITTLE_ENDIAN - ---help--- - Framebuffer support for Fujitsu Lime GDC on host CPU bus. - -endchoice - -config FB_MB862XX_I2C - bool "Support I2C bus on MB862XX GDC" - depends on FB_MB862XX && I2C - default y - help - Selecting this option adds Coral-P(A)/Lime GDC I2C bus adapter - driver to support accessing I2C devices on controller's I2C bus. - These are usually some video decoder chips. - -config FB_EP93XX - tristate "EP93XX frame buffer support" - depends on FB && ARCH_EP93XX - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - ---help--- - Framebuffer driver for the Cirrus Logic EP93XX series of processors. - This driver is also available as a module. The module will be called - ep93xx-fb. - -config FB_PRE_INIT_FB - bool "Don't reinitialize, use bootloader's GDC/Display configuration" - depends on FB && FB_MB862XX_LIME - ---help--- - Select this option if display contents should be inherited as set by - the bootloader. - -config FB_MSM - tristate "MSM Framebuffer support" - depends on FB && ARCH_MSM - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - -config FB_MX3 - tristate "MX3 Framebuffer support" - depends on FB && MX3_IPU - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - default y - help - This is a framebuffer device for the i.MX31 LCD Controller. So - far only synchronous displays are supported. If you plan to use - an LCD display with your i.MX31 system, say Y here. - -config FB_BROADSHEET - tristate "E-Ink Broadsheet/Epson S1D13521 controller support" - depends on FB - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT - select FB_SYS_FOPS - select FB_DEFERRED_IO - help - This driver implements support for the E-Ink Broadsheet - controller. The release name for this device was Epson S1D13521 - and could also have been called by other names when coupled with - a bridge adapter. - -config FB_AUO_K190X - tristate "AUO-K190X EPD controller support" - depends on FB - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT - select FB_SYS_FOPS - select FB_DEFERRED_IO - help - Provides support for epaper controllers from the K190X series - of AUO. These controllers can be used to drive epaper displays - from Sipix. - - This option enables the common support, shared by the individual - controller drivers. You will also have to enable the driver - for the controller type used in your device. - -config FB_AUO_K1900 - tristate "AUO-K1900 EPD controller support" - depends on FB && FB_AUO_K190X - help - This driver implements support for the AUO K1900 epd-controller. - This controller can drive Sipix epaper displays but can only do - serial updates, reducing the number of possible frames per second. - -config FB_AUO_K1901 - tristate "AUO-K1901 EPD controller support" - depends on FB && FB_AUO_K190X - help - This driver implements support for the AUO K1901 epd-controller. - This controller can drive Sipix epaper displays and supports - concurrent updates, making higher frames per second possible. - -config FB_JZ4740 - tristate "JZ4740 LCD framebuffer support" - depends on FB && MACH_JZ4740 - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT - help - Framebuffer support for the JZ4740 SoC. - -config FB_MXS - tristate "MXS LCD framebuffer support" - depends on FB && ARCH_MXS - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select FB_MODE_HELPERS - select VIDEOMODE_HELPERS - help - Framebuffer support for the MXS SoC. - -config FB_PUV3_UNIGFX - tristate "PKUnity v3 Unigfx framebuffer support" - depends on FB && UNICORE32 && ARCH_PUV3 - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT - select FB_SYS_FOPS - help - Choose this option if you want to use the Unigfx device as a - framebuffer device. Without the support of PCI & AGP. - -config FB_HYPERV - tristate "Microsoft Hyper-V Synthetic Video support" - depends on FB && HYPERV - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This framebuffer driver supports Microsoft Hyper-V Synthetic Video. - -config FB_SIMPLE - bool "Simple framebuffer support" - depends on (FB = y) - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - Say Y if you want support for a simple frame-buffer. - - This driver assumes that the display hardware has been initialized - before the kernel boots, and the kernel will simply render to the - pre-allocated frame buffer surface. - - Configuration re: surface address, size, and format must be provided - through device tree, or plain old platform data. - -source "drivers/video/omap/Kconfig" -source "drivers/video/omap2/Kconfig" -source "drivers/video/exynos/Kconfig" -source "drivers/video/mmp/Kconfig" -source "drivers/video/backlight/Kconfig" - if VT source "drivers/video/console/Kconfig" endif if FB || SGI_NEWPORT_CONSOLE source "drivers/video/logo/Kconfig" -endif -config FB_SH_MOBILE_MERAM - tristate "SuperH Mobile MERAM read ahead support" - depends on (SUPERH || ARCH_SHMOBILE) - select GENERIC_ALLOCATOR - ---help--- - Enable MERAM support for the SuperH controller. - - This will allow for caching of the framebuffer to provide more - reliable access under heavy main memory bus traffic situations. - Up to 4 memory channels can be configured, allowing 4 RGB or - 2 YCbCr framebuffers to be configured. +endif -config FB_SSD1307 - tristate "Solomon SSD1307 framebuffer support" - depends on FB && I2C - depends on OF - depends on GPIOLIB - select FB_SYS_FOPS - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT - select FB_DEFERRED_IO - select PWM - help - This driver implements support for the Solomon SSD1307 - OLED controller over I2C. endmenu diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 1be26fe1059..9ad3c17d645 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -1,175 +1,11 @@ -# Makefile for the Linux video drivers. -# 5 Aug 1999, James Simmons, -# Rewritten to use lists instead of if-statements. - -# Each configuration option enables a list of files. - obj-$(CONFIG_VGASTATE) += vgastate.o obj-$(CONFIG_HDMI) += hdmi.o -obj-y += fb_notify.o -obj-$(CONFIG_FB) += fb.o -fb-y := fbmem.o fbmon.o fbcmap.o fbsysfs.o \ - modedb.o fbcvt.o -fb-objs := $(fb-y) obj-$(CONFIG_VT) += console/ obj-$(CONFIG_LOGO) += logo/ obj-y += backlight/ -obj-$(CONFIG_EXYNOS_VIDEO) += exynos/ - -obj-$(CONFIG_FB_CFB_FILLRECT) += cfbfillrect.o -obj-$(CONFIG_FB_CFB_COPYAREA) += cfbcopyarea.o -obj-$(CONFIG_FB_CFB_IMAGEBLIT) += cfbimgblt.o -obj-$(CONFIG_FB_SYS_FILLRECT) += sysfillrect.o -obj-$(CONFIG_FB_SYS_COPYAREA) += syscopyarea.o -obj-$(CONFIG_FB_SYS_IMAGEBLIT) += sysimgblt.o -obj-$(CONFIG_FB_SYS_FOPS) += fb_sys_fops.o -obj-$(CONFIG_FB_SVGALIB) += svgalib.o -obj-$(CONFIG_FB_MACMODES) += macmodes.o -obj-$(CONFIG_FB_DDC) += fb_ddc.o -obj-$(CONFIG_FB_DEFERRED_IO) += fb_defio.o -obj-$(CONFIG_FB_WMT_GE_ROPS) += wmt_ge_rops.o - -# Hardware specific drivers go first -obj-$(CONFIG_FB_AMIGA) += amifb.o c2p_planar.o -obj-$(CONFIG_FB_ARC) += arcfb.o -obj-$(CONFIG_FB_CLPS711X) += clps711xfb.o -obj-$(CONFIG_FB_CYBER2000) += cyber2000fb.o -obj-$(CONFIG_FB_GRVGA) += grvga.o -obj-$(CONFIG_FB_PM2) += pm2fb.o -obj-$(CONFIG_FB_PM3) += pm3fb.o - -obj-$(CONFIG_FB_I740) += i740fb.o -obj-$(CONFIG_FB_MATROX) += matrox/ -obj-$(CONFIG_FB_RIVA) += riva/ -obj-$(CONFIG_FB_NVIDIA) += nvidia/ -obj-$(CONFIG_FB_ATY) += aty/ macmodes.o -obj-$(CONFIG_FB_ATY128) += aty/ macmodes.o -obj-$(CONFIG_FB_RADEON) += aty/ -obj-$(CONFIG_FB_SIS) += sis/ -obj-$(CONFIG_FB_VIA) += via/ -obj-$(CONFIG_FB_KYRO) += kyro/ -obj-$(CONFIG_FB_SAVAGE) += savage/ -obj-$(CONFIG_FB_GEODE) += geode/ -obj-$(CONFIG_FB_MBX) += mbx/ -obj-$(CONFIG_FB_NEOMAGIC) += neofb.o -obj-$(CONFIG_FB_3DFX) += tdfxfb.o -obj-$(CONFIG_FB_CONTROL) += controlfb.o -obj-$(CONFIG_FB_PLATINUM) += platinumfb.o -obj-$(CONFIG_FB_VALKYRIE) += valkyriefb.o -obj-$(CONFIG_FB_CT65550) += chipsfb.o -obj-$(CONFIG_FB_IMSTT) += imsttfb.o -obj-$(CONFIG_FB_FM2) += fm2fb.o -obj-$(CONFIG_FB_VT8623) += vt8623fb.o -obj-$(CONFIG_FB_TRIDENT) += tridentfb.o -obj-$(CONFIG_FB_LE80578) += vermilion/ -obj-$(CONFIG_FB_S3) += s3fb.o -obj-$(CONFIG_FB_ARK) += arkfb.o -obj-$(CONFIG_FB_STI) += stifb.o -obj-$(CONFIG_FB_FFB) += ffb.o sbuslib.o -obj-$(CONFIG_FB_CG6) += cg6.o sbuslib.o -obj-$(CONFIG_FB_CG3) += cg3.o sbuslib.o -obj-$(CONFIG_FB_BW2) += bw2.o sbuslib.o -obj-$(CONFIG_FB_CG14) += cg14.o sbuslib.o -obj-$(CONFIG_FB_P9100) += p9100.o sbuslib.o -obj-$(CONFIG_FB_TCX) += tcx.o sbuslib.o -obj-$(CONFIG_FB_LEO) += leo.o sbuslib.o -obj-$(CONFIG_FB_ACORN) += acornfb.o -obj-$(CONFIG_FB_ATARI) += atafb.o c2p_iplan2.o atafb_mfb.o \ - atafb_iplan2p2.o atafb_iplan2p4.o atafb_iplan2p8.o -obj-$(CONFIG_FB_MAC) += macfb.o -obj-$(CONFIG_FB_HECUBA) += hecubafb.o -obj-$(CONFIG_FB_N411) += n411.o -obj-$(CONFIG_FB_HGA) += hgafb.o -obj-$(CONFIG_FB_XVR500) += sunxvr500.o -obj-$(CONFIG_FB_XVR2500) += sunxvr2500.o -obj-$(CONFIG_FB_XVR1000) += sunxvr1000.o -obj-$(CONFIG_FB_IGA) += igafb.o -obj-$(CONFIG_FB_APOLLO) += dnfb.o -obj-$(CONFIG_FB_Q40) += q40fb.o -obj-$(CONFIG_FB_TGA) += tgafb.o -obj-$(CONFIG_FB_HP300) += hpfb.o -obj-$(CONFIG_FB_G364) += g364fb.o -obj-$(CONFIG_FB_EP93XX) += ep93xx-fb.o -obj-$(CONFIG_FB_SA1100) += sa1100fb.o -obj-$(CONFIG_FB_HIT) += hitfb.o -obj-$(CONFIG_FB_ATMEL) += atmel_lcdfb.o -obj-$(CONFIG_FB_PVR2) += pvr2fb.o -obj-$(CONFIG_FB_VOODOO1) += sstfb.o -obj-$(CONFIG_FB_ARMCLCD) += amba-clcd.o -obj-$(CONFIG_FB_GOLDFISH) += goldfishfb.o -obj-$(CONFIG_FB_68328) += 68328fb.o -obj-$(CONFIG_FB_GBE) += gbefb.o -obj-$(CONFIG_FB_CIRRUS) += cirrusfb.o -obj-$(CONFIG_FB_ASILIANT) += asiliantfb.o -obj-$(CONFIG_FB_PXA) += pxafb.o -obj-$(CONFIG_FB_PXA168) += pxa168fb.o -obj-$(CONFIG_PXA3XX_GCU) += pxa3xx-gcu.o -obj-$(CONFIG_MMP_DISP) += mmp/ -obj-$(CONFIG_FB_W100) += w100fb.o -obj-$(CONFIG_FB_TMIO) += tmiofb.o -obj-$(CONFIG_FB_AU1100) += au1100fb.o -obj-$(CONFIG_FB_AU1200) += au1200fb.o -obj-$(CONFIG_FB_VT8500) += vt8500lcdfb.o -obj-$(CONFIG_FB_WM8505) += wm8505fb.o -obj-$(CONFIG_FB_PMAG_AA) += pmag-aa-fb.o -obj-$(CONFIG_FB_PMAG_BA) += pmag-ba-fb.o -obj-$(CONFIG_FB_PMAGB_B) += pmagb-b-fb.o -obj-$(CONFIG_FB_MAXINE) += maxinefb.o -obj-$(CONFIG_FB_METRONOME) += metronomefb.o -obj-$(CONFIG_FB_BROADSHEET) += broadsheetfb.o -obj-$(CONFIG_FB_AUO_K190X) += auo_k190x.o -obj-$(CONFIG_FB_AUO_K1900) += auo_k1900fb.o -obj-$(CONFIG_FB_AUO_K1901) += auo_k1901fb.o -obj-$(CONFIG_FB_S1D13XXX) += s1d13xxxfb.o -obj-$(CONFIG_FB_SH7760) += sh7760fb.o -obj-$(CONFIG_FB_IMX) += imxfb.o -obj-$(CONFIG_FB_S3C) += s3c-fb.o -obj-$(CONFIG_FB_S3C2410) += s3c2410fb.o -obj-$(CONFIG_FB_FSL_DIU) += fsl-diu-fb.o -obj-$(CONFIG_FB_COBALT) += cobalt_lcdfb.o -obj-$(CONFIG_FB_IBM_GXT4500) += gxt4500.o -obj-$(CONFIG_FB_PS3) += ps3fb.o -obj-$(CONFIG_FB_SM501) += sm501fb.o -obj-$(CONFIG_FB_UDL) += udlfb.o -obj-$(CONFIG_FB_SMSCUFX) += smscufx.o -obj-$(CONFIG_FB_XILINX) += xilinxfb.o -obj-$(CONFIG_SH_MIPI_DSI) += sh_mipi_dsi.o -obj-$(CONFIG_FB_SH_MOBILE_HDMI) += sh_mobile_hdmi.o -obj-$(CONFIG_FB_SH_MOBILE_MERAM) += sh_mobile_meram.o -obj-$(CONFIG_FB_SH_MOBILE_LCDC) += sh_mobile_lcdcfb.o -obj-$(CONFIG_FB_OMAP) += omap/ -obj-y += omap2/ -obj-$(CONFIG_XEN_FBDEV_FRONTEND) += xen-fbfront.o -obj-$(CONFIG_FB_CARMINE) += carminefb.o -obj-$(CONFIG_FB_MB862XX) += mb862xx/ -obj-$(CONFIG_FB_MSM) += msm/ -obj-$(CONFIG_FB_NUC900) += nuc900fb.o -obj-$(CONFIG_FB_JZ4740) += jz4740_fb.o -obj-$(CONFIG_FB_PUV3_UNIGFX) += fb-puv3.o -obj-$(CONFIG_FB_HYPERV) += hyperv_fb.o -obj-$(CONFIG_FB_OPENCORES) += ocfb.o - -# Platform or fallback drivers go here -obj-$(CONFIG_FB_UVESA) += uvesafb.o -obj-$(CONFIG_FB_VESA) += vesafb.o -obj-$(CONFIG_FB_EFI) += efifb.o -obj-$(CONFIG_FB_VGA16) += vga16fb.o -obj-$(CONFIG_FB_OF) += offb.o -obj-$(CONFIG_FB_BF537_LQ035) += bf537-lq035.o -obj-$(CONFIG_FB_BF54X_LQ043) += bf54x-lq043fb.o -obj-$(CONFIG_FB_BFIN_LQ035Q1) += bfin-lq035q1-fb.o -obj-$(CONFIG_FB_BFIN_T350MCQB) += bfin-t350mcqb-fb.o -obj-$(CONFIG_FB_BFIN_7393) += bfin_adv7393fb.o -obj-$(CONFIG_FB_MX3) += mx3fb.o -obj-$(CONFIG_FB_DA8XX) += da8xx-fb.o -obj-$(CONFIG_FB_MXS) += mxsfb.o -obj-$(CONFIG_FB_SSD1307) += ssd1307fb.o -obj-$(CONFIG_FB_SIMPLE) += simplefb.o - -# the test framebuffer is last -obj-$(CONFIG_FB_VIRTUAL) += vfb.o +obj-y += fbdev/ obj-$(CONFIG_VIDEOMODE_HELPERS) += display_timing.o videomode.o ifeq ($(CONFIG_OF),y) diff --git a/drivers/video/acornfb.c b/drivers/video/acornfb.c deleted file mode 100644 index a305caea58e..00000000000 --- a/drivers/video/acornfb.c +++ /dev/null @@ -1,1143 +0,0 @@ -/* - * linux/drivers/video/acornfb.c - * - * Copyright (C) 1998-2001 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Frame buffer code for Acorn platforms - * - * NOTE: Most of the modes with X!=640 will disappear shortly. - * NOTE: Startup setting of HS & VS polarity not supported. - * (do we need to support it if we're coming up in 640x480?) - * - * FIXME: (things broken by the "new improved" FBCON API) - * - Blanking 8bpp displays with VIDC - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "acornfb.h" - -/* - * Default resolution. - * NOTE that it has to be supported in the table towards - * the end of this file. - */ -#define DEFAULT_XRES 640 -#define DEFAULT_YRES 480 -#define DEFAULT_BPP 4 - -/* - * define this to debug the video mode selection - */ -#undef DEBUG_MODE_SELECTION - -/* - * Translation from RISC OS monitor types to actual - * HSYNC and VSYNC frequency ranges. These are - * probably not right, but they're the best info I - * have. Allow 1% either way on the nominal for TVs. - */ -#define NR_MONTYPES 6 -static struct fb_monspecs monspecs[NR_MONTYPES] = { - { /* TV */ - .hfmin = 15469, - .hfmax = 15781, - .vfmin = 49, - .vfmax = 51, - }, { /* Multi Freq */ - .hfmin = 0, - .hfmax = 99999, - .vfmin = 0, - .vfmax = 199, - }, { /* Hi-res mono */ - .hfmin = 58608, - .hfmax = 58608, - .vfmin = 64, - .vfmax = 64, - }, { /* VGA */ - .hfmin = 30000, - .hfmax = 70000, - .vfmin = 60, - .vfmax = 60, - }, { /* SVGA */ - .hfmin = 30000, - .hfmax = 70000, - .vfmin = 56, - .vfmax = 75, - }, { - .hfmin = 30000, - .hfmax = 70000, - .vfmin = 60, - .vfmax = 60, - } -}; - -static struct fb_info fb_info; -static struct acornfb_par current_par; -static struct vidc_timing current_vidc; - -extern unsigned int vram_size; /* set by setup.c */ - -#ifdef HAS_VIDC20 -#include - -#define MAX_SIZE 2*1024*1024 - -/* VIDC20 has a different set of rules from the VIDC: - * hcr : must be multiple of 4 - * hswr : must be even - * hdsr : must be even - * hder : must be even - * vcr : >= 2, (interlace, must be odd) - * vswr : >= 1 - * vdsr : >= 1 - * vder : >= vdsr - */ -static void acornfb_set_timing(struct fb_info *info) -{ - struct fb_var_screeninfo *var = &info->var; - struct vidc_timing vidc; - u_int vcr, fsize; - u_int ext_ctl, dat_ctl; - u_int words_per_line; - - memset(&vidc, 0, sizeof(vidc)); - - vidc.h_sync_width = var->hsync_len - 8; - vidc.h_border_start = vidc.h_sync_width + var->left_margin + 8 - 12; - vidc.h_display_start = vidc.h_border_start + 12 - 18; - vidc.h_display_end = vidc.h_display_start + var->xres; - vidc.h_border_end = vidc.h_display_end + 18 - 12; - vidc.h_cycle = vidc.h_border_end + var->right_margin + 12 - 8; - vidc.h_interlace = vidc.h_cycle / 2; - vidc.v_sync_width = var->vsync_len - 1; - vidc.v_border_start = vidc.v_sync_width + var->upper_margin; - vidc.v_display_start = vidc.v_border_start; - vidc.v_display_end = vidc.v_display_start + var->yres; - vidc.v_border_end = vidc.v_display_end; - vidc.control = acornfb_default_control(); - - vcr = var->vsync_len + var->upper_margin + var->yres + - var->lower_margin; - - if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) { - vidc.v_cycle = (vcr - 3) / 2; - vidc.control |= VIDC20_CTRL_INT; - } else - vidc.v_cycle = vcr - 2; - - switch (var->bits_per_pixel) { - case 1: vidc.control |= VIDC20_CTRL_1BPP; break; - case 2: vidc.control |= VIDC20_CTRL_2BPP; break; - case 4: vidc.control |= VIDC20_CTRL_4BPP; break; - default: - case 8: vidc.control |= VIDC20_CTRL_8BPP; break; - case 16: vidc.control |= VIDC20_CTRL_16BPP; break; - case 32: vidc.control |= VIDC20_CTRL_32BPP; break; - } - - acornfb_vidc20_find_rates(&vidc, var); - fsize = var->vsync_len + var->upper_margin + var->lower_margin - 1; - - if (memcmp(¤t_vidc, &vidc, sizeof(vidc))) { - current_vidc = vidc; - - vidc_writel(VIDC20_CTRL| vidc.control); - vidc_writel(0xd0000000 | vidc.pll_ctl); - vidc_writel(0x80000000 | vidc.h_cycle); - vidc_writel(0x81000000 | vidc.h_sync_width); - vidc_writel(0x82000000 | vidc.h_border_start); - vidc_writel(0x83000000 | vidc.h_display_start); - vidc_writel(0x84000000 | vidc.h_display_end); - vidc_writel(0x85000000 | vidc.h_border_end); - vidc_writel(0x86000000); - vidc_writel(0x87000000 | vidc.h_interlace); - vidc_writel(0x90000000 | vidc.v_cycle); - vidc_writel(0x91000000 | vidc.v_sync_width); - vidc_writel(0x92000000 | vidc.v_border_start); - vidc_writel(0x93000000 | vidc.v_display_start); - vidc_writel(0x94000000 | vidc.v_display_end); - vidc_writel(0x95000000 | vidc.v_border_end); - vidc_writel(0x96000000); - vidc_writel(0x97000000); - } - - iomd_writel(fsize, IOMD_FSIZE); - - ext_ctl = acornfb_default_econtrol(); - - if (var->sync & FB_SYNC_COMP_HIGH_ACT) /* should be FB_SYNC_COMP */ - ext_ctl |= VIDC20_ECTL_HS_NCSYNC | VIDC20_ECTL_VS_NCSYNC; - else { - if (var->sync & FB_SYNC_HOR_HIGH_ACT) - ext_ctl |= VIDC20_ECTL_HS_HSYNC; - else - ext_ctl |= VIDC20_ECTL_HS_NHSYNC; - - if (var->sync & FB_SYNC_VERT_HIGH_ACT) - ext_ctl |= VIDC20_ECTL_VS_VSYNC; - else - ext_ctl |= VIDC20_ECTL_VS_NVSYNC; - } - - vidc_writel(VIDC20_ECTL | ext_ctl); - - words_per_line = var->xres * var->bits_per_pixel / 32; - - if (current_par.using_vram && info->fix.smem_len == 2048*1024) - words_per_line /= 2; - - /* RiscPC doesn't use the VIDC's VRAM control. */ - dat_ctl = VIDC20_DCTL_VRAM_DIS | VIDC20_DCTL_SNA | words_per_line; - - /* The data bus width is dependent on both the type - * and amount of video memory. - * DRAM 32bit low - * 1MB VRAM 32bit - * 2MB VRAM 64bit - */ - if (current_par.using_vram && current_par.vram_half_sam == 2048) - dat_ctl |= VIDC20_DCTL_BUS_D63_0; - else - dat_ctl |= VIDC20_DCTL_BUS_D31_0; - - vidc_writel(VIDC20_DCTL | dat_ctl); - -#ifdef DEBUG_MODE_SELECTION - printk(KERN_DEBUG "VIDC registers for %dx%dx%d:\n", var->xres, - var->yres, var->bits_per_pixel); - printk(KERN_DEBUG " H-cycle : %d\n", vidc.h_cycle); - printk(KERN_DEBUG " H-sync-width : %d\n", vidc.h_sync_width); - printk(KERN_DEBUG " H-border-start : %d\n", vidc.h_border_start); - printk(KERN_DEBUG " H-display-start : %d\n", vidc.h_display_start); - printk(KERN_DEBUG " H-display-end : %d\n", vidc.h_display_end); - printk(KERN_DEBUG " H-border-end : %d\n", vidc.h_border_end); - printk(KERN_DEBUG " H-interlace : %d\n", vidc.h_interlace); - printk(KERN_DEBUG " V-cycle : %d\n", vidc.v_cycle); - printk(KERN_DEBUG " V-sync-width : %d\n", vidc.v_sync_width); - printk(KERN_DEBUG " V-border-start : %d\n", vidc.v_border_start); - printk(KERN_DEBUG " V-display-start : %d\n", vidc.v_display_start); - printk(KERN_DEBUG " V-display-end : %d\n", vidc.v_display_end); - printk(KERN_DEBUG " V-border-end : %d\n", vidc.v_border_end); - printk(KERN_DEBUG " Ext Ctrl (C) : 0x%08X\n", ext_ctl); - printk(KERN_DEBUG " PLL Ctrl (D) : 0x%08X\n", vidc.pll_ctl); - printk(KERN_DEBUG " Ctrl (E) : 0x%08X\n", vidc.control); - printk(KERN_DEBUG " Data Ctrl (F) : 0x%08X\n", dat_ctl); - printk(KERN_DEBUG " Fsize : 0x%08X\n", fsize); -#endif -} - -/* - * We have to take note of the VIDC20's 16-bit palette here. - * The VIDC20 looks up a 16 bit pixel as follows: - * - * bits 111111 - * 5432109876543210 - * red ++++++++ (8 bits, 7 to 0) - * green ++++++++ (8 bits, 11 to 4) - * blue ++++++++ (8 bits, 15 to 8) - * - * We use a pixel which looks like: - * - * bits 111111 - * 5432109876543210 - * red +++++ (5 bits, 4 to 0) - * green +++++ (5 bits, 9 to 5) - * blue +++++ (5 bits, 14 to 10) - */ -static int -acornfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int trans, struct fb_info *info) -{ - union palette pal; - - if (regno >= current_par.palette_size) - return 1; - - if (regno < 16 && info->fix.visual == FB_VISUAL_DIRECTCOLOR) { - u32 pseudo_val; - - pseudo_val = regno << info->var.red.offset; - pseudo_val |= regno << info->var.green.offset; - pseudo_val |= regno << info->var.blue.offset; - - ((u32 *)info->pseudo_palette)[regno] = pseudo_val; - } - - pal.p = 0; - pal.vidc20.red = red >> 8; - pal.vidc20.green = green >> 8; - pal.vidc20.blue = blue >> 8; - - current_par.palette[regno] = pal; - - if (info->var.bits_per_pixel == 16) { - int i; - - pal.p = 0; - vidc_writel(0x10000000); - for (i = 0; i < 256; i += 1) { - pal.vidc20.red = current_par.palette[ i & 31].vidc20.red; - pal.vidc20.green = current_par.palette[(i >> 1) & 31].vidc20.green; - pal.vidc20.blue = current_par.palette[(i >> 2) & 31].vidc20.blue; - vidc_writel(pal.p); - /* Palette register pointer auto-increments */ - } - } else { - vidc_writel(0x10000000 | regno); - vidc_writel(pal.p); - } - - return 0; -} -#endif - -/* - * Before selecting the timing parameters, adjust - * the resolution to fit the rules. - */ -static int -acornfb_adjust_timing(struct fb_info *info, struct fb_var_screeninfo *var, u_int fontht) -{ - u_int font_line_len, sam_size, min_size, size, nr_y; - - /* xres must be even */ - var->xres = (var->xres + 1) & ~1; - - /* - * We don't allow xres_virtual to differ from xres - */ - var->xres_virtual = var->xres; - var->xoffset = 0; - - if (current_par.using_vram) - sam_size = current_par.vram_half_sam * 2; - else - sam_size = 16; - - /* - * Now, find a value for yres_virtual which allows - * us to do ywrap scrolling. The value of - * yres_virtual must be such that the end of the - * displayable frame buffer must be aligned with - * the start of a font line. - */ - font_line_len = var->xres * var->bits_per_pixel * fontht / 8; - min_size = var->xres * var->yres * var->bits_per_pixel / 8; - - /* - * If minimum screen size is greater than that we have - * available, reject it. - */ - if (min_size > info->fix.smem_len) - return -EINVAL; - - /* Find int 'y', such that y * fll == s * sam < maxsize - * y = s * sam / fll; s = maxsize / sam - */ - for (size = info->fix.smem_len; - nr_y = size / font_line_len, min_size <= size; - size -= sam_size) { - if (nr_y * font_line_len == size) - break; - } - nr_y *= fontht; - - if (var->accel_flags & FB_ACCELF_TEXT) { - if (min_size > size) { - /* - * failed, use ypan - */ - size = info->fix.smem_len; - var->yres_virtual = size / (font_line_len / fontht); - } else - var->yres_virtual = nr_y; - } else if (var->yres_virtual > nr_y) - var->yres_virtual = nr_y; - - current_par.screen_end = info->fix.smem_start + size; - - /* - * Fix yres & yoffset if needed. - */ - if (var->yres > var->yres_virtual) - var->yres = var->yres_virtual; - - if (var->vmode & FB_VMODE_YWRAP) { - if (var->yoffset > var->yres_virtual) - var->yoffset = var->yres_virtual; - } else { - if (var->yoffset + var->yres > var->yres_virtual) - var->yoffset = var->yres_virtual - var->yres; - } - - /* hsync_len must be even */ - var->hsync_len = (var->hsync_len + 1) & ~1; - -#if defined(HAS_VIDC20) - /* left_margin must be even */ - if (var->left_margin & 1) { - var->left_margin += 1; - var->right_margin -= 1; - } - - /* right_margin must be even */ - if (var->right_margin & 1) - var->right_margin += 1; -#endif - - if (var->vsync_len < 1) - var->vsync_len = 1; - - return 0; -} - -static int -acornfb_validate_timing(struct fb_var_screeninfo *var, - struct fb_monspecs *monspecs) -{ - unsigned long hs, vs; - - /* - * hs(Hz) = 10^12 / (pixclock * xtotal) - * vs(Hz) = hs(Hz) / ytotal - * - * No need to do long long divisions or anything - * like that if you factor it correctly - */ - hs = 1953125000 / var->pixclock; - hs = hs * 512 / - (var->xres + var->left_margin + var->right_margin + var->hsync_len); - vs = hs / - (var->yres + var->upper_margin + var->lower_margin + var->vsync_len); - - return (vs >= monspecs->vfmin && vs <= monspecs->vfmax && - hs >= monspecs->hfmin && hs <= monspecs->hfmax) ? 0 : -EINVAL; -} - -static inline void -acornfb_update_dma(struct fb_info *info, struct fb_var_screeninfo *var) -{ - u_int off = var->yoffset * info->fix.line_length; - -#if defined(HAS_MEMC) - memc_write(VDMA_INIT, off >> 2); -#elif defined(HAS_IOMD) - iomd_writel(info->fix.smem_start + off, IOMD_VIDINIT); -#endif -} - -static int -acornfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) -{ - u_int fontht; - int err; - - /* - * FIXME: Find the font height - */ - fontht = 8; - - var->red.msb_right = 0; - var->green.msb_right = 0; - var->blue.msb_right = 0; - var->transp.msb_right = 0; - - switch (var->bits_per_pixel) { - case 1: case 2: case 4: case 8: - var->red.offset = 0; - var->red.length = var->bits_per_pixel; - var->green = var->red; - var->blue = var->red; - var->transp.offset = 0; - var->transp.length = 0; - break; - -#ifdef HAS_VIDC20 - case 16: - var->red.offset = 0; - var->red.length = 5; - var->green.offset = 5; - var->green.length = 5; - var->blue.offset = 10; - var->blue.length = 5; - var->transp.offset = 15; - var->transp.length = 1; - break; - - case 32: - var->red.offset = 0; - var->red.length = 8; - var->green.offset = 8; - var->green.length = 8; - var->blue.offset = 16; - var->blue.length = 8; - var->transp.offset = 24; - var->transp.length = 4; - break; -#endif - default: - return -EINVAL; - } - - /* - * Check to see if the pixel rate is valid. - */ - if (!acornfb_valid_pixrate(var)) - return -EINVAL; - - /* - * Validate and adjust the resolution to - * match the video generator hardware. - */ - err = acornfb_adjust_timing(info, var, fontht); - if (err) - return err; - - /* - * Validate the timing against the - * monitor hardware. - */ - return acornfb_validate_timing(var, &info->monspecs); -} - -static int acornfb_set_par(struct fb_info *info) -{ - switch (info->var.bits_per_pixel) { - case 1: - current_par.palette_size = 2; - info->fix.visual = FB_VISUAL_MONO10; - break; - case 2: - current_par.palette_size = 4; - info->fix.visual = FB_VISUAL_PSEUDOCOLOR; - break; - case 4: - current_par.palette_size = 16; - info->fix.visual = FB_VISUAL_PSEUDOCOLOR; - break; - case 8: - current_par.palette_size = VIDC_PALETTE_SIZE; - info->fix.visual = FB_VISUAL_PSEUDOCOLOR; - break; -#ifdef HAS_VIDC20 - case 16: - current_par.palette_size = 32; - info->fix.visual = FB_VISUAL_DIRECTCOLOR; - break; - case 32: - current_par.palette_size = VIDC_PALETTE_SIZE; - info->fix.visual = FB_VISUAL_DIRECTCOLOR; - break; -#endif - default: - BUG(); - } - - info->fix.line_length = (info->var.xres * info->var.bits_per_pixel) / 8; - -#if defined(HAS_MEMC) - { - unsigned long size = info->fix.smem_len - VDMA_XFERSIZE; - - memc_write(VDMA_START, 0); - memc_write(VDMA_END, size >> 2); - } -#elif defined(HAS_IOMD) - { - unsigned long start, size; - u_int control; - - start = info->fix.smem_start; - size = current_par.screen_end; - - if (current_par.using_vram) { - size -= current_par.vram_half_sam; - control = DMA_CR_E | (current_par.vram_half_sam / 256); - } else { - size -= 16; - control = DMA_CR_E | DMA_CR_D | 16; - } - - iomd_writel(start, IOMD_VIDSTART); - iomd_writel(size, IOMD_VIDEND); - iomd_writel(control, IOMD_VIDCR); - } -#endif - - acornfb_update_dma(info, &info->var); - acornfb_set_timing(info); - - return 0; -} - -static int -acornfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) -{ - u_int y_bottom = var->yoffset; - - if (!(var->vmode & FB_VMODE_YWRAP)) - y_bottom += info->var.yres; - - if (y_bottom > info->var.yres_virtual) - return -EINVAL; - - acornfb_update_dma(info, var); - - return 0; -} - -static struct fb_ops acornfb_ops = { - .owner = THIS_MODULE, - .fb_check_var = acornfb_check_var, - .fb_set_par = acornfb_set_par, - .fb_setcolreg = acornfb_setcolreg, - .fb_pan_display = acornfb_pan_display, - .fb_fillrect = cfb_fillrect, - .fb_copyarea = cfb_copyarea, - .fb_imageblit = cfb_imageblit, -}; - -/* - * Everything after here is initialisation!!! - */ -static struct fb_videomode modedb[] = { - { /* 320x256 @ 50Hz */ - NULL, 50, 320, 256, 125000, 92, 62, 35, 19, 38, 2, - FB_SYNC_COMP_HIGH_ACT, - FB_VMODE_NONINTERLACED - }, { /* 640x250 @ 50Hz, 15.6 kHz hsync */ - NULL, 50, 640, 250, 62500, 185, 123, 38, 21, 76, 3, - 0, - FB_VMODE_NONINTERLACED - }, { /* 640x256 @ 50Hz, 15.6 kHz hsync */ - NULL, 50, 640, 256, 62500, 185, 123, 35, 18, 76, 3, - 0, - FB_VMODE_NONINTERLACED - }, { /* 640x512 @ 50Hz, 26.8 kHz hsync */ - NULL, 50, 640, 512, 41667, 113, 87, 18, 1, 56, 3, - 0, - FB_VMODE_NONINTERLACED - }, { /* 640x250 @ 70Hz, 31.5 kHz hsync */ - NULL, 70, 640, 250, 39722, 48, 16, 109, 88, 96, 2, - 0, - FB_VMODE_NONINTERLACED - }, { /* 640x256 @ 70Hz, 31.5 kHz hsync */ - NULL, 70, 640, 256, 39722, 48, 16, 106, 85, 96, 2, - 0, - FB_VMODE_NONINTERLACED - }, { /* 640x352 @ 70Hz, 31.5 kHz hsync */ - NULL, 70, 640, 352, 39722, 48, 16, 58, 37, 96, 2, - 0, - FB_VMODE_NONINTERLACED - }, { /* 640x480 @ 60Hz, 31.5 kHz hsync */ - NULL, 60, 640, 480, 39722, 48, 16, 32, 11, 96, 2, - 0, - FB_VMODE_NONINTERLACED - }, { /* 800x600 @ 56Hz, 35.2 kHz hsync */ - NULL, 56, 800, 600, 27778, 101, 23, 22, 1, 100, 2, - 0, - FB_VMODE_NONINTERLACED - }, { /* 896x352 @ 60Hz, 21.8 kHz hsync */ - NULL, 60, 896, 352, 41667, 59, 27, 9, 0, 118, 3, - 0, - FB_VMODE_NONINTERLACED - }, { /* 1024x 768 @ 60Hz, 48.4 kHz hsync */ - NULL, 60, 1024, 768, 15385, 160, 24, 29, 3, 136, 6, - 0, - FB_VMODE_NONINTERLACED - }, { /* 1280x1024 @ 60Hz, 63.8 kHz hsync */ - NULL, 60, 1280, 1024, 9090, 186, 96, 38, 1, 160, 3, - 0, - FB_VMODE_NONINTERLACED - } -}; - -static struct fb_videomode acornfb_default_mode = { - .name = NULL, - .refresh = 60, - .xres = 640, - .yres = 480, - .pixclock = 39722, - .left_margin = 56, - .right_margin = 16, - .upper_margin = 34, - .lower_margin = 9, - .hsync_len = 88, - .vsync_len = 2, - .sync = 0, - .vmode = FB_VMODE_NONINTERLACED -}; - -static void acornfb_init_fbinfo(void) -{ - static int first = 1; - - if (!first) - return; - first = 0; - - fb_info.fbops = &acornfb_ops; - fb_info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; - fb_info.pseudo_palette = current_par.pseudo_palette; - - strcpy(fb_info.fix.id, "Acorn"); - fb_info.fix.type = FB_TYPE_PACKED_PIXELS; - fb_info.fix.type_aux = 0; - fb_info.fix.xpanstep = 0; - fb_info.fix.ypanstep = 1; - fb_info.fix.ywrapstep = 1; - fb_info.fix.line_length = 0; - fb_info.fix.accel = FB_ACCEL_NONE; - - /* - * setup initial parameters - */ - memset(&fb_info.var, 0, sizeof(fb_info.var)); - -#if defined(HAS_VIDC20) - fb_info.var.red.length = 8; - fb_info.var.transp.length = 4; -#endif - fb_info.var.green = fb_info.var.red; - fb_info.var.blue = fb_info.var.red; - fb_info.var.nonstd = 0; - fb_info.var.activate = FB_ACTIVATE_NOW; - fb_info.var.height = -1; - fb_info.var.width = -1; - fb_info.var.vmode = FB_VMODE_NONINTERLACED; - fb_info.var.accel_flags = FB_ACCELF_TEXT; - - current_par.dram_size = 0; - current_par.montype = -1; - current_par.dpms = 0; -} - -/* - * setup acornfb options: - * - * mon:hmin-hmax:vmin-vmax:dpms:width:height - * Set monitor parameters: - * hmin = horizontal minimum frequency (Hz) - * hmax = horizontal maximum frequency (Hz) (optional) - * vmin = vertical minimum frequency (Hz) - * vmax = vertical maximum frequency (Hz) (optional) - * dpms = DPMS supported? (optional) - * width = width of picture in mm. (optional) - * height = height of picture in mm. (optional) - * - * montype:type - * Set RISC-OS style monitor type: - * 0 (or tv) - TV frequency - * 1 (or multi) - Multi frequency - * 2 (or hires) - Hi-res monochrome - * 3 (or vga) - VGA - * 4 (or svga) - SVGA - * auto, or option missing - * - try hardware detect - * - * dram:size - * Set the amount of DRAM to use for the frame buffer - * (even if you have VRAM). - * size can optionally be followed by 'M' or 'K' for - * MB or KB respectively. - */ -static void acornfb_parse_mon(char *opt) -{ - char *p = opt; - - current_par.montype = -2; - - fb_info.monspecs.hfmin = simple_strtoul(p, &p, 0); - if (*p == '-') - fb_info.monspecs.hfmax = simple_strtoul(p + 1, &p, 0); - else - fb_info.monspecs.hfmax = fb_info.monspecs.hfmin; - - if (*p != ':') - goto bad; - - fb_info.monspecs.vfmin = simple_strtoul(p + 1, &p, 0); - if (*p == '-') - fb_info.monspecs.vfmax = simple_strtoul(p + 1, &p, 0); - else - fb_info.monspecs.vfmax = fb_info.monspecs.vfmin; - - if (*p != ':') - goto check_values; - - fb_info.monspecs.dpms = simple_strtoul(p + 1, &p, 0); - - if (*p != ':') - goto check_values; - - fb_info.var.width = simple_strtoul(p + 1, &p, 0); - - if (*p != ':') - goto check_values; - - fb_info.var.height = simple_strtoul(p + 1, NULL, 0); - -check_values: - if (fb_info.monspecs.hfmax < fb_info.monspecs.hfmin || - fb_info.monspecs.vfmax < fb_info.monspecs.vfmin) - goto bad; - return; - -bad: - printk(KERN_ERR "Acornfb: bad monitor settings: %s\n", opt); - current_par.montype = -1; -} - -static void acornfb_parse_montype(char *opt) -{ - current_par.montype = -2; - - if (strncmp(opt, "tv", 2) == 0) { - opt += 2; - current_par.montype = 0; - } else if (strncmp(opt, "multi", 5) == 0) { - opt += 5; - current_par.montype = 1; - } else if (strncmp(opt, "hires", 5) == 0) { - opt += 5; - current_par.montype = 2; - } else if (strncmp(opt, "vga", 3) == 0) { - opt += 3; - current_par.montype = 3; - } else if (strncmp(opt, "svga", 4) == 0) { - opt += 4; - current_par.montype = 4; - } else if (strncmp(opt, "auto", 4) == 0) { - opt += 4; - current_par.montype = -1; - } else if (isdigit(*opt)) - current_par.montype = simple_strtoul(opt, &opt, 0); - - if (current_par.montype == -2 || - current_par.montype > NR_MONTYPES) { - printk(KERN_ERR "acornfb: unknown monitor type: %s\n", - opt); - current_par.montype = -1; - } else - if (opt && *opt) { - if (strcmp(opt, ",dpms") == 0) - current_par.dpms = 1; - else - printk(KERN_ERR - "acornfb: unknown monitor option: %s\n", - opt); - } -} - -static void acornfb_parse_dram(char *opt) -{ - unsigned int size; - - size = simple_strtoul(opt, &opt, 0); - - if (opt) { - switch (*opt) { - case 'M': - case 'm': - size *= 1024; - case 'K': - case 'k': - size *= 1024; - default: - break; - } - } - - current_par.dram_size = size; -} - -static struct options { - char *name; - void (*parse)(char *opt); -} opt_table[] = { - { "mon", acornfb_parse_mon }, - { "montype", acornfb_parse_montype }, - { "dram", acornfb_parse_dram }, - { NULL, NULL } -}; - -static int acornfb_setup(char *options) -{ - struct options *optp; - char *opt; - - if (!options || !*options) - return 0; - - acornfb_init_fbinfo(); - - while ((opt = strsep(&options, ",")) != NULL) { - if (!*opt) - continue; - - for (optp = opt_table; optp->name; optp++) { - int optlen; - - optlen = strlen(optp->name); - - if (strncmp(opt, optp->name, optlen) == 0 && - opt[optlen] == ':') { - optp->parse(opt + optlen + 1); - break; - } - } - - if (!optp->name) - printk(KERN_ERR "acornfb: unknown parameter: %s\n", - opt); - } - return 0; -} - -/* - * Detect type of monitor connected - * For now, we just assume SVGA - */ -static int acornfb_detect_monitortype(void) -{ - return 4; -} - -/* - * This enables the unused memory to be freed on older Acorn machines. - * We are freeing memory on behalf of the architecture initialisation - * code here. - */ -static inline void -free_unused_pages(unsigned int virtual_start, unsigned int virtual_end) -{ - int mb_freed = 0; - - /* - * Align addresses - */ - virtual_start = PAGE_ALIGN(virtual_start); - virtual_end = PAGE_ALIGN(virtual_end); - - while (virtual_start < virtual_end) { - struct page *page; - - /* - * Clear page reserved bit, - * set count to 1, and free - * the page. - */ - page = virt_to_page(virtual_start); - __free_reserved_page(page); - - virtual_start += PAGE_SIZE; - mb_freed += PAGE_SIZE / 1024; - } - - printk("acornfb: freed %dK memory\n", mb_freed); -} - -static int acornfb_probe(struct platform_device *dev) -{ - unsigned long size; - u_int h_sync, v_sync; - int rc, i; - char *option = NULL; - - if (fb_get_options("acornfb", &option)) - return -ENODEV; - acornfb_setup(option); - - acornfb_init_fbinfo(); - - current_par.dev = &dev->dev; - - if (current_par.montype == -1) - current_par.montype = acornfb_detect_monitortype(); - - if (current_par.montype == -1 || current_par.montype > NR_MONTYPES) - current_par.montype = 4; - - if (current_par.montype >= 0) { - fb_info.monspecs = monspecs[current_par.montype]; - fb_info.monspecs.dpms = current_par.dpms; - } - - /* - * Try to select a suitable default mode - */ - for (i = 0; i < ARRAY_SIZE(modedb); i++) { - unsigned long hs; - - hs = modedb[i].refresh * - (modedb[i].yres + modedb[i].upper_margin + - modedb[i].lower_margin + modedb[i].vsync_len); - if (modedb[i].xres == DEFAULT_XRES && - modedb[i].yres == DEFAULT_YRES && - modedb[i].refresh >= fb_info.monspecs.vfmin && - modedb[i].refresh <= fb_info.monspecs.vfmax && - hs >= fb_info.monspecs.hfmin && - hs <= fb_info.monspecs.hfmax) { - acornfb_default_mode = modedb[i]; - break; - } - } - - fb_info.screen_base = (char *)SCREEN_BASE; - fb_info.fix.smem_start = SCREEN_START; - current_par.using_vram = 0; - - /* - * If vram_size is set, we are using VRAM in - * a Risc PC. However, if the user has specified - * an amount of DRAM then use that instead. - */ - if (vram_size && !current_par.dram_size) { - size = vram_size; - current_par.vram_half_sam = vram_size / 1024; - current_par.using_vram = 1; - } else if (current_par.dram_size) - size = current_par.dram_size; - else - size = MAX_SIZE; - - /* - * Limit maximum screen size. - */ - if (size > MAX_SIZE) - size = MAX_SIZE; - - size = PAGE_ALIGN(size); - -#if defined(HAS_VIDC20) - if (!current_par.using_vram) { - dma_addr_t handle; - void *base; - - /* - * RiscPC needs to allocate the DRAM memory - * for the framebuffer if we are not using - * VRAM. - */ - base = dma_alloc_writecombine(current_par.dev, size, &handle, - GFP_KERNEL); - if (base == NULL) { - printk(KERN_ERR "acornfb: unable to allocate screen " - "memory\n"); - return -ENOMEM; - } - - fb_info.screen_base = base; - fb_info.fix.smem_start = handle; - } -#endif - fb_info.fix.smem_len = size; - current_par.palette_size = VIDC_PALETTE_SIZE; - - /* - * Lookup the timing for this resolution. If we can't - * find it, then we can't restore it if we change - * the resolution, so we disable this feature. - */ - do { - rc = fb_find_mode(&fb_info.var, &fb_info, NULL, modedb, - ARRAY_SIZE(modedb), - &acornfb_default_mode, DEFAULT_BPP); - /* - * If we found an exact match, all ok. - */ - if (rc == 1) - break; - - rc = fb_find_mode(&fb_info.var, &fb_info, NULL, NULL, 0, - &acornfb_default_mode, DEFAULT_BPP); - /* - * If we found an exact match, all ok. - */ - if (rc == 1) - break; - - rc = fb_find_mode(&fb_info.var, &fb_info, NULL, modedb, - ARRAY_SIZE(modedb), - &acornfb_default_mode, DEFAULT_BPP); - if (rc) - break; - - rc = fb_find_mode(&fb_info.var, &fb_info, NULL, NULL, 0, - &acornfb_default_mode, DEFAULT_BPP); - } while (0); - - /* - * If we didn't find an exact match, try the - * generic database. - */ - if (rc == 0) { - printk("Acornfb: no valid mode found\n"); - return -EINVAL; - } - - h_sync = 1953125000 / fb_info.var.pixclock; - h_sync = h_sync * 512 / (fb_info.var.xres + fb_info.var.left_margin + - fb_info.var.right_margin + fb_info.var.hsync_len); - v_sync = h_sync / (fb_info.var.yres + fb_info.var.upper_margin + - fb_info.var.lower_margin + fb_info.var.vsync_len); - - printk(KERN_INFO "Acornfb: %dkB %cRAM, %s, using %dx%d, " - "%d.%03dkHz, %dHz\n", - fb_info.fix.smem_len / 1024, - current_par.using_vram ? 'V' : 'D', - VIDC_NAME, fb_info.var.xres, fb_info.var.yres, - h_sync / 1000, h_sync % 1000, v_sync); - - printk(KERN_INFO "Acornfb: Monitor: %d.%03d-%d.%03dkHz, %d-%dHz%s\n", - fb_info.monspecs.hfmin / 1000, fb_info.monspecs.hfmin % 1000, - fb_info.monspecs.hfmax / 1000, fb_info.monspecs.hfmax % 1000, - fb_info.monspecs.vfmin, fb_info.monspecs.vfmax, - fb_info.monspecs.dpms ? ", DPMS" : ""); - - if (fb_set_var(&fb_info, &fb_info.var)) - printk(KERN_ERR "Acornfb: unable to set display parameters\n"); - - if (register_framebuffer(&fb_info) < 0) - return -EINVAL; - return 0; -} - -static struct platform_driver acornfb_driver = { - .probe = acornfb_probe, - .driver = { - .name = "acornfb", - }, -}; - -static int __init acornfb_init(void) -{ - return platform_driver_register(&acornfb_driver); -} - -module_init(acornfb_init); - -MODULE_AUTHOR("Russell King"); -MODULE_DESCRIPTION("VIDC 1/1a/20 framebuffer driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/video/acornfb.h b/drivers/video/acornfb.h deleted file mode 100644 index 175c8ff3367..00000000000 --- a/drivers/video/acornfb.h +++ /dev/null @@ -1,169 +0,0 @@ -/* - * linux/drivers/video/acornfb.h - * - * Copyright (C) 1998,1999 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Frame buffer code for Acorn platforms - */ -#if defined(HAS_VIDC20) -#include -#define VIDC_PALETTE_SIZE 256 -#define VIDC_NAME "VIDC20" -#endif - -#define EXTEND8(x) ((x)|(x)<<8) -#define EXTEND4(x) ((x)|(x)<<4|(x)<<8|(x)<<12) - -struct vidc20_palette { - u_int red:8; - u_int green:8; - u_int blue:8; - u_int ext:4; - u_int unused:4; -}; - -struct vidc_palette { - u_int red:4; - u_int green:4; - u_int blue:4; - u_int trans:1; - u_int sbz1:13; - u_int reg:4; - u_int sbz2:2; -}; - -union palette { - struct vidc20_palette vidc20; - struct vidc_palette vidc; - u_int p; -}; - -struct acornfb_par { - struct device *dev; - unsigned long screen_end; - unsigned int dram_size; - unsigned int vram_half_sam; - unsigned int palette_size; - signed int montype; - unsigned int using_vram : 1; - unsigned int dpms : 1; - - union palette palette[VIDC_PALETTE_SIZE]; - - u32 pseudo_palette[16]; -}; - -struct vidc_timing { - u_int h_cycle; - u_int h_sync_width; - u_int h_border_start; - u_int h_display_start; - u_int h_display_end; - u_int h_border_end; - u_int h_interlace; - - u_int v_cycle; - u_int v_sync_width; - u_int v_border_start; - u_int v_display_start; - u_int v_display_end; - u_int v_border_end; - - u_int control; - - /* VIDC20 only */ - u_int pll_ctl; -}; - -struct modey_params { - u_int y_res; - u_int u_margin; - u_int b_margin; - u_int vsync_len; - u_int vf; -}; - -struct modex_params { - u_int x_res; - u_int l_margin; - u_int r_margin; - u_int hsync_len; - u_int clock; - u_int hf; - const struct modey_params *modey; -}; - -#ifdef HAS_VIDC20 -/* - * VIDC20 registers - */ -#define VIDC20_CTRL 0xe0000000 -#define VIDC20_CTRL_PIX_VCLK (0 << 0) -#define VIDC20_CTRL_PIX_HCLK (1 << 0) -#define VIDC20_CTRL_PIX_RCLK (2 << 0) -#define VIDC20_CTRL_PIX_CK (0 << 2) -#define VIDC20_CTRL_PIX_CK2 (1 << 2) -#define VIDC20_CTRL_PIX_CK3 (2 << 2) -#define VIDC20_CTRL_PIX_CK4 (3 << 2) -#define VIDC20_CTRL_PIX_CK5 (4 << 2) -#define VIDC20_CTRL_PIX_CK6 (5 << 2) -#define VIDC20_CTRL_PIX_CK7 (6 << 2) -#define VIDC20_CTRL_PIX_CK8 (7 << 2) -#define VIDC20_CTRL_1BPP (0 << 5) -#define VIDC20_CTRL_2BPP (1 << 5) -#define VIDC20_CTRL_4BPP (2 << 5) -#define VIDC20_CTRL_8BPP (3 << 5) -#define VIDC20_CTRL_16BPP (4 << 5) -#define VIDC20_CTRL_32BPP (6 << 5) -#define VIDC20_CTRL_FIFO_NS (0 << 8) -#define VIDC20_CTRL_FIFO_4 (1 << 8) -#define VIDC20_CTRL_FIFO_8 (2 << 8) -#define VIDC20_CTRL_FIFO_12 (3 << 8) -#define VIDC20_CTRL_FIFO_16 (4 << 8) -#define VIDC20_CTRL_FIFO_20 (5 << 8) -#define VIDC20_CTRL_FIFO_24 (6 << 8) -#define VIDC20_CTRL_FIFO_28 (7 << 8) -#define VIDC20_CTRL_INT (1 << 12) -#define VIDC20_CTRL_DUP (1 << 13) -#define VIDC20_CTRL_PDOWN (1 << 14) - -#define VIDC20_ECTL 0xc0000000 -#define VIDC20_ECTL_REG(x) ((x) & 0xf3) -#define VIDC20_ECTL_ECK (1 << 2) -#define VIDC20_ECTL_REDPED (1 << 8) -#define VIDC20_ECTL_GREENPED (1 << 9) -#define VIDC20_ECTL_BLUEPED (1 << 10) -#define VIDC20_ECTL_DAC (1 << 12) -#define VIDC20_ECTL_LCDGS (1 << 13) -#define VIDC20_ECTL_HRM (1 << 14) - -#define VIDC20_ECTL_HS_MASK (3 << 16) -#define VIDC20_ECTL_HS_HSYNC (0 << 16) -#define VIDC20_ECTL_HS_NHSYNC (1 << 16) -#define VIDC20_ECTL_HS_CSYNC (2 << 16) -#define VIDC20_ECTL_HS_NCSYNC (3 << 16) - -#define VIDC20_ECTL_VS_MASK (3 << 18) -#define VIDC20_ECTL_VS_VSYNC (0 << 18) -#define VIDC20_ECTL_VS_NVSYNC (1 << 18) -#define VIDC20_ECTL_VS_CSYNC (2 << 18) -#define VIDC20_ECTL_VS_NCSYNC (3 << 18) - -#define VIDC20_DCTL 0xf0000000 -/* 0-9 = number of words in scanline */ -#define VIDC20_DCTL_SNA (1 << 12) -#define VIDC20_DCTL_HDIS (1 << 13) -#define VIDC20_DCTL_BUS_NS (0 << 16) -#define VIDC20_DCTL_BUS_D31_0 (1 << 16) -#define VIDC20_DCTL_BUS_D63_32 (2 << 16) -#define VIDC20_DCTL_BUS_D63_0 (3 << 16) -#define VIDC20_DCTL_VRAM_DIS (0 << 18) -#define VIDC20_DCTL_VRAM_PXCLK (1 << 18) -#define VIDC20_DCTL_VRAM_PXCLK2 (2 << 18) -#define VIDC20_DCTL_VRAM_PXCLK4 (3 << 18) - -#endif diff --git a/drivers/video/amba-clcd.c b/drivers/video/amba-clcd.c deleted file mode 100644 index 14d6b3793e0..00000000000 --- a/drivers/video/amba-clcd.c +++ /dev/null @@ -1,656 +0,0 @@ -/* - * linux/drivers/video/amba-clcd.c - * - * Copyright (C) 2001 ARM Limited, by David A Rusling - * Updated to 2.5, Deep Blue Solutions Ltd. - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive - * for more details. - * - * ARM PrimeCell PL110 Color LCD Controller - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#define to_clcd(info) container_of(info, struct clcd_fb, fb) - -/* This is limited to 16 characters when displayed by X startup */ -static const char *clcd_name = "CLCD FB"; - -/* - * Unfortunately, the enable/disable functions may be called either from - * process or IRQ context, and we _need_ to delay. This is _not_ good. - */ -static inline void clcdfb_sleep(unsigned int ms) -{ - if (in_atomic()) { - mdelay(ms); - } else { - msleep(ms); - } -} - -static inline void clcdfb_set_start(struct clcd_fb *fb) -{ - unsigned long ustart = fb->fb.fix.smem_start; - unsigned long lstart; - - ustart += fb->fb.var.yoffset * fb->fb.fix.line_length; - lstart = ustart + fb->fb.var.yres * fb->fb.fix.line_length / 2; - - writel(ustart, fb->regs + CLCD_UBAS); - writel(lstart, fb->regs + CLCD_LBAS); -} - -static void clcdfb_disable(struct clcd_fb *fb) -{ - u32 val; - - if (fb->board->disable) - fb->board->disable(fb); - - val = readl(fb->regs + fb->off_cntl); - if (val & CNTL_LCDPWR) { - val &= ~CNTL_LCDPWR; - writel(val, fb->regs + fb->off_cntl); - - clcdfb_sleep(20); - } - if (val & CNTL_LCDEN) { - val &= ~CNTL_LCDEN; - writel(val, fb->regs + fb->off_cntl); - } - - /* - * Disable CLCD clock source. - */ - if (fb->clk_enabled) { - fb->clk_enabled = false; - clk_disable(fb->clk); - } -} - -static void clcdfb_enable(struct clcd_fb *fb, u32 cntl) -{ - /* - * Enable the CLCD clock source. - */ - if (!fb->clk_enabled) { - fb->clk_enabled = true; - clk_enable(fb->clk); - } - - /* - * Bring up by first enabling.. - */ - cntl |= CNTL_LCDEN; - writel(cntl, fb->regs + fb->off_cntl); - - clcdfb_sleep(20); - - /* - * and now apply power. - */ - cntl |= CNTL_LCDPWR; - writel(cntl, fb->regs + fb->off_cntl); - - /* - * finally, enable the interface. - */ - if (fb->board->enable) - fb->board->enable(fb); -} - -static int -clcdfb_set_bitfields(struct clcd_fb *fb, struct fb_var_screeninfo *var) -{ - u32 caps; - int ret = 0; - - if (fb->panel->caps && fb->board->caps) - caps = fb->panel->caps & fb->board->caps; - else { - /* Old way of specifying what can be used */ - caps = fb->panel->cntl & CNTL_BGR ? - CLCD_CAP_BGR : CLCD_CAP_RGB; - /* But mask out 444 modes as they weren't supported */ - caps &= ~CLCD_CAP_444; - } - - /* Only TFT panels can do RGB888/BGR888 */ - if (!(fb->panel->cntl & CNTL_LCDTFT)) - caps &= ~CLCD_CAP_888; - - memset(&var->transp, 0, sizeof(var->transp)); - - var->red.msb_right = 0; - var->green.msb_right = 0; - var->blue.msb_right = 0; - - switch (var->bits_per_pixel) { - case 1: - case 2: - case 4: - case 8: - /* If we can't do 5551, reject */ - caps &= CLCD_CAP_5551; - if (!caps) { - ret = -EINVAL; - break; - } - - var->red.length = var->bits_per_pixel; - var->red.offset = 0; - var->green.length = var->bits_per_pixel; - var->green.offset = 0; - var->blue.length = var->bits_per_pixel; - var->blue.offset = 0; - break; - - case 16: - /* If we can't do 444, 5551 or 565, reject */ - if (!(caps & (CLCD_CAP_444 | CLCD_CAP_5551 | CLCD_CAP_565))) { - ret = -EINVAL; - break; - } - - /* - * Green length can be 4, 5 or 6 depending whether - * we're operating in 444, 5551 or 565 mode. - */ - if (var->green.length == 4 && caps & CLCD_CAP_444) - caps &= CLCD_CAP_444; - if (var->green.length == 5 && caps & CLCD_CAP_5551) - caps &= CLCD_CAP_5551; - else if (var->green.length == 6 && caps & CLCD_CAP_565) - caps &= CLCD_CAP_565; - else { - /* - * PL110 officially only supports RGB555, - * but may be wired up to allow RGB565. - */ - if (caps & CLCD_CAP_565) { - var->green.length = 6; - caps &= CLCD_CAP_565; - } else if (caps & CLCD_CAP_5551) { - var->green.length = 5; - caps &= CLCD_CAP_5551; - } else { - var->green.length = 4; - caps &= CLCD_CAP_444; - } - } - - if (var->green.length >= 5) { - var->red.length = 5; - var->blue.length = 5; - } else { - var->red.length = 4; - var->blue.length = 4; - } - break; - case 32: - /* If we can't do 888, reject */ - caps &= CLCD_CAP_888; - if (!caps) { - ret = -EINVAL; - break; - } - - var->red.length = 8; - var->green.length = 8; - var->blue.length = 8; - break; - default: - ret = -EINVAL; - break; - } - - /* - * >= 16bpp displays have separate colour component bitfields - * encoded in the pixel data. Calculate their position from - * the bitfield length defined above. - */ - if (ret == 0 && var->bits_per_pixel >= 16) { - bool bgr, rgb; - - bgr = caps & CLCD_CAP_BGR && var->blue.offset == 0; - rgb = caps & CLCD_CAP_RGB && var->red.offset == 0; - - if (!bgr && !rgb) - /* - * The requested format was not possible, try just - * our capabilities. One of BGR or RGB must be - * supported. - */ - bgr = caps & CLCD_CAP_BGR; - - if (bgr) { - var->blue.offset = 0; - var->green.offset = var->blue.offset + var->blue.length; - var->red.offset = var->green.offset + var->green.length; - } else { - var->red.offset = 0; - var->green.offset = var->red.offset + var->red.length; - var->blue.offset = var->green.offset + var->green.length; - } - } - - return ret; -} - -static int clcdfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) -{ - struct clcd_fb *fb = to_clcd(info); - int ret = -EINVAL; - - if (fb->board->check) - ret = fb->board->check(fb, var); - - if (ret == 0 && - var->xres_virtual * var->bits_per_pixel / 8 * - var->yres_virtual > fb->fb.fix.smem_len) - ret = -EINVAL; - - if (ret == 0) - ret = clcdfb_set_bitfields(fb, var); - - return ret; -} - -static int clcdfb_set_par(struct fb_info *info) -{ - struct clcd_fb *fb = to_clcd(info); - struct clcd_regs regs; - - fb->fb.fix.line_length = fb->fb.var.xres_virtual * - fb->fb.var.bits_per_pixel / 8; - - if (fb->fb.var.bits_per_pixel <= 8) - fb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR; - else - fb->fb.fix.visual = FB_VISUAL_TRUECOLOR; - - fb->board->decode(fb, ®s); - - clcdfb_disable(fb); - - writel(regs.tim0, fb->regs + CLCD_TIM0); - writel(regs.tim1, fb->regs + CLCD_TIM1); - writel(regs.tim2, fb->regs + CLCD_TIM2); - writel(regs.tim3, fb->regs + CLCD_TIM3); - - clcdfb_set_start(fb); - - clk_set_rate(fb->clk, (1000000000 / regs.pixclock) * 1000); - - fb->clcd_cntl = regs.cntl; - - clcdfb_enable(fb, regs.cntl); - -#ifdef DEBUG - printk(KERN_INFO - "CLCD: Registers set to\n" - " %08x %08x %08x %08x\n" - " %08x %08x %08x %08x\n", - readl(fb->regs + CLCD_TIM0), readl(fb->regs + CLCD_TIM1), - readl(fb->regs + CLCD_TIM2), readl(fb->regs + CLCD_TIM3), - readl(fb->regs + CLCD_UBAS), readl(fb->regs + CLCD_LBAS), - readl(fb->regs + fb->off_ienb), readl(fb->regs + fb->off_cntl)); -#endif - - return 0; -} - -static inline u32 convert_bitfield(int val, struct fb_bitfield *bf) -{ - unsigned int mask = (1 << bf->length) - 1; - - return (val >> (16 - bf->length) & mask) << bf->offset; -} - -/* - * Set a single color register. The values supplied have a 16 bit - * magnitude. Return != 0 for invalid regno. - */ -static int -clcdfb_setcolreg(unsigned int regno, unsigned int red, unsigned int green, - unsigned int blue, unsigned int transp, struct fb_info *info) -{ - struct clcd_fb *fb = to_clcd(info); - - if (regno < 16) - fb->cmap[regno] = convert_bitfield(transp, &fb->fb.var.transp) | - convert_bitfield(blue, &fb->fb.var.blue) | - convert_bitfield(green, &fb->fb.var.green) | - convert_bitfield(red, &fb->fb.var.red); - - if (fb->fb.fix.visual == FB_VISUAL_PSEUDOCOLOR && regno < 256) { - int hw_reg = CLCD_PALETTE + ((regno * 2) & ~3); - u32 val, mask, newval; - - newval = (red >> 11) & 0x001f; - newval |= (green >> 6) & 0x03e0; - newval |= (blue >> 1) & 0x7c00; - - /* - * 3.2.11: if we're configured for big endian - * byte order, the palette entries are swapped. - */ - if (fb->clcd_cntl & CNTL_BEBO) - regno ^= 1; - - if (regno & 1) { - newval <<= 16; - mask = 0x0000ffff; - } else { - mask = 0xffff0000; - } - - val = readl(fb->regs + hw_reg) & mask; - writel(val | newval, fb->regs + hw_reg); - } - - return regno > 255; -} - -/* - * Blank the screen if blank_mode != 0, else unblank. If blank == NULL - * then the caller blanks by setting the CLUT (Color Look Up Table) to all - * black. Return 0 if blanking succeeded, != 0 if un-/blanking failed due - * to e.g. a video mode which doesn't support it. Implements VESA suspend - * and powerdown modes on hardware that supports disabling hsync/vsync: - * blank_mode == 2: suspend vsync - * blank_mode == 3: suspend hsync - * blank_mode == 4: powerdown - */ -static int clcdfb_blank(int blank_mode, struct fb_info *info) -{ - struct clcd_fb *fb = to_clcd(info); - - if (blank_mode != 0) { - clcdfb_disable(fb); - } else { - clcdfb_enable(fb, fb->clcd_cntl); - } - return 0; -} - -static int clcdfb_mmap(struct fb_info *info, - struct vm_area_struct *vma) -{ - struct clcd_fb *fb = to_clcd(info); - unsigned long len, off = vma->vm_pgoff << PAGE_SHIFT; - int ret = -EINVAL; - - len = info->fix.smem_len; - - if (off <= len && vma->vm_end - vma->vm_start <= len - off && - fb->board->mmap) - ret = fb->board->mmap(fb, vma); - - return ret; -} - -static struct fb_ops clcdfb_ops = { - .owner = THIS_MODULE, - .fb_check_var = clcdfb_check_var, - .fb_set_par = clcdfb_set_par, - .fb_setcolreg = clcdfb_setcolreg, - .fb_blank = clcdfb_blank, - .fb_fillrect = cfb_fillrect, - .fb_copyarea = cfb_copyarea, - .fb_imageblit = cfb_imageblit, - .fb_mmap = clcdfb_mmap, -}; - -static int clcdfb_register(struct clcd_fb *fb) -{ - int ret; - - /* - * ARM PL111 always has IENB at 0x1c; it's only PL110 - * which is reversed on some platforms. - */ - if (amba_manf(fb->dev) == 0x41 && amba_part(fb->dev) == 0x111) { - fb->off_ienb = CLCD_PL111_IENB; - fb->off_cntl = CLCD_PL111_CNTL; - } else { -#ifdef CONFIG_ARCH_VERSATILE - fb->off_ienb = CLCD_PL111_IENB; - fb->off_cntl = CLCD_PL111_CNTL; -#else - fb->off_ienb = CLCD_PL110_IENB; - fb->off_cntl = CLCD_PL110_CNTL; -#endif - } - - fb->clk = clk_get(&fb->dev->dev, NULL); - if (IS_ERR(fb->clk)) { - ret = PTR_ERR(fb->clk); - goto out; - } - - ret = clk_prepare(fb->clk); - if (ret) - goto free_clk; - - fb->fb.device = &fb->dev->dev; - - fb->fb.fix.mmio_start = fb->dev->res.start; - fb->fb.fix.mmio_len = resource_size(&fb->dev->res); - - fb->regs = ioremap(fb->fb.fix.mmio_start, fb->fb.fix.mmio_len); - if (!fb->regs) { - printk(KERN_ERR "CLCD: unable to remap registers\n"); - ret = -ENOMEM; - goto clk_unprep; - } - - fb->fb.fbops = &clcdfb_ops; - fb->fb.flags = FBINFO_FLAG_DEFAULT; - fb->fb.pseudo_palette = fb->cmap; - - strncpy(fb->fb.fix.id, clcd_name, sizeof(fb->fb.fix.id)); - fb->fb.fix.type = FB_TYPE_PACKED_PIXELS; - fb->fb.fix.type_aux = 0; - fb->fb.fix.xpanstep = 0; - fb->fb.fix.ypanstep = 0; - fb->fb.fix.ywrapstep = 0; - fb->fb.fix.accel = FB_ACCEL_NONE; - - fb->fb.var.xres = fb->panel->mode.xres; - fb->fb.var.yres = fb->panel->mode.yres; - fb->fb.var.xres_virtual = fb->panel->mode.xres; - fb->fb.var.yres_virtual = fb->panel->mode.yres; - fb->fb.var.bits_per_pixel = fb->panel->bpp; - fb->fb.var.grayscale = fb->panel->grayscale; - fb->fb.var.pixclock = fb->panel->mode.pixclock; - fb->fb.var.left_margin = fb->panel->mode.left_margin; - fb->fb.var.right_margin = fb->panel->mode.right_margin; - fb->fb.var.upper_margin = fb->panel->mode.upper_margin; - fb->fb.var.lower_margin = fb->panel->mode.lower_margin; - fb->fb.var.hsync_len = fb->panel->mode.hsync_len; - fb->fb.var.vsync_len = fb->panel->mode.vsync_len; - fb->fb.var.sync = fb->panel->mode.sync; - fb->fb.var.vmode = fb->panel->mode.vmode; - fb->fb.var.activate = FB_ACTIVATE_NOW; - fb->fb.var.nonstd = 0; - fb->fb.var.height = fb->panel->height; - fb->fb.var.width = fb->panel->width; - fb->fb.var.accel_flags = 0; - - fb->fb.monspecs.hfmin = 0; - fb->fb.monspecs.hfmax = 100000; - fb->fb.monspecs.vfmin = 0; - fb->fb.monspecs.vfmax = 400; - fb->fb.monspecs.dclkmin = 1000000; - fb->fb.monspecs.dclkmax = 100000000; - - /* - * Make sure that the bitfields are set appropriately. - */ - clcdfb_set_bitfields(fb, &fb->fb.var); - - /* - * Allocate colourmap. - */ - ret = fb_alloc_cmap(&fb->fb.cmap, 256, 0); - if (ret) - goto unmap; - - /* - * Ensure interrupts are disabled. - */ - writel(0, fb->regs + fb->off_ienb); - - fb_set_var(&fb->fb, &fb->fb.var); - - dev_info(&fb->dev->dev, "%s hardware, %s display\n", - fb->board->name, fb->panel->mode.name); - - ret = register_framebuffer(&fb->fb); - if (ret == 0) - goto out; - - printk(KERN_ERR "CLCD: cannot register framebuffer (%d)\n", ret); - - fb_dealloc_cmap(&fb->fb.cmap); - unmap: - iounmap(fb->regs); - clk_unprep: - clk_unprepare(fb->clk); - free_clk: - clk_put(fb->clk); - out: - return ret; -} - -static int clcdfb_probe(struct amba_device *dev, const struct amba_id *id) -{ - struct clcd_board *board = dev_get_platdata(&dev->dev); - struct clcd_fb *fb; - int ret; - - if (!board) - return -EINVAL; - - ret = dma_set_mask_and_coherent(&dev->dev, DMA_BIT_MASK(32)); - if (ret) - goto out; - - ret = amba_request_regions(dev, NULL); - if (ret) { - printk(KERN_ERR "CLCD: unable to reserve regs region\n"); - goto out; - } - - fb = kzalloc(sizeof(struct clcd_fb), GFP_KERNEL); - if (!fb) { - printk(KERN_INFO "CLCD: could not allocate new clcd_fb struct\n"); - ret = -ENOMEM; - goto free_region; - } - - fb->dev = dev; - fb->board = board; - - dev_info(&fb->dev->dev, "PL%03x rev%u at 0x%08llx\n", - amba_part(dev), amba_rev(dev), - (unsigned long long)dev->res.start); - - ret = fb->board->setup(fb); - if (ret) - goto free_fb; - - ret = clcdfb_register(fb); - if (ret == 0) { - amba_set_drvdata(dev, fb); - goto out; - } - - fb->board->remove(fb); - free_fb: - kfree(fb); - free_region: - amba_release_regions(dev); - out: - return ret; -} - -static int clcdfb_remove(struct amba_device *dev) -{ - struct clcd_fb *fb = amba_get_drvdata(dev); - - clcdfb_disable(fb); - unregister_framebuffer(&fb->fb); - if (fb->fb.cmap.len) - fb_dealloc_cmap(&fb->fb.cmap); - iounmap(fb->regs); - clk_unprepare(fb->clk); - clk_put(fb->clk); - - fb->board->remove(fb); - - kfree(fb); - - amba_release_regions(dev); - - return 0; -} - -static struct amba_id clcdfb_id_table[] = { - { - .id = 0x00041110, - .mask = 0x000ffffe, - }, - { 0, 0 }, -}; - -MODULE_DEVICE_TABLE(amba, clcdfb_id_table); - -static struct amba_driver clcd_driver = { - .drv = { - .name = "clcd-pl11x", - }, - .probe = clcdfb_probe, - .remove = clcdfb_remove, - .id_table = clcdfb_id_table, -}; - -static int __init amba_clcdfb_init(void) -{ - if (fb_get_options("ambafb", NULL)) - return -ENODEV; - - return amba_driver_register(&clcd_driver); -} - -module_init(amba_clcdfb_init); - -static void __exit amba_clcdfb_exit(void) -{ - amba_driver_unregister(&clcd_driver); -} - -module_exit(amba_clcdfb_exit); - -MODULE_DESCRIPTION("ARM PrimeCell PL110 CLCD core driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/video/amifb.c b/drivers/video/amifb.c deleted file mode 100644 index 518f790ef88..00000000000 --- a/drivers/video/amifb.c +++ /dev/null @@ -1,3792 +0,0 @@ -/* - * linux/drivers/video/amifb.c -- Amiga builtin chipset frame buffer device - * - * Copyright (C) 1995-2003 Geert Uytterhoeven - * - * with work by Roman Zippel - * - * - * This file is based on the Atari frame buffer device (atafb.c): - * - * Copyright (C) 1994 Martin Schaller - * Roman Hodek - * - * with work by Andreas Schwab - * Guenther Kelleter - * - * and on the original Amiga console driver (amicon.c): - * - * Copyright (C) 1993 Hamish Macdonald - * Greg Harp - * Copyright (C) 1994 David Carter [carter@compsci.bristol.ac.uk] - * - * with work by William Rucklidge (wjr@cs.cornell.edu) - * Geert Uytterhoeven - * Jes Sorensen (jds@kom.auc.dk) - * - * - * History: - * - * - 24 Jul 96: Copper generates now vblank interrupt and - * VESA Power Saving Protocol is fully implemented - * - 14 Jul 96: Rework and hopefully last ECS bugs fixed - * - 7 Mar 96: Hardware sprite support by Roman Zippel - * - 18 Feb 96: OCS and ECS support by Roman Zippel - * Hardware functions completely rewritten - * - 2 Dec 95: AGA version by Geert Uytterhoeven - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive - * for more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "c2p.h" - - -#define DEBUG - -#if !defined(CONFIG_FB_AMIGA_OCS) && !defined(CONFIG_FB_AMIGA_ECS) && !defined(CONFIG_FB_AMIGA_AGA) -#define CONFIG_FB_AMIGA_OCS /* define at least one fb driver, this will change later */ -#endif - -#if !defined(CONFIG_FB_AMIGA_OCS) -# define IS_OCS (0) -#elif defined(CONFIG_FB_AMIGA_ECS) || defined(CONFIG_FB_AMIGA_AGA) -# define IS_OCS (chipset == TAG_OCS) -#else -# define CONFIG_FB_AMIGA_OCS_ONLY -# define IS_OCS (1) -#endif - -#if !defined(CONFIG_FB_AMIGA_ECS) -# define IS_ECS (0) -#elif defined(CONFIG_FB_AMIGA_OCS) || defined(CONFIG_FB_AMIGA_AGA) -# define IS_ECS (chipset == TAG_ECS) -#else -# define CONFIG_FB_AMIGA_ECS_ONLY -# define IS_ECS (1) -#endif - -#if !defined(CONFIG_FB_AMIGA_AGA) -# define IS_AGA (0) -#elif defined(CONFIG_FB_AMIGA_OCS) || defined(CONFIG_FB_AMIGA_ECS) -# define IS_AGA (chipset == TAG_AGA) -#else -# define CONFIG_FB_AMIGA_AGA_ONLY -# define IS_AGA (1) -#endif - -#ifdef DEBUG -# define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __func__ , ## args) -#else -# define DPRINTK(fmt, args...) -#endif - -/******************************************************************************* - - - Generic video timings - --------------------- - - Timings used by the frame buffer interface: - - +----------+---------------------------------------------+----------+-------+ - | | ^ | | | - | | |upper_margin | | | - | | v | | | - +----------###############################################----------+-------+ - | # ^ # | | - | # | # | | - | # | # | | - | # | # | | - | left # | # right | hsync | - | margin # | xres # margin | len | - |<-------->#<---------------+--------------------------->#<-------->|<----->| - | # | # | | - | # | # | | - | # | # | | - | # |yres # | | - | # | # | | - | # | # | | - | # | # | | - | # | # | | - | # | # | | - | # | # | | - | # | # | | - | # | # | | - | # v # | | - +----------###############################################----------+-------+ - | | ^ | | | - | | |lower_margin | | | - | | v | | | - +----------+---------------------------------------------+----------+-------+ - | | ^ | | | - | | |vsync_len | | | - | | v | | | - +----------+---------------------------------------------+----------+-------+ - - - Amiga video timings - ------------------- - - The Amiga native chipsets uses another timing scheme: - - - hsstrt: Start of horizontal synchronization pulse - - hsstop: End of horizontal synchronization pulse - - htotal: Last value on the line (i.e. line length = htotal + 1) - - vsstrt: Start of vertical synchronization pulse - - vsstop: End of vertical synchronization pulse - - vtotal: Last line value (i.e. number of lines = vtotal + 1) - - hcenter: Start of vertical retrace for interlace - - You can specify the blanking timings independently. Currently I just set - them equal to the respective synchronization values: - - - hbstrt: Start of horizontal blank - - hbstop: End of horizontal blank - - vbstrt: Start of vertical blank - - vbstop: End of vertical blank - - Horizontal values are in color clock cycles (280 ns), vertical values are in - scanlines. - - (0, 0) is somewhere in the upper-left corner :-) - - - Amiga visible window definitions - -------------------------------- - - Currently I only have values for AGA, SHRES (28 MHz dotclock). Feel free to - make corrections and/or additions. - - Within the above synchronization specifications, the visible window is - defined by the following parameters (actual register resolutions may be - different; all horizontal values are normalized with respect to the pixel - clock): - - - diwstrt_h: Horizontal start of the visible window - - diwstop_h: Horizontal stop + 1(*) of the visible window - - diwstrt_v: Vertical start of the visible window - - diwstop_v: Vertical stop of the visible window - - ddfstrt: Horizontal start of display DMA - - ddfstop: Horizontal stop of display DMA - - hscroll: Horizontal display output delay - - Sprite positioning: - - - sprstrt_h: Horizontal start - 4 of sprite - - sprstrt_v: Vertical start of sprite - - (*) Even Commodore did it wrong in the AGA monitor drivers by not adding 1. - - Horizontal values are in dotclock cycles (35 ns), vertical values are in - scanlines. - - (0, 0) is somewhere in the upper-left corner :-) - - - Dependencies (AGA, SHRES (35 ns dotclock)) - ------------------------------------------- - - Since there are much more parameters for the Amiga display than for the - frame buffer interface, there must be some dependencies among the Amiga - display parameters. Here's what I found out: - - - ddfstrt and ddfstop are best aligned to 64 pixels. - - the chipset needs 64 + 4 horizontal pixels after the DMA start before - the first pixel is output, so diwstrt_h = ddfstrt + 64 + 4 if you want - to display the first pixel on the line too. Increase diwstrt_h for - virtual screen panning. - - the display DMA always fetches 64 pixels at a time (fmode = 3). - - ddfstop is ddfstrt+#pixels - 64. - - diwstop_h = diwstrt_h + xres + 1. Because of the additional 1 this can - be 1 more than htotal. - - hscroll simply adds a delay to the display output. Smooth horizontal - panning needs an extra 64 pixels on the left to prefetch the pixels that - `fall off' on the left. - - if ddfstrt < 192, the sprite DMA cycles are all stolen by the bitplane - DMA, so it's best to make the DMA start as late as possible. - - you really don't want to make ddfstrt < 128, since this will steal DMA - cycles from the other DMA channels (audio, floppy and Chip RAM refresh). - - I make diwstop_h and diwstop_v as large as possible. - - General dependencies - -------------------- - - - all values are SHRES pixel (35ns) - - table 1:fetchstart table 2:prefetch table 3:fetchsize - ------------------ ---------------- ----------------- - Pixclock # SHRES|HIRES|LORES # SHRES|HIRES|LORES # SHRES|HIRES|LORES - -------------#------+-----+------#------+-----+------#------+-----+------ - Bus width 1x # 16 | 32 | 64 # 16 | 32 | 64 # 64 | 64 | 64 - Bus width 2x # 32 | 64 | 128 # 32 | 64 | 64 # 64 | 64 | 128 - Bus width 4x # 64 | 128 | 256 # 64 | 64 | 64 # 64 | 128 | 256 - - - chipset needs 4 pixels before the first pixel is output - - ddfstrt must be aligned to fetchstart (table 1) - - chipset needs also prefetch (table 2) to get first pixel data, so - ddfstrt = ((diwstrt_h - 4) & -fetchstart) - prefetch - - for horizontal panning decrease diwstrt_h - - the length of a fetchline must be aligned to fetchsize (table 3) - - if fetchstart is smaller than fetchsize, then ddfstrt can a little bit - moved to optimize use of dma (useful for OCS/ECS overscan displays) - - ddfstop is ddfstrt + ddfsize - fetchsize - - If C= didn't change anything for AGA, then at following positions the - dma bus is already used: - ddfstrt < 48 -> memory refresh - < 96 -> disk dma - < 160 -> audio dma - < 192 -> sprite 0 dma - < 416 -> sprite dma (32 per sprite) - - in accordance with the hardware reference manual a hardware stop is at - 192, but AGA (ECS?) can go below this. - - DMA priorities - -------------- - - Since there are limits on the earliest start value for display DMA and the - display of sprites, I use the following policy on horizontal panning and - the hardware cursor: - - - if you want to start display DMA too early, you lose the ability to - do smooth horizontal panning (xpanstep 1 -> 64). - - if you want to go even further, you lose the hardware cursor too. - - IMHO a hardware cursor is more important for X than horizontal scrolling, - so that's my motivation. - - - Implementation - -------------- - - ami_decode_var() converts the frame buffer values to the Amiga values. It's - just a `straightforward' implementation of the above rules. - - - Standard VGA timings - -------------------- - - xres yres left right upper lower hsync vsync - ---- ---- ---- ----- ----- ----- ----- ----- - 80x25 720 400 27 45 35 12 108 2 - 80x30 720 480 27 45 30 9 108 2 - - These were taken from a XFree86 configuration file, recalculated for a 28 MHz - dotclock (Amigas don't have a 25 MHz dotclock) and converted to frame buffer - generic timings. - - As a comparison, graphics/monitor.h suggests the following: - - xres yres left right upper lower hsync vsync - ---- ---- ---- ----- ----- ----- ----- ----- - - VGA 640 480 52 112 24 19 112 - 2 + - VGA70 640 400 52 112 27 21 112 - 2 - - - - Sync polarities - --------------- - - VSYNC HSYNC Vertical size Vertical total - ----- ----- ------------- -------------- - + + Reserved Reserved - + - 400 414 - - + 350 362 - - - 480 496 - - Source: CL-GD542X Technical Reference Manual, Cirrus Logic, Oct 1992 - - - Broadcast video timings - ----------------------- - - According to the CCIR and RETMA specifications, we have the following values: - - CCIR -> PAL - ----------- - - - a scanline is 64 µs long, of which 52.48 µs are visible. This is about - 736 visible 70 ns pixels per line. - - we have 625 scanlines, of which 575 are visible (interlaced); after - rounding this becomes 576. - - RETMA -> NTSC - ------------- - - - a scanline is 63.5 µs long, of which 53.5 µs are visible. This is about - 736 visible 70 ns pixels per line. - - we have 525 scanlines, of which 485 are visible (interlaced); after - rounding this becomes 484. - - Thus if you want a PAL compatible display, you have to do the following: - - - set the FB_SYNC_BROADCAST flag to indicate that standard broadcast - timings are to be used. - - make sure upper_margin + yres + lower_margin + vsync_len = 625 for an - interlaced, 312 for a non-interlaced and 156 for a doublescanned - display. - - make sure left_margin + xres + right_margin + hsync_len = 1816 for a - SHRES, 908 for a HIRES and 454 for a LORES display. - - the left visible part begins at 360 (SHRES; HIRES:180, LORES:90), - left_margin + 2 * hsync_len must be greater or equal. - - the upper visible part begins at 48 (interlaced; non-interlaced:24, - doublescanned:12), upper_margin + 2 * vsync_len must be greater or - equal. - - ami_encode_var() calculates margins with a hsync of 5320 ns and a vsync - of 4 scanlines - - The settings for a NTSC compatible display are straightforward. - - Note that in a strict sense the PAL and NTSC standards only define the - encoding of the color part (chrominance) of the video signal and don't say - anything about horizontal/vertical synchronization nor refresh rates. - - - -- Geert -- - -*******************************************************************************/ - - - /* - * Custom Chipset Definitions - */ - -#define CUSTOM_OFS(fld) ((long)&((struct CUSTOM*)0)->fld) - - /* - * BPLCON0 -- Bitplane Control Register 0 - */ - -#define BPC0_HIRES (0x8000) -#define BPC0_BPU2 (0x4000) /* Bit plane used count */ -#define BPC0_BPU1 (0x2000) -#define BPC0_BPU0 (0x1000) -#define BPC0_HAM (0x0800) /* HAM mode */ -#define BPC0_DPF (0x0400) /* Double playfield */ -#define BPC0_COLOR (0x0200) /* Enable colorburst */ -#define BPC0_GAUD (0x0100) /* Genlock audio enable */ -#define BPC0_UHRES (0x0080) /* Ultrahi res enable */ -#define BPC0_SHRES (0x0040) /* Super hi res mode */ -#define BPC0_BYPASS (0x0020) /* Bypass LUT - AGA */ -#define BPC0_BPU3 (0x0010) /* AGA */ -#define BPC0_LPEN (0x0008) /* Light pen enable */ -#define BPC0_LACE (0x0004) /* Interlace */ -#define BPC0_ERSY (0x0002) /* External resync */ -#define BPC0_ECSENA (0x0001) /* ECS enable */ - - /* - * BPLCON2 -- Bitplane Control Register 2 - */ - -#define BPC2_ZDBPSEL2 (0x4000) /* Bitplane to be used for ZD - AGA */ -#define BPC2_ZDBPSEL1 (0x2000) -#define BPC2_ZDBPSEL0 (0x1000) -#define BPC2_ZDBPEN (0x0800) /* Enable ZD with ZDBPSELx - AGA */ -#define BPC2_ZDCTEN (0x0400) /* Enable ZD with palette bit #31 - AGA */ -#define BPC2_KILLEHB (0x0200) /* Kill EHB mode - AGA */ -#define BPC2_RDRAM (0x0100) /* Color table accesses read, not write - AGA */ -#define BPC2_SOGEN (0x0080) /* SOG output pin high - AGA */ -#define BPC2_PF2PRI (0x0040) /* PF2 priority over PF1 */ -#define BPC2_PF2P2 (0x0020) /* PF2 priority wrt sprites */ -#define BPC2_PF2P1 (0x0010) -#define BPC2_PF2P0 (0x0008) -#define BPC2_PF1P2 (0x0004) /* ditto PF1 */ -#define BPC2_PF1P1 (0x0002) -#define BPC2_PF1P0 (0x0001) - - /* - * BPLCON3 -- Bitplane Control Register 3 (AGA) - */ - -#define BPC3_BANK2 (0x8000) /* Bits to select color register bank */ -#define BPC3_BANK1 (0x4000) -#define BPC3_BANK0 (0x2000) -#define BPC3_PF2OF2 (0x1000) /* Bits for color table offset when PF2 */ -#define BPC3_PF2OF1 (0x0800) -#define BPC3_PF2OF0 (0x0400) -#define BPC3_LOCT (0x0200) /* Color register writes go to low bits */ -#define BPC3_SPRES1 (0x0080) /* Sprite resolution bits */ -#define BPC3_SPRES0 (0x0040) -#define BPC3_BRDRBLNK (0x0020) /* Border blanked? */ -#define BPC3_BRDRTRAN (0x0010) /* Border transparent? */ -#define BPC3_ZDCLKEN (0x0004) /* ZD pin is 14 MHz (HIRES) clock output */ -#define BPC3_BRDRSPRT (0x0002) /* Sprites in border? */ -#define BPC3_EXTBLKEN (0x0001) /* BLANK programmable */ - - /* - * BPLCON4 -- Bitplane Control Register 4 (AGA) - */ - -#define BPC4_BPLAM7 (0x8000) /* bitplane color XOR field */ -#define BPC4_BPLAM6 (0x4000) -#define BPC4_BPLAM5 (0x2000) -#define BPC4_BPLAM4 (0x1000) -#define BPC4_BPLAM3 (0x0800) -#define BPC4_BPLAM2 (0x0400) -#define BPC4_BPLAM1 (0x0200) -#define BPC4_BPLAM0 (0x0100) -#define BPC4_ESPRM7 (0x0080) /* 4 high bits for even sprite colors */ -#define BPC4_ESPRM6 (0x0040) -#define BPC4_ESPRM5 (0x0020) -#define BPC4_ESPRM4 (0x0010) -#define BPC4_OSPRM7 (0x0008) /* 4 high bits for odd sprite colors */ -#define BPC4_OSPRM6 (0x0004) -#define BPC4_OSPRM5 (0x0002) -#define BPC4_OSPRM4 (0x0001) - - /* - * BEAMCON0 -- Beam Control Register - */ - -#define BMC0_HARDDIS (0x4000) /* Disable hardware limits */ -#define BMC0_LPENDIS (0x2000) /* Disable light pen latch */ -#define BMC0_VARVBEN (0x1000) /* Enable variable vertical blank */ -#define BMC0_LOLDIS (0x0800) /* Disable long/short line toggle */ -#define BMC0_CSCBEN (0x0400) /* Composite sync/blank */ -#define BMC0_VARVSYEN (0x0200) /* Enable variable vertical sync */ -#define BMC0_VARHSYEN (0x0100) /* Enable variable horizontal sync */ -#define BMC0_VARBEAMEN (0x0080) /* Enable variable beam counters */ -#define BMC0_DUAL (0x0040) /* Enable alternate horizontal beam counter */ -#define BMC0_PAL (0x0020) /* Set decodes for PAL */ -#define BMC0_VARCSYEN (0x0010) /* Enable variable composite sync */ -#define BMC0_BLANKEN (0x0008) /* Blank enable (no longer used on AGA) */ -#define BMC0_CSYTRUE (0x0004) /* CSY polarity */ -#define BMC0_VSYTRUE (0x0002) /* VSY polarity */ -#define BMC0_HSYTRUE (0x0001) /* HSY polarity */ - - - /* - * FMODE -- Fetch Mode Control Register (AGA) - */ - -#define FMODE_SSCAN2 (0x8000) /* Sprite scan-doubling */ -#define FMODE_BSCAN2 (0x4000) /* Use PF2 modulus every other line */ -#define FMODE_SPAGEM (0x0008) /* Sprite page mode */ -#define FMODE_SPR32 (0x0004) /* Sprite 32 bit fetch */ -#define FMODE_BPAGEM (0x0002) /* Bitplane page mode */ -#define FMODE_BPL32 (0x0001) /* Bitplane 32 bit fetch */ - - /* - * Tags used to indicate a specific Pixel Clock - * - * clk_shift is the shift value to get the timings in 35 ns units - */ - -enum { TAG_SHRES, TAG_HIRES, TAG_LORES }; - - /* - * Tags used to indicate the specific chipset - */ - -enum { TAG_OCS, TAG_ECS, TAG_AGA }; - - /* - * Tags used to indicate the memory bandwidth - */ - -enum { TAG_FMODE_1, TAG_FMODE_2, TAG_FMODE_4 }; - - - /* - * Clock Definitions, Maximum Display Depth - * - * These depend on the E-Clock or the Chipset, so they are filled in - * dynamically - */ - -static u_long pixclock[3]; /* SHRES/HIRES/LORES: index = clk_shift */ -static u_short maxdepth[3]; /* SHRES/HIRES/LORES: index = clk_shift */ -static u_short maxfmode, chipset; - - - /* - * Broadcast Video Timings - * - * Horizontal values are in 35 ns (SHRES) units - * Vertical values are in interlaced scanlines - */ - -#define PAL_DIWSTRT_H (360) /* PAL Window Limits */ -#define PAL_DIWSTRT_V (48) -#define PAL_HTOTAL (1816) -#define PAL_VTOTAL (625) - -#define NTSC_DIWSTRT_H (360) /* NTSC Window Limits */ -#define NTSC_DIWSTRT_V (40) -#define NTSC_HTOTAL (1816) -#define NTSC_VTOTAL (525) - - - /* - * Various macros - */ - -#define up2(v) (((v) + 1) & -2) -#define down2(v) ((v) & -2) -#define div2(v) ((v)>>1) -#define mod2(v) ((v) & 1) - -#define up4(v) (((v) + 3) & -4) -#define down4(v) ((v) & -4) -#define mul4(v) ((v) << 2) -#define div4(v) ((v)>>2) -#define mod4(v) ((v) & 3) - -#define up8(v) (((v) + 7) & -8) -#define down8(v) ((v) & -8) -#define div8(v) ((v)>>3) -#define mod8(v) ((v) & 7) - -#define up16(v) (((v) + 15) & -16) -#define down16(v) ((v) & -16) -#define div16(v) ((v)>>4) -#define mod16(v) ((v) & 15) - -#define up32(v) (((v) + 31) & -32) -#define down32(v) ((v) & -32) -#define div32(v) ((v)>>5) -#define mod32(v) ((v) & 31) - -#define up64(v) (((v) + 63) & -64) -#define down64(v) ((v) & -64) -#define div64(v) ((v)>>6) -#define mod64(v) ((v) & 63) - -#define upx(x, v) (((v) + (x) - 1) & -(x)) -#define downx(x, v) ((v) & -(x)) -#define modx(x, v) ((v) & ((x) - 1)) - -/* if x1 is not a constant, this macro won't make real sense :-) */ -#ifdef __mc68000__ -#define DIVUL(x1, x2) ({int res; asm("divul %1,%2,%3": "=d" (res): \ - "d" (x2), "d" ((long)((x1) / 0x100000000ULL)), "0" ((long)(x1))); res;}) -#else -/* We know a bit about the numbers, so we can do it this way */ -#define DIVUL(x1, x2) ((((long)((unsigned long long)x1 >> 8) / x2) << 8) + \ - ((((long)((unsigned long long)x1 >> 8) % x2) << 8) / x2)) -#endif - -#define highw(x) ((u_long)(x)>>16 & 0xffff) -#define loww(x) ((u_long)(x) & 0xffff) - -#define custom amiga_custom - -#define VBlankOn() custom.intena = IF_SETCLR|IF_COPER -#define VBlankOff() custom.intena = IF_COPER - - - /* - * Chip RAM we reserve for the Frame Buffer - * - * This defines the Maximum Virtual Screen Size - * (Setable per kernel options?) - */ - -#define VIDEOMEMSIZE_AGA_2M (1310720) /* AGA (2MB) : max 1280*1024*256 */ -#define VIDEOMEMSIZE_AGA_1M (786432) /* AGA (1MB) : max 1024*768*256 */ -#define VIDEOMEMSIZE_ECS_2M (655360) /* ECS (2MB) : max 1280*1024*16 */ -#define VIDEOMEMSIZE_ECS_1M (393216) /* ECS (1MB) : max 1024*768*16 */ -#define VIDEOMEMSIZE_OCS (262144) /* OCS : max ca. 800*600*16 */ - -#define SPRITEMEMSIZE (64 * 64 / 4) /* max 64*64*4 */ -#define DUMMYSPRITEMEMSIZE (8) -static u_long spritememory; - -#define CHIPRAM_SAFETY_LIMIT (16384) - -static u_long videomemory; - - /* - * This is the earliest allowed start of fetching display data. - * Only if you really want no hardware cursor and audio, - * set this to 128, but let it better at 192 - */ - -static u_long min_fstrt = 192; - -#define assignchunk(name, type, ptr, size) \ -{ \ - (name) = (type)(ptr); \ - ptr += size; \ -} - - - /* - * Copper Instructions - */ - -#define CMOVE(val, reg) (CUSTOM_OFS(reg) << 16 | (val)) -#define CMOVE2(val, reg) ((CUSTOM_OFS(reg) + 2) << 16 | (val)) -#define CWAIT(x, y) (((y) & 0x1fe) << 23 | ((x) & 0x7f0) << 13 | 0x0001fffe) -#define CEND (0xfffffffe) - - -typedef union { - u_long l; - u_short w[2]; -} copins; - -static struct copdisplay { - copins *init; - copins *wait; - copins *list[2][2]; - copins *rebuild[2]; -} copdisplay; - -static u_short currentcop = 0; - - /* - * Hardware Cursor API Definitions - * These used to be in linux/fb.h, but were preliminary and used by - * amifb only anyway - */ - -#define FBIOGET_FCURSORINFO 0x4607 -#define FBIOGET_VCURSORINFO 0x4608 -#define FBIOPUT_VCURSORINFO 0x4609 -#define FBIOGET_CURSORSTATE 0x460A -#define FBIOPUT_CURSORSTATE 0x460B - - -struct fb_fix_cursorinfo { - __u16 crsr_width; /* width and height of the cursor in */ - __u16 crsr_height; /* pixels (zero if no cursor) */ - __u16 crsr_xsize; /* cursor size in display pixels */ - __u16 crsr_ysize; - __u16 crsr_color1; /* colormap entry for cursor color1 */ - __u16 crsr_color2; /* colormap entry for cursor color2 */ -}; - -struct fb_var_cursorinfo { - __u16 width; - __u16 height; - __u16 xspot; - __u16 yspot; - __u8 data[1]; /* field with [height][width] */ -}; - -struct fb_cursorstate { - __s16 xoffset; - __s16 yoffset; - __u16 mode; -}; - -#define FB_CURSOR_OFF 0 -#define FB_CURSOR_ON 1 -#define FB_CURSOR_FLASH 2 - - - /* - * Hardware Cursor - */ - -static int cursorrate = 20; /* Number of frames/flash toggle */ -static u_short cursorstate = -1; -static u_short cursormode = FB_CURSOR_OFF; - -static u_short *lofsprite, *shfsprite, *dummysprite; - - /* - * Current Video Mode - */ - -struct amifb_par { - - /* General Values */ - - int xres; /* vmode */ - int yres; /* vmode */ - int vxres; /* vmode */ - int vyres; /* vmode */ - int xoffset; /* vmode */ - int yoffset; /* vmode */ - u_short bpp; /* vmode */ - u_short clk_shift; /* vmode */ - u_short line_shift; /* vmode */ - int vmode; /* vmode */ - u_short diwstrt_h; /* vmode */ - u_short diwstop_h; /* vmode */ - u_short diwstrt_v; /* vmode */ - u_short diwstop_v; /* vmode */ - u_long next_line; /* modulo for next line */ - u_long next_plane; /* modulo for next plane */ - - /* Cursor Values */ - - struct { - short crsr_x; /* movecursor */ - short crsr_y; /* movecursor */ - short spot_x; - short spot_y; - u_short height; - u_short width; - u_short fmode; - } crsr; - - /* OCS Hardware Registers */ - - u_long bplpt0; /* vmode, pan (Note: physical address) */ - u_long bplpt0wrap; /* vmode, pan (Note: physical address) */ - u_short ddfstrt; - u_short ddfstop; - u_short bpl1mod; - u_short bpl2mod; - u_short bplcon0; /* vmode */ - u_short bplcon1; /* vmode */ - u_short htotal; /* vmode */ - u_short vtotal; /* vmode */ - - /* Additional ECS Hardware Registers */ - - u_short bplcon3; /* vmode */ - u_short beamcon0; /* vmode */ - u_short hsstrt; /* vmode */ - u_short hsstop; /* vmode */ - u_short hbstrt; /* vmode */ - u_short hbstop; /* vmode */ - u_short vsstrt; /* vmode */ - u_short vsstop; /* vmode */ - u_short vbstrt; /* vmode */ - u_short vbstop; /* vmode */ - u_short hcenter; /* vmode */ - - /* Additional AGA Hardware Registers */ - - u_short fmode; /* vmode */ -}; - - - /* - * Saved color entry 0 so we can restore it when unblanking - */ - -static u_char red0, green0, blue0; - - -#if defined(CONFIG_FB_AMIGA_ECS) -static u_short ecs_palette[32]; -#endif - - - /* - * Latches for Display Changes during VBlank - */ - -static u_short do_vmode_full = 0; /* Change the Video Mode */ -static u_short do_vmode_pan = 0; /* Update the Video Mode */ -static short do_blank = 0; /* (Un)Blank the Screen (±1) */ -static u_short do_cursor = 0; /* Move the Cursor */ - - - /* - * Various Flags - */ - -static u_short is_blanked = 0; /* Screen is Blanked */ -static u_short is_lace = 0; /* Screen is laced */ - - /* - * Predefined Video Modes - * - */ - -static struct fb_videomode ami_modedb[] __initdata = { - - /* - * AmigaOS Video Modes - * - * If you change these, make sure to update DEFMODE_* as well! - */ - - { - /* 640x200, 15 kHz, 60 Hz (NTSC) */ - "ntsc", 60, 640, 200, TAG_HIRES, 106, 86, 44, 16, 76, 2, - FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP - }, { - /* 640x400, 15 kHz, 60 Hz interlaced (NTSC) */ - "ntsc-lace", 60, 640, 400, TAG_HIRES, 106, 86, 88, 33, 76, 4, - FB_SYNC_BROADCAST, FB_VMODE_INTERLACED | FB_VMODE_YWRAP - }, { - /* 640x256, 15 kHz, 50 Hz (PAL) */ - "pal", 50, 640, 256, TAG_HIRES, 106, 86, 40, 14, 76, 2, - FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP - }, { - /* 640x512, 15 kHz, 50 Hz interlaced (PAL) */ - "pal-lace", 50, 640, 512, TAG_HIRES, 106, 86, 80, 29, 76, 4, - FB_SYNC_BROADCAST, FB_VMODE_INTERLACED | FB_VMODE_YWRAP - }, { - /* 640x480, 29 kHz, 57 Hz */ - "multiscan", 57, 640, 480, TAG_SHRES, 96, 112, 29, 8, 72, 8, - 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP - }, { - /* 640x960, 29 kHz, 57 Hz interlaced */ - "multiscan-lace", 57, 640, 960, TAG_SHRES, 96, 112, 58, 16, 72, - 16, - 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP - }, { - /* 640x200, 15 kHz, 72 Hz */ - "euro36", 72, 640, 200, TAG_HIRES, 92, 124, 6, 6, 52, 5, - 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP - }, { - /* 640x400, 15 kHz, 72 Hz interlaced */ - "euro36-lace", 72, 640, 400, TAG_HIRES, 92, 124, 12, 12, 52, - 10, - 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP - }, { - /* 640x400, 29 kHz, 68 Hz */ - "euro72", 68, 640, 400, TAG_SHRES, 164, 92, 9, 9, 80, 8, - 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP - }, { - /* 640x800, 29 kHz, 68 Hz interlaced */ - "euro72-lace", 68, 640, 800, TAG_SHRES, 164, 92, 18, 18, 80, - 16, - 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP - }, { - /* 800x300, 23 kHz, 70 Hz */ - "super72", 70, 800, 300, TAG_SHRES, 212, 140, 10, 11, 80, 7, - 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP - }, { - /* 800x600, 23 kHz, 70 Hz interlaced */ - "super72-lace", 70, 800, 600, TAG_SHRES, 212, 140, 20, 22, 80, - 14, - 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP - }, { - /* 640x200, 27 kHz, 57 Hz doublescan */ - "dblntsc", 57, 640, 200, TAG_SHRES, 196, 124, 18, 17, 80, 4, - 0, FB_VMODE_DOUBLE | FB_VMODE_YWRAP - }, { - /* 640x400, 27 kHz, 57 Hz */ - "dblntsc-ff", 57, 640, 400, TAG_SHRES, 196, 124, 36, 35, 80, 7, - 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP - }, { - /* 640x800, 27 kHz, 57 Hz interlaced */ - "dblntsc-lace", 57, 640, 800, TAG_SHRES, 196, 124, 72, 70, 80, - 14, - 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP - }, { - /* 640x256, 27 kHz, 47 Hz doublescan */ - "dblpal", 47, 640, 256, TAG_SHRES, 196, 124, 14, 13, 80, 4, - 0, FB_VMODE_DOUBLE | FB_VMODE_YWRAP - }, { - /* 640x512, 27 kHz, 47 Hz */ - "dblpal-ff", 47, 640, 512, TAG_SHRES, 196, 124, 28, 27, 80, 7, - 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP - }, { - /* 640x1024, 27 kHz, 47 Hz interlaced */ - "dblpal-lace", 47, 640, 1024, TAG_SHRES, 196, 124, 56, 54, 80, - 14, - 0, FB_VMODE_INTERLACED | FB_VMODE_YWRAP - }, - - /* - * VGA Video Modes - */ - - { - /* 640x480, 31 kHz, 60 Hz (VGA) */ - "vga", 60, 640, 480, TAG_SHRES, 64, 96, 30, 9, 112, 2, - 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP - }, { - /* 640x400, 31 kHz, 70 Hz (VGA) */ - "vga70", 70, 640, 400, TAG_SHRES, 64, 96, 35, 12, 112, 2, - FB_SYNC_VERT_HIGH_ACT | FB_SYNC_COMP_HIGH_ACT, - FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP - }, - -#if 0 - - /* - * A2024 video modes - * These modes don't work yet because there's no A2024 driver. - */ - - { - /* 1024x800, 10 Hz */ - "a2024-10", 10, 1024, 800, TAG_HIRES, 0, 0, 0, 0, 0, 0, - 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP - }, { - /* 1024x800, 15 Hz */ - "a2024-15", 15, 1024, 800, TAG_HIRES, 0, 0, 0, 0, 0, 0, - 0, FB_VMODE_NONINTERLACED | FB_VMODE_YWRAP - } -#endif -}; - -#define NUM_TOTAL_MODES ARRAY_SIZE(ami_modedb) - -static char *mode_option __initdata = NULL; -static int round_down_bpp = 1; /* for mode probing */ - - /* - * Some default modes - */ - - -#define DEFMODE_PAL 2 /* "pal" for PAL OCS/ECS */ -#define DEFMODE_NTSC 0 /* "ntsc" for NTSC OCS/ECS */ -#define DEFMODE_AMBER_PAL 3 /* "pal-lace" for flicker fixed PAL (A3000) */ -#define DEFMODE_AMBER_NTSC 1 /* "ntsc-lace" for flicker fixed NTSC (A3000) */ -#define DEFMODE_AGA 19 /* "vga70" for AGA */ - - -static int amifb_ilbm = 0; /* interleaved or normal bitplanes */ - -static u32 amifb_hfmin __initdata; /* monitor hfreq lower limit (Hz) */ -static u32 amifb_hfmax __initdata; /* monitor hfreq upper limit (Hz) */ -static u16 amifb_vfmin __initdata; /* monitor vfreq lower limit (Hz) */ -static u16 amifb_vfmax __initdata; /* monitor vfreq upper limit (Hz) */ - - - /* - * Macros for the conversion from real world values to hardware register - * values - * - * This helps us to keep our attention on the real stuff... - * - * Hardware limits for AGA: - * - * parameter min max step - * --------- --- ---- ---- - * diwstrt_h 0 2047 1 - * diwstrt_v 0 2047 1 - * diwstop_h 0 4095 1 - * diwstop_v 0 4095 1 - * - * ddfstrt 0 2032 16 - * ddfstop 0 2032 16 - * - * htotal 8 2048 8 - * hsstrt 0 2040 8 - * hsstop 0 2040 8 - * vtotal 1 4096 1 - * vsstrt 0 4095 1 - * vsstop 0 4095 1 - * hcenter 0 2040 8 - * - * hbstrt 0 2047 1 - * hbstop 0 2047 1 - * vbstrt 0 4095 1 - * vbstop 0 4095 1 - * - * Horizontal values are in 35 ns (SHRES) pixels - * Vertical values are in half scanlines - */ - -/* bplcon1 (smooth scrolling) */ - -#define hscroll2hw(hscroll) \ - (((hscroll) << 12 & 0x3000) | ((hscroll) << 8 & 0xc300) | \ - ((hscroll) << 4 & 0x0c00) | ((hscroll) << 2 & 0x00f0) | \ - ((hscroll)>>2 & 0x000f)) - -/* diwstrt/diwstop/diwhigh (visible display window) */ - -#define diwstrt2hw(diwstrt_h, diwstrt_v) \ - (((diwstrt_v) << 7 & 0xff00) | ((diwstrt_h)>>2 & 0x00ff)) -#define diwstop2hw(diwstop_h, diwstop_v) \ - (((diwstop_v) << 7 & 0xff00) | ((diwstop_h)>>2 & 0x00ff)) -#define diwhigh2hw(diwstrt_h, diwstrt_v, diwstop_h, diwstop_v) \ - (((diwstop_h) << 3 & 0x2000) | ((diwstop_h) << 11 & 0x1800) | \ - ((diwstop_v)>>1 & 0x0700) | ((diwstrt_h)>>5 & 0x0020) | \ - ((diwstrt_h) << 3 & 0x0018) | ((diwstrt_v)>>9 & 0x0007)) - -/* ddfstrt/ddfstop (display DMA) */ - -#define ddfstrt2hw(ddfstrt) div8(ddfstrt) -#define ddfstop2hw(ddfstop) div8(ddfstop) - -/* hsstrt/hsstop/htotal/vsstrt/vsstop/vtotal/hcenter (sync timings) */ - -#define hsstrt2hw(hsstrt) (div8(hsstrt)) -#define hsstop2hw(hsstop) (div8(hsstop)) -#define htotal2hw(htotal) (div8(htotal) - 1) -#define vsstrt2hw(vsstrt) (div2(vsstrt)) -#define vsstop2hw(vsstop) (div2(vsstop)) -#define vtotal2hw(vtotal) (div2(vtotal) - 1) -#define hcenter2hw(htotal) (div8(htotal)) - -/* hbstrt/hbstop/vbstrt/vbstop (blanking timings) */ - -#define hbstrt2hw(hbstrt) (((hbstrt) << 8 & 0x0700) | ((hbstrt)>>3 & 0x00ff)) -#define hbstop2hw(hbstop) (((hbstop) << 8 & 0x0700) | ((hbstop)>>3 & 0x00ff)) -#define vbstrt2hw(vbstrt) (div2(vbstrt)) -#define vbstop2hw(vbstop) (div2(vbstop)) - -/* colour */ - -#define rgb2hw8_high(red, green, blue) \ - (((red & 0xf0) << 4) | (green & 0xf0) | ((blue & 0xf0)>>4)) -#define rgb2hw8_low(red, green, blue) \ - (((red & 0x0f) << 8) | ((green & 0x0f) << 4) | (blue & 0x0f)) -#define rgb2hw4(red, green, blue) \ - (((red & 0xf0) << 4) | (green & 0xf0) | ((blue & 0xf0)>>4)) -#define rgb2hw2(red, green, blue) \ - (((red & 0xc0) << 4) | (green & 0xc0) | ((blue & 0xc0)>>4)) - -/* sprpos/sprctl (sprite positioning) */ - -#define spr2hw_pos(start_v, start_h) \ - (((start_v) << 7 & 0xff00) | ((start_h)>>3 & 0x00ff)) -#define spr2hw_ctl(start_v, start_h, stop_v) \ - (((stop_v) << 7 & 0xff00) | ((start_v)>>4 & 0x0040) | \ - ((stop_v)>>5 & 0x0020) | ((start_h) << 3 & 0x0018) | \ - ((start_v)>>7 & 0x0004) | ((stop_v)>>8 & 0x0002) | \ - ((start_h)>>2 & 0x0001)) - -/* get current vertical position of beam */ -#define get_vbpos() ((u_short)((*(u_long volatile *)&custom.vposr >> 7) & 0xffe)) - - /* - * Copper Initialisation List - */ - -#define COPINITSIZE (sizeof(copins) * 40) - -enum { - cip_bplcon0 -}; - - /* - * Long Frame/Short Frame Copper List - * Don't change the order, build_copper()/rebuild_copper() rely on this - */ - -#define COPLISTSIZE (sizeof(copins) * 64) - -enum { - cop_wait, cop_bplcon0, - cop_spr0ptrh, cop_spr0ptrl, - cop_diwstrt, cop_diwstop, - cop_diwhigh, -}; - - /* - * Pixel modes for Bitplanes and Sprites - */ - -static u_short bplpixmode[3] = { - BPC0_SHRES, /* 35 ns */ - BPC0_HIRES, /* 70 ns */ - 0 /* 140 ns */ -}; - -static u_short sprpixmode[3] = { - BPC3_SPRES1 | BPC3_SPRES0, /* 35 ns */ - BPC3_SPRES1, /* 70 ns */ - BPC3_SPRES0 /* 140 ns */ -}; - - /* - * Fetch modes for Bitplanes and Sprites - */ - -static u_short bplfetchmode[3] = { - 0, /* 1x */ - FMODE_BPL32, /* 2x */ - FMODE_BPAGEM | FMODE_BPL32 /* 4x */ -}; - -static u_short sprfetchmode[3] = { - 0, /* 1x */ - FMODE_SPR32, /* 2x */ - FMODE_SPAGEM | FMODE_SPR32 /* 4x */ -}; - - -/* --------------------------- Hardware routines --------------------------- */ - - /* - * Get the video params out of `var'. If a value doesn't fit, round - * it up, if it's too big, return -EINVAL. - */ - -static int ami_decode_var(struct fb_var_screeninfo *var, struct amifb_par *par, - const struct fb_info *info) -{ - u_short clk_shift, line_shift; - u_long maxfetchstop, fstrt, fsize, fconst, xres_n, yres_n; - u_int htotal, vtotal; - - /* - * Find a matching Pixel Clock - */ - - for (clk_shift = TAG_SHRES; clk_shift <= TAG_LORES; clk_shift++) - if (var->pixclock <= pixclock[clk_shift]) - break; - if (clk_shift > TAG_LORES) { - DPRINTK("pixclock too high\n"); - return -EINVAL; - } - par->clk_shift = clk_shift; - - /* - * Check the Geometry Values - */ - - if ((par->xres = var->xres) < 64) - par->xres = 64; - if ((par->yres = var->yres) < 64) - par->yres = 64; - if ((par->vxres = var->xres_virtual) < par->xres) - par->vxres = par->xres; - if ((par->vyres = var->yres_virtual) < par->yres) - par->vyres = par->yres; - - par->bpp = var->bits_per_pixel; - if (!var->nonstd) { - if (par->bpp < 1) - par->bpp = 1; - if (par->bpp > maxdepth[clk_shift]) { - if (round_down_bpp && maxdepth[clk_shift]) - par->bpp = maxdepth[clk_shift]; - else { - DPRINTK("invalid bpp\n"); - return -EINVAL; - } - } - } else if (var->nonstd == FB_NONSTD_HAM) { - if (par->bpp < 6) - par->bpp = 6; - if (par->bpp != 6) { - if (par->bpp < 8) - par->bpp = 8; - if (par->bpp != 8 || !IS_AGA) { - DPRINTK("invalid bpp for ham mode\n"); - return -EINVAL; - } - } - } else { - DPRINTK("unknown nonstd mode\n"); - return -EINVAL; - } - - /* - * FB_VMODE_SMOOTH_XPAN will be cleared, if one of the following - * checks failed and smooth scrolling is not possible - */ - - par->vmode = var->vmode | FB_VMODE_SMOOTH_XPAN; - switch (par->vmode & FB_VMODE_MASK) { - case FB_VMODE_INTERLACED: - line_shift = 0; - break; - case FB_VMODE_NONINTERLACED: - line_shift = 1; - break; - case FB_VMODE_DOUBLE: - if (!IS_AGA) { - DPRINTK("double mode only possible with aga\n"); - return -EINVAL; - } - line_shift = 2; - break; - default: - DPRINTK("unknown video mode\n"); - return -EINVAL; - break; - } - par->line_shift = line_shift; - - /* - * Vertical and Horizontal Timings - */ - - xres_n = par->xres << clk_shift; - yres_n = par->yres << line_shift; - par->htotal = down8((var->left_margin + par->xres + var->right_margin + - var->hsync_len) << clk_shift); - par->vtotal = - down2(((var->upper_margin + par->yres + var->lower_margin + - var->vsync_len) << line_shift) + 1); - - if (IS_AGA) - par->bplcon3 = sprpixmode[clk_shift]; - else - par->bplcon3 = 0; - if (var->sync & FB_SYNC_BROADCAST) { - par->diwstop_h = par->htotal - - ((var->right_margin - var->hsync_len) << clk_shift); - if (IS_AGA) - par->diwstop_h += mod4(var->hsync_len); - else - par->diwstop_h = down4(par->diwstop_h); - - par->diwstrt_h = par->diwstop_h - xres_n; - par->diwstop_v = par->vtotal - - ((var->lower_margin - var->vsync_len) << line_shift); - par->diwstrt_v = par->diwstop_v - yres_n; - if (par->diwstop_h >= par->htotal + 8) { - DPRINTK("invalid diwstop_h\n"); - return -EINVAL; - } - if (par->diwstop_v > par->vtotal) { - DPRINTK("invalid diwstop_v\n"); - return -EINVAL; - } - - if (!IS_OCS) { - /* Initialize sync with some reasonable values for pwrsave */ - par->hsstrt = 160; - par->hsstop = 320; - par->vsstrt = 30; - par->vsstop = 34; - } else { - par->hsstrt = 0; - par->hsstop = 0; - par->vsstrt = 0; - par->vsstop = 0; - } - if (par->vtotal > (PAL_VTOTAL + NTSC_VTOTAL) / 2) { - /* PAL video mode */ - if (par->htotal != PAL_HTOTAL) { - DPRINTK("htotal invalid for pal\n"); - return -EINVAL; - } - if (par->diwstrt_h < PAL_DIWSTRT_H) { - DPRINTK("diwstrt_h too low for pal\n"); - return -EINVAL; - } - if (par->diwstrt_v < PAL_DIWSTRT_V) { - DPRINTK("diwstrt_v too low for pal\n"); - return -EINVAL; - } - htotal = PAL_HTOTAL>>clk_shift; - vtotal = PAL_VTOTAL>>1; - if (!IS_OCS) { - par->beamcon0 = BMC0_PAL; - par->bplcon3 |= BPC3_BRDRBLNK; - } else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) || - AMIGAHW_PRESENT(AGNUS_HR_NTSC)) { - par->beamcon0 = BMC0_PAL; - par->hsstop = 1; - } else if (amiga_vblank != 50) { - DPRINTK("pal not supported by this chipset\n"); - return -EINVAL; - } - } else { - /* NTSC video mode - * In the AGA chipset seems to be hardware bug with BPC3_BRDRBLNK - * and NTSC activated, so than better let diwstop_h <= 1812 - */ - if (par->htotal != NTSC_HTOTAL) { - DPRINTK("htotal invalid for ntsc\n"); - return -EINVAL; - } - if (par->diwstrt_h < NTSC_DIWSTRT_H) { - DPRINTK("diwstrt_h too low for ntsc\n"); - return -EINVAL; - } - if (par->diwstrt_v < NTSC_DIWSTRT_V) { - DPRINTK("diwstrt_v too low for ntsc\n"); - return -EINVAL; - } - htotal = NTSC_HTOTAL>>clk_shift; - vtotal = NTSC_VTOTAL>>1; - if (!IS_OCS) { - par->beamcon0 = 0; - par->bplcon3 |= BPC3_BRDRBLNK; - } else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) || - AMIGAHW_PRESENT(AGNUS_HR_NTSC)) { - par->beamcon0 = 0; - par->hsstop = 1; - } else if (amiga_vblank != 60) { - DPRINTK("ntsc not supported by this chipset\n"); - return -EINVAL; - } - } - if (IS_OCS) { - if (par->diwstrt_h >= 1024 || par->diwstop_h < 1024 || - par->diwstrt_v >= 512 || par->diwstop_v < 256) { - DPRINTK("invalid position for display on ocs\n"); - return -EINVAL; - } - } - } else if (!IS_OCS) { - /* Programmable video mode */ - par->hsstrt = var->right_margin << clk_shift; - par->hsstop = (var->right_margin + var->hsync_len) << clk_shift; - par->diwstop_h = par->htotal - mod8(par->hsstrt) + 8 - (1 << clk_shift); - if (!IS_AGA) - par->diwstop_h = down4(par->diwstop_h) - 16; - par->diwstrt_h = par->diwstop_h - xres_n; - par->hbstop = par->diwstrt_h + 4; - par->hbstrt = par->diwstop_h + 4; - if (par->hbstrt >= par->htotal + 8) - par->hbstrt -= par->htotal; - par->hcenter = par->hsstrt + (par->htotal >> 1); - par->vsstrt = var->lower_margin << line_shift; - par->vsstop = (var->lower_margin + var->vsync_len) << line_shift; - par->diwstop_v = par->vtotal; - if ((par->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) - par->diwstop_v -= 2; - par->diwstrt_v = par->diwstop_v - yres_n; - par->vbstop = par->diwstrt_v - 2; - par->vbstrt = par->diwstop_v - 2; - if (par->vtotal > 2048) { - DPRINTK("vtotal too high\n"); - return -EINVAL; - } - if (par->htotal > 2048) { - DPRINTK("htotal too high\n"); - return -EINVAL; - } - par->bplcon3 |= BPC3_EXTBLKEN; - par->beamcon0 = BMC0_HARDDIS | BMC0_VARVBEN | BMC0_LOLDIS | - BMC0_VARVSYEN | BMC0_VARHSYEN | BMC0_VARBEAMEN | - BMC0_PAL | BMC0_VARCSYEN; - if (var->sync & FB_SYNC_HOR_HIGH_ACT) - par->beamcon0 |= BMC0_HSYTRUE; - if (var->sync & FB_SYNC_VERT_HIGH_ACT) - par->beamcon0 |= BMC0_VSYTRUE; - if (var->sync & FB_SYNC_COMP_HIGH_ACT) - par->beamcon0 |= BMC0_CSYTRUE; - htotal = par->htotal>>clk_shift; - vtotal = par->vtotal>>1; - } else { - DPRINTK("only broadcast modes possible for ocs\n"); - return -EINVAL; - } - - /* - * Checking the DMA timing - */ - - fconst = 16 << maxfmode << clk_shift; - - /* - * smallest window start value without turn off other dma cycles - * than sprite1-7, unless you change min_fstrt - */ - - - fsize = ((maxfmode + clk_shift <= 1) ? fconst : 64); - fstrt = downx(fconst, par->diwstrt_h - 4) - fsize; - if (fstrt < min_fstrt) { - DPRINTK("fetch start too low\n"); - return -EINVAL; - } - - /* - * smallest window start value where smooth scrolling is possible - */ - - fstrt = downx(fconst, par->diwstrt_h - fconst + (1 << clk_shift) - 4) - - fsize; - if (fstrt < min_fstrt) - par->vmode &= ~FB_VMODE_SMOOTH_XPAN; - - maxfetchstop = down16(par->htotal - 80); - - fstrt = downx(fconst, par->diwstrt_h - 4) - 64 - fconst; - fsize = upx(fconst, xres_n + - modx(fconst, downx(1 << clk_shift, par->diwstrt_h - 4))); - if (fstrt + fsize > maxfetchstop) - par->vmode &= ~FB_VMODE_SMOOTH_XPAN; - - fsize = upx(fconst, xres_n); - if (fstrt + fsize > maxfetchstop) { - DPRINTK("fetch stop too high\n"); - return -EINVAL; - } - - if (maxfmode + clk_shift <= 1) { - fsize = up64(xres_n + fconst - 1); - if (min_fstrt + fsize - 64 > maxfetchstop) - par->vmode &= ~FB_VMODE_SMOOTH_XPAN; - - fsize = up64(xres_n); - if (min_fstrt + fsize - 64 > maxfetchstop) { - DPRINTK("fetch size too high\n"); - return -EINVAL; - } - - fsize -= 64; - } else - fsize -= fconst; - - /* - * Check if there is enough time to update the bitplane pointers for ywrap - */ - - if (par->htotal - fsize - 64 < par->bpp * 64) - par->vmode &= ~FB_VMODE_YWRAP; - - /* - * Bitplane calculations and check the Memory Requirements - */ - - if (amifb_ilbm) { - par->next_plane = div8(upx(16 << maxfmode, par->vxres)); - par->next_line = par->bpp * par->next_plane; - if (par->next_line * par->vyres > info->fix.smem_len) { - DPRINTK("too few video mem\n"); - return -EINVAL; - } - } else { - par->next_line = div8(upx(16 << maxfmode, par->vxres)); - par->next_plane = par->vyres * par->next_line; - if (par->next_plane * par->bpp > info->fix.smem_len) { - DPRINTK("too few video mem\n"); - return -EINVAL; - } - } - - /* - * Hardware Register Values - */ - - par->bplcon0 = BPC0_COLOR | bplpixmode[clk_shift]; - if (!IS_OCS) - par->bplcon0 |= BPC0_ECSENA; - if (par->bpp == 8) - par->bplcon0 |= BPC0_BPU3; - else - par->bplcon0 |= par->bpp << 12; - if (var->nonstd == FB_NONSTD_HAM) - par->bplcon0 |= BPC0_HAM; - if (var->sync & FB_SYNC_EXT) - par->bplcon0 |= BPC0_ERSY; - - if (IS_AGA) - par->fmode = bplfetchmode[maxfmode]; - - switch (par->vmode & FB_VMODE_MASK) { - case FB_VMODE_INTERLACED: - par->bplcon0 |= BPC0_LACE; - break; - case FB_VMODE_DOUBLE: - if (IS_AGA) - par->fmode |= FMODE_SSCAN2 | FMODE_BSCAN2; - break; - } - - if (!((par->vmode ^ var->vmode) & FB_VMODE_YWRAP)) { - par->xoffset = var->xoffset; - par->yoffset = var->yoffset; - if (par->vmode & FB_VMODE_YWRAP) { - if (par->xoffset || par->yoffset < 0 || - par->yoffset >= par->vyres) - par->xoffset = par->yoffset = 0; - } else { - if (par->xoffset < 0 || - par->xoffset > upx(16 << maxfmode, par->vxres - par->xres) || - par->yoffset < 0 || par->yoffset > par->vyres - par->yres) - par->xoffset = par->yoffset = 0; - } - } else - par->xoffset = par->yoffset = 0; - - par->crsr.crsr_x = par->crsr.crsr_y = 0; - par->crsr.spot_x = par->crsr.spot_y = 0; - par->crsr.height = par->crsr.width = 0; - - return 0; -} - - /* - * Fill the `var' structure based on the values in `par' and maybe - * other values read out of the hardware. - */ - -static void ami_encode_var(struct fb_var_screeninfo *var, - struct amifb_par *par) -{ - u_short clk_shift, line_shift; - - memset(var, 0, sizeof(struct fb_var_screeninfo)); - - clk_shift = par->clk_shift; - line_shift = par->line_shift; - - var->xres = par->xres; - var->yres = par->yres; - var->xres_virtual = par->vxres; - var->yres_virtual = par->vyres; - var->xoffset = par->xoffset; - var->yoffset = par->yoffset; - - var->bits_per_pixel = par->bpp; - var->grayscale = 0; - - var->red.offset = 0; - var->red.msb_right = 0; - var->red.length = par->bpp; - if (par->bplcon0 & BPC0_HAM) - var->red.length -= 2; - var->blue = var->green = var->red; - var->transp.offset = 0; - var->transp.length = 0; - var->transp.msb_right = 0; - - if (par->bplcon0 & BPC0_HAM) - var->nonstd = FB_NONSTD_HAM; - else - var->nonstd = 0; - var->activate = 0; - - var->height = -1; - var->width = -1; - - var->pixclock = pixclock[clk_shift]; - - if (IS_AGA && par->fmode & FMODE_BSCAN2) - var->vmode = FB_VMODE_DOUBLE; - else if (par->bplcon0 & BPC0_LACE) - var->vmode = FB_VMODE_INTERLACED; - else - var->vmode = FB_VMODE_NONINTERLACED; - - if (!IS_OCS && par->beamcon0 & BMC0_VARBEAMEN) { - var->hsync_len = (par->hsstop - par->hsstrt)>>clk_shift; - var->right_margin = par->hsstrt>>clk_shift; - var->left_margin = (par->htotal>>clk_shift) - var->xres - var->right_margin - var->hsync_len; - var->vsync_len = (par->vsstop - par->vsstrt)>>line_shift; - var->lower_margin = par->vsstrt>>line_shift; - var->upper_margin = (par->vtotal>>line_shift) - var->yres - var->lower_margin - var->vsync_len; - var->sync = 0; - if (par->beamcon0 & BMC0_HSYTRUE) - var->sync |= FB_SYNC_HOR_HIGH_ACT; - if (par->beamcon0 & BMC0_VSYTRUE) - var->sync |= FB_SYNC_VERT_HIGH_ACT; - if (par->beamcon0 & BMC0_CSYTRUE) - var->sync |= FB_SYNC_COMP_HIGH_ACT; - } else { - var->sync = FB_SYNC_BROADCAST; - var->hsync_len = (152>>clk_shift) + mod4(par->diwstop_h); - var->right_margin = ((par->htotal - down4(par->diwstop_h))>>clk_shift) + var->hsync_len; - var->left_margin = (par->htotal>>clk_shift) - var->xres - var->right_margin - var->hsync_len; - var->vsync_len = 4>>line_shift; - var->lower_margin = ((par->vtotal - par->diwstop_v)>>line_shift) + var->vsync_len; - var->upper_margin = (((par->vtotal - 2)>>line_shift) + 1) - var->yres - - var->lower_margin - var->vsync_len; - } - - if (par->bplcon0 & BPC0_ERSY) - var->sync |= FB_SYNC_EXT; - if (par->vmode & FB_VMODE_YWRAP) - var->vmode |= FB_VMODE_YWRAP; -} - - - /* - * Update hardware - */ - -static void ami_update_par(struct fb_info *info) -{ - struct amifb_par *par = info->par; - short clk_shift, vshift, fstrt, fsize, fstop, fconst, shift, move, mod; - - clk_shift = par->clk_shift; - - if (!(par->vmode & FB_VMODE_SMOOTH_XPAN)) - par->xoffset = upx(16 << maxfmode, par->xoffset); - - fconst = 16 << maxfmode << clk_shift; - vshift = modx(16 << maxfmode, par->xoffset); - fstrt = par->diwstrt_h - (vshift << clk_shift) - 4; - fsize = (par->xres + vshift) << clk_shift; - shift = modx(fconst, fstrt); - move = downx(2 << maxfmode, div8(par->xoffset)); - if (maxfmode + clk_shift > 1) { - fstrt = downx(fconst, fstrt) - 64; - fsize = upx(fconst, fsize); - fstop = fstrt + fsize - fconst; - } else { - mod = fstrt = downx(fconst, fstrt) - fconst; - fstop = fstrt + upx(fconst, fsize) - 64; - fsize = up64(fsize); - fstrt = fstop - fsize + 64; - if (fstrt < min_fstrt) { - fstop += min_fstrt - fstrt; - fstrt = min_fstrt; - } - move = move - div8((mod - fstrt)>>clk_shift); - } - mod = par->next_line - div8(fsize>>clk_shift); - par->ddfstrt = fstrt; - par->ddfstop = fstop; - par->bplcon1 = hscroll2hw(shift); - par->bpl2mod = mod; - if (par->bplcon0 & BPC0_LACE) - par->bpl2mod += par->next_line; - if (IS_AGA && (par->fmode & FMODE_BSCAN2)) - par->bpl1mod = -div8(fsize>>clk_shift); - else - par->bpl1mod = par->bpl2mod; - - if (par->yoffset) { - par->bplpt0 = info->fix.smem_start + - par->next_line * par->yoffset + move; - if (par->vmode & FB_VMODE_YWRAP) { - if (par->yoffset > par->vyres - par->yres) { - par->bplpt0wrap = info->fix.smem_start + move; - if (par->bplcon0 & BPC0_LACE && - mod2(par->diwstrt_v + par->vyres - - par->yoffset)) - par->bplpt0wrap += par->next_line; - } - } - } else - par->bplpt0 = info->fix.smem_start + move; - - if (par->bplcon0 & BPC0_LACE && mod2(par->diwstrt_v)) - par->bplpt0 += par->next_line; -} - - - /* - * Pan or Wrap the Display - * - * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag - * in `var'. - */ - -static void ami_pan_var(struct fb_var_screeninfo *var, struct fb_info *info) -{ - struct amifb_par *par = info->par; - - par->xoffset = var->xoffset; - par->yoffset = var->yoffset; - if (var->vmode & FB_VMODE_YWRAP) - par->vmode |= FB_VMODE_YWRAP; - else - par->vmode &= ~FB_VMODE_YWRAP; - - do_vmode_pan = 0; - ami_update_par(info); - do_vmode_pan = 1; -} - - -static void ami_update_display(const struct amifb_par *par) -{ - custom.bplcon1 = par->bplcon1; - custom.bpl1mod = par->bpl1mod; - custom.bpl2mod = par->bpl2mod; - custom.ddfstrt = ddfstrt2hw(par->ddfstrt); - custom.ddfstop = ddfstop2hw(par->ddfstop); -} - - /* - * Change the video mode (called by VBlank interrupt) - */ - -static void ami_init_display(const struct amifb_par *par) -{ - int i; - - custom.bplcon0 = par->bplcon0 & ~BPC0_LACE; - custom.bplcon2 = (IS_OCS ? 0 : BPC2_KILLEHB) | BPC2_PF2P2 | BPC2_PF1P2; - if (!IS_OCS) { - custom.bplcon3 = par->bplcon3; - if (IS_AGA) - custom.bplcon4 = BPC4_ESPRM4 | BPC4_OSPRM4; - if (par->beamcon0 & BMC0_VARBEAMEN) { - custom.htotal = htotal2hw(par->htotal); - custom.hbstrt = hbstrt2hw(par->hbstrt); - custom.hbstop = hbstop2hw(par->hbstop); - custom.hsstrt = hsstrt2hw(par->hsstrt); - custom.hsstop = hsstop2hw(par->hsstop); - custom.hcenter = hcenter2hw(par->hcenter); - custom.vtotal = vtotal2hw(par->vtotal); - custom.vbstrt = vbstrt2hw(par->vbstrt); - custom.vbstop = vbstop2hw(par->vbstop); - custom.vsstrt = vsstrt2hw(par->vsstrt); - custom.vsstop = vsstop2hw(par->vsstop); - } - } - if (!IS_OCS || par->hsstop) - custom.beamcon0 = par->beamcon0; - if (IS_AGA) - custom.fmode = par->fmode; - - /* - * The minimum period for audio depends on htotal - */ - - amiga_audio_min_period = div16(par->htotal); - - is_lace = par->bplcon0 & BPC0_LACE ? 1 : 0; -#if 1 - if (is_lace) { - i = custom.vposr >> 15; - } else { - custom.vposw = custom.vposr | 0x8000; - i = 1; - } -#else - i = 1; - custom.vposw = custom.vposr | 0x8000; -#endif - custom.cop2lc = (u_short *)ZTWO_PADDR(copdisplay.list[currentcop][i]); -} - - /* - * (Un)Blank the screen (called by VBlank interrupt) - */ - -static void ami_do_blank(const struct amifb_par *par) -{ -#if defined(CONFIG_FB_AMIGA_AGA) - u_short bplcon3 = par->bplcon3; -#endif - u_char red, green, blue; - - if (do_blank > 0) { - custom.dmacon = DMAF_RASTER | DMAF_SPRITE; - red = green = blue = 0; - if (!IS_OCS && do_blank > 1) { - switch (do_blank) { - case FB_BLANK_VSYNC_SUSPEND: - custom.hsstrt = hsstrt2hw(par->hsstrt); - custom.hsstop = hsstop2hw(par->hsstop); - custom.vsstrt = vsstrt2hw(par->vtotal + 4); - custom.vsstop = vsstop2hw(par->vtotal + 4); - break; - case FB_BLANK_HSYNC_SUSPEND: - custom.hsstrt = hsstrt2hw(par->htotal + 16); - custom.hsstop = hsstop2hw(par->htotal + 16); - custom.vsstrt = vsstrt2hw(par->vsstrt); - custom.vsstop = vsstrt2hw(par->vsstop); - break; - case FB_BLANK_POWERDOWN: - custom.hsstrt = hsstrt2hw(par->htotal + 16); - custom.hsstop = hsstop2hw(par->htotal + 16); - custom.vsstrt = vsstrt2hw(par->vtotal + 4); - custom.vsstop = vsstop2hw(par->vtotal + 4); - break; - } - if (!(par->beamcon0 & BMC0_VARBEAMEN)) { - custom.htotal = htotal2hw(par->htotal); - custom.vtotal = vtotal2hw(par->vtotal); - custom.beamcon0 = BMC0_HARDDIS | BMC0_VARBEAMEN | - BMC0_VARVSYEN | BMC0_VARHSYEN | BMC0_VARCSYEN; - } - } - } else { - custom.dmacon = DMAF_SETCLR | DMAF_RASTER | DMAF_SPRITE; - red = red0; - green = green0; - blue = blue0; - if (!IS_OCS) { - custom.hsstrt = hsstrt2hw(par->hsstrt); - custom.hsstop = hsstop2hw(par->hsstop); - custom.vsstrt = vsstrt2hw(par->vsstrt); - custom.vsstop = vsstop2hw(par->vsstop); - custom.beamcon0 = par->beamcon0; - } - } -#if defined(CONFIG_FB_AMIGA_AGA) - if (IS_AGA) { - custom.bplcon3 = bplcon3; - custom.color[0] = rgb2hw8_high(red, green, blue); - custom.bplcon3 = bplcon3 | BPC3_LOCT; - custom.color[0] = rgb2hw8_low(red, green, blue); - custom.bplcon3 = bplcon3; - } else -#endif -#if defined(CONFIG_FB_AMIGA_ECS) - if (par->bplcon0 & BPC0_SHRES) { - u_short color, mask; - int i; - - mask = 0x3333; - color = rgb2hw2(red, green, blue); - for (i = 12; i >= 0; i -= 4) - custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color; - mask <<= 2; color >>= 2; - for (i = 3; i >= 0; i--) - custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color; - } else -#endif - custom.color[0] = rgb2hw4(red, green, blue); - is_blanked = do_blank > 0 ? do_blank : 0; -} - -static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, - const struct amifb_par *par) -{ - fix->crsr_width = fix->crsr_xsize = par->crsr.width; - fix->crsr_height = fix->crsr_ysize = par->crsr.height; - fix->crsr_color1 = 17; - fix->crsr_color2 = 18; - return 0; -} - -static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, - u_char __user *data, - const struct amifb_par *par) -{ - register u_short *lspr, *sspr; -#ifdef __mc68000__ - register u_long datawords asm ("d2"); -#else - register u_long datawords; -#endif - register short delta; - register u_char color; - short height, width, bits, words; - int size, alloc; - - size = par->crsr.height * par->crsr.width; - alloc = var->height * var->width; - var->height = par->crsr.height; - var->width = par->crsr.width; - var->xspot = par->crsr.spot_x; - var->yspot = par->crsr.spot_y; - if (size > var->height * var->width) - return -ENAMETOOLONG; - if (!access_ok(VERIFY_WRITE, data, size)) - return -EFAULT; - delta = 1 << par->crsr.fmode; - lspr = lofsprite + (delta << 1); - if (par->bplcon0 & BPC0_LACE) - sspr = shfsprite + (delta << 1); - else - sspr = NULL; - for (height = (short)var->height - 1; height >= 0; height--) { - bits = 0; words = delta; datawords = 0; - for (width = (short)var->width - 1; width >= 0; width--) { - if (bits == 0) { - bits = 16; --words; -#ifdef __mc68000__ - asm volatile ("movew %1@(%3:w:2),%0 ; swap %0 ; movew %1@+,%0" - : "=d" (datawords), "=a" (lspr) : "1" (lspr), "d" (delta)); -#else - datawords = (*(lspr + delta) << 16) | (*lspr++); -#endif - } - --bits; -#ifdef __mc68000__ - asm volatile ( - "clrb %0 ; swap %1 ; lslw #1,%1 ; roxlb #1,%0 ; " - "swap %1 ; lslw #1,%1 ; roxlb #1,%0" - : "=d" (color), "=d" (datawords) : "1" (datawords)); -#else - color = (((datawords >> 30) & 2) - | ((datawords >> 15) & 1)); - datawords <<= 1; -#endif - put_user(color, data++); - } - if (bits > 0) { - --words; ++lspr; - } - while (--words >= 0) - ++lspr; -#ifdef __mc68000__ - asm volatile ("lea %0@(%4:w:2),%0 ; tstl %1 ; jeq 1f ; exg %0,%1\n1:" - : "=a" (lspr), "=a" (sspr) : "0" (lspr), "1" (sspr), "d" (delta)); -#else - lspr += delta; - if (sspr) { - u_short *tmp = lspr; - lspr = sspr; - sspr = tmp; - } -#endif - } - return 0; -} - -static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, - u_char __user *data, struct amifb_par *par) -{ - register u_short *lspr, *sspr; -#ifdef __mc68000__ - register u_long datawords asm ("d2"); -#else - register u_long datawords; -#endif - register short delta; - u_short fmode; - short height, width, bits, words; - - if (!var->width) - return -EINVAL; - else if (var->width <= 16) - fmode = TAG_FMODE_1; - else if (var->width <= 32) - fmode = TAG_FMODE_2; - else if (var->width <= 64) - fmode = TAG_FMODE_4; - else - return -EINVAL; - if (fmode > maxfmode) - return -EINVAL; - if (!var->height) - return -EINVAL; - if (!access_ok(VERIFY_READ, data, var->width * var->height)) - return -EFAULT; - delta = 1 << fmode; - lofsprite = shfsprite = (u_short *)spritememory; - lspr = lofsprite + (delta << 1); - if (par->bplcon0 & BPC0_LACE) { - if (((var->height + 4) << fmode << 2) > SPRITEMEMSIZE) - return -EINVAL; - memset(lspr, 0, (var->height + 4) << fmode << 2); - shfsprite += ((var->height + 5)&-2) << fmode; - sspr = shfsprite + (delta << 1); - } else { - if (((var->height + 2) << fmode << 2) > SPRITEMEMSIZE) - return -EINVAL; - memset(lspr, 0, (var->height + 2) << fmode << 2); - sspr = NULL; - } - for (height = (short)var->height - 1; height >= 0; height--) { - bits = 16; words = delta; datawords = 0; - for (width = (short)var->width - 1; width >= 0; width--) { - unsigned long tdata = 0; - get_user(tdata, data); - data++; -#ifdef __mc68000__ - asm volatile ( - "lsrb #1,%2 ; roxlw #1,%0 ; swap %0 ; " - "lsrb #1,%2 ; roxlw #1,%0 ; swap %0" - : "=d" (datawords) - : "0" (datawords), "d" (tdata)); -#else - datawords = ((datawords << 1) & 0xfffefffe); - datawords |= tdata & 1; - datawords |= (tdata & 2) << (16 - 1); -#endif - if (--bits == 0) { - bits = 16; --words; -#ifdef __mc68000__ - asm volatile ("swap %2 ; movew %2,%0@(%3:w:2) ; swap %2 ; movew %2,%0@+" - : "=a" (lspr) : "0" (lspr), "d" (datawords), "d" (delta)); -#else - *(lspr + delta) = (u_short) (datawords >> 16); - *lspr++ = (u_short) (datawords & 0xffff); -#endif - } - } - if (bits < 16) { - --words; -#ifdef __mc68000__ - asm volatile ( - "swap %2 ; lslw %4,%2 ; movew %2,%0@(%3:w:2) ; " - "swap %2 ; lslw %4,%2 ; movew %2,%0@+" - : "=a" (lspr) : "0" (lspr), "d" (datawords), "d" (delta), "d" (bits)); -#else - *(lspr + delta) = (u_short) (datawords >> (16 + bits)); - *lspr++ = (u_short) ((datawords & 0x0000ffff) >> bits); -#endif - } - while (--words >= 0) { -#ifdef __mc68000__ - asm volatile ("moveql #0,%%d0 ; movew %%d0,%0@(%2:w:2) ; movew %%d0,%0@+" - : "=a" (lspr) : "0" (lspr), "d" (delta) : "d0"); -#else - *(lspr + delta) = 0; - *lspr++ = 0; -#endif - } -#ifdef __mc68000__ - asm volatile ("lea %0@(%4:w:2),%0 ; tstl %1 ; jeq 1f ; exg %0,%1\n1:" - : "=a" (lspr), "=a" (sspr) : "0" (lspr), "1" (sspr), "d" (delta)); -#else - lspr += delta; - if (sspr) { - u_short *tmp = lspr; - lspr = sspr; - sspr = tmp; - } -#endif - } - par->crsr.height = var->height; - par->crsr.width = var->width; - par->crsr.spot_x = var->xspot; - par->crsr.spot_y = var->yspot; - par->crsr.fmode = fmode; - if (IS_AGA) { - par->fmode &= ~(FMODE_SPAGEM | FMODE_SPR32); - par->fmode |= sprfetchmode[fmode]; - custom.fmode = par->fmode; - } - return 0; -} - -static int ami_get_cursorstate(struct fb_cursorstate *state, - const struct amifb_par *par) -{ - state->xoffset = par->crsr.crsr_x; - state->yoffset = par->crsr.crsr_y; - state->mode = cursormode; - return 0; -} - -static int ami_set_cursorstate(struct fb_cursorstate *state, - struct amifb_par *par) -{ - par->crsr.crsr_x = state->xoffset; - par->crsr.crsr_y = state->yoffset; - if ((cursormode = state->mode) == FB_CURSOR_OFF) - cursorstate = -1; - do_cursor = 1; - return 0; -} - -static void ami_set_sprite(const struct amifb_par *par) -{ - copins *copl, *cops; - u_short hs, vs, ve; - u_long pl, ps, pt; - short mx, my; - - cops = copdisplay.list[currentcop][0]; - copl = copdisplay.list[currentcop][1]; - ps = pl = ZTWO_PADDR(dummysprite); - mx = par->crsr.crsr_x - par->crsr.spot_x; - my = par->crsr.crsr_y - par->crsr.spot_y; - if (!(par->vmode & FB_VMODE_YWRAP)) { - mx -= par->xoffset; - my -= par->yoffset; - } - if (!is_blanked && cursorstate > 0 && par->crsr.height > 0 && - mx > -(short)par->crsr.width && mx < par->xres && - my > -(short)par->crsr.height && my < par->yres) { - pl = ZTWO_PADDR(lofsprite); - hs = par->diwstrt_h + (mx << par->clk_shift) - 4; - vs = par->diwstrt_v + (my << par->line_shift); - ve = vs + (par->crsr.height << par->line_shift); - if (par->bplcon0 & BPC0_LACE) { - ps = ZTWO_PADDR(shfsprite); - lofsprite[0] = spr2hw_pos(vs, hs); - shfsprite[0] = spr2hw_pos(vs + 1, hs); - if (mod2(vs)) { - lofsprite[1 << par->crsr.fmode] = spr2hw_ctl(vs, hs, ve); - shfsprite[1 << par->crsr.fmode] = spr2hw_ctl(vs + 1, hs, ve + 1); - pt = pl; pl = ps; ps = pt; - } else { - lofsprite[1 << par->crsr.fmode] = spr2hw_ctl(vs, hs, ve + 1); - shfsprite[1 << par->crsr.fmode] = spr2hw_ctl(vs + 1, hs, ve); - } - } else { - lofsprite[0] = spr2hw_pos(vs, hs) | (IS_AGA && (par->fmode & FMODE_BSCAN2) ? 0x80 : 0); - lofsprite[1 << par->crsr.fmode] = spr2hw_ctl(vs, hs, ve); - } - } - copl[cop_spr0ptrh].w[1] = highw(pl); - copl[cop_spr0ptrl].w[1] = loww(pl); - if (par->bplcon0 & BPC0_LACE) { - cops[cop_spr0ptrh].w[1] = highw(ps); - cops[cop_spr0ptrl].w[1] = loww(ps); - } -} - - - /* - * Initialise the Copper Initialisation List - */ - -static void __init ami_init_copper(void) -{ - copins *cop = copdisplay.init; - u_long p; - int i; - - if (!IS_OCS) { - (cop++)->l = CMOVE(BPC0_COLOR | BPC0_SHRES | BPC0_ECSENA, bplcon0); - (cop++)->l = CMOVE(0x0181, diwstrt); - (cop++)->l = CMOVE(0x0281, diwstop); - (cop++)->l = CMOVE(0x0000, diwhigh); - } else - (cop++)->l = CMOVE(BPC0_COLOR, bplcon0); - p = ZTWO_PADDR(dummysprite); - for (i = 0; i < 8; i++) { - (cop++)->l = CMOVE(0, spr[i].pos); - (cop++)->l = CMOVE(highw(p), sprpt[i]); - (cop++)->l = CMOVE2(loww(p), sprpt[i]); - } - - (cop++)->l = CMOVE(IF_SETCLR | IF_COPER, intreq); - copdisplay.wait = cop; - (cop++)->l = CEND; - (cop++)->l = CMOVE(0, copjmp2); - cop->l = CEND; - - custom.cop1lc = (u_short *)ZTWO_PADDR(copdisplay.init); - custom.copjmp1 = 0; -} - -static void ami_reinit_copper(const struct amifb_par *par) -{ - copdisplay.init[cip_bplcon0].w[1] = ~(BPC0_BPU3 | BPC0_BPU2 | BPC0_BPU1 | BPC0_BPU0) & par->bplcon0; - copdisplay.wait->l = CWAIT(32, par->diwstrt_v - 4); -} - - - /* - * Rebuild the Copper List - * - * We only change the things that are not static - */ - -static void ami_rebuild_copper(const struct amifb_par *par) -{ - copins *copl, *cops; - u_short line, h_end1, h_end2; - short i; - u_long p; - - if (IS_AGA && maxfmode + par->clk_shift == 0) - h_end1 = par->diwstrt_h - 64; - else - h_end1 = par->htotal - 32; - h_end2 = par->ddfstop + 64; - - ami_set_sprite(par); - - copl = copdisplay.rebuild[1]; - p = par->bplpt0; - if (par->vmode & FB_VMODE_YWRAP) { - if ((par->vyres - par->yoffset) != 1 || !mod2(par->diwstrt_v)) { - if (par->yoffset > par->vyres - par->yres) { - for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) { - (copl++)->l = CMOVE(highw(p), bplpt[i]); - (copl++)->l = CMOVE2(loww(p), bplpt[i]); - } - line = par->diwstrt_v + ((par->vyres - par->yoffset) << par->line_shift) - 1; - while (line >= 512) { - (copl++)->l = CWAIT(h_end1, 510); - line -= 512; - } - if (line >= 510 && IS_AGA && maxfmode + par->clk_shift == 0) - (copl++)->l = CWAIT(h_end1, line); - else - (copl++)->l = CWAIT(h_end2, line); - p = par->bplpt0wrap; - } - } else - p = par->bplpt0wrap; - } - for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) { - (copl++)->l = CMOVE(highw(p), bplpt[i]); - (copl++)->l = CMOVE2(loww(p), bplpt[i]); - } - copl->l = CEND; - - if (par->bplcon0 & BPC0_LACE) { - cops = copdisplay.rebuild[0]; - p = par->bplpt0; - if (mod2(par->diwstrt_v)) - p -= par->next_line; - else - p += par->next_line; - if (par->vmode & FB_VMODE_YWRAP) { - if ((par->vyres - par->yoffset) != 1 || mod2(par->diwstrt_v)) { - if (par->yoffset > par->vyres - par->yres + 1) { - for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) { - (cops++)->l = CMOVE(highw(p), bplpt[i]); - (cops++)->l = CMOVE2(loww(p), bplpt[i]); - } - line = par->diwstrt_v + ((par->vyres - par->yoffset) << par->line_shift) - 2; - while (line >= 512) { - (cops++)->l = CWAIT(h_end1, 510); - line -= 512; - } - if (line > 510 && IS_AGA && maxfmode + par->clk_shift == 0) - (cops++)->l = CWAIT(h_end1, line); - else - (cops++)->l = CWAIT(h_end2, line); - p = par->bplpt0wrap; - if (mod2(par->diwstrt_v + par->vyres - - par->yoffset)) - p -= par->next_line; - else - p += par->next_line; - } - } else - p = par->bplpt0wrap - par->next_line; - } - for (i = 0; i < (short)par->bpp; i++, p += par->next_plane) { - (cops++)->l = CMOVE(highw(p), bplpt[i]); - (cops++)->l = CMOVE2(loww(p), bplpt[i]); - } - cops->l = CEND; - } -} - - - /* - * Build the Copper List - */ - -static void ami_build_copper(struct fb_info *info) -{ - struct amifb_par *par = info->par; - copins *copl, *cops; - u_long p; - - currentcop = 1 - currentcop; - - copl = copdisplay.list[currentcop][1]; - - (copl++)->l = CWAIT(0, 10); - (copl++)->l = CMOVE(par->bplcon0, bplcon0); - (copl++)->l = CMOVE(0, sprpt[0]); - (copl++)->l = CMOVE2(0, sprpt[0]); - - if (par->bplcon0 & BPC0_LACE) { - cops = copdisplay.list[currentcop][0]; - - (cops++)->l = CWAIT(0, 10); - (cops++)->l = CMOVE(par->bplcon0, bplcon0); - (cops++)->l = CMOVE(0, sprpt[0]); - (cops++)->l = CMOVE2(0, sprpt[0]); - - (copl++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v + 1), diwstrt); - (copl++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v + 1), diwstop); - (cops++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v), diwstrt); - (cops++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v), diwstop); - if (!IS_OCS) { - (copl++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v + 1, - par->diwstop_h, par->diwstop_v + 1), diwhigh); - (cops++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v, - par->diwstop_h, par->diwstop_v), diwhigh); -#if 0 - if (par->beamcon0 & BMC0_VARBEAMEN) { - (copl++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal); - (copl++)->l = CMOVE(vbstrt2hw(par->vbstrt + 1), vbstrt); - (copl++)->l = CMOVE(vbstop2hw(par->vbstop + 1), vbstop); - (cops++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal); - (cops++)->l = CMOVE(vbstrt2hw(par->vbstrt), vbstrt); - (cops++)->l = CMOVE(vbstop2hw(par->vbstop), vbstop); - } -#endif - } - p = ZTWO_PADDR(copdisplay.list[currentcop][0]); - (copl++)->l = CMOVE(highw(p), cop2lc); - (copl++)->l = CMOVE2(loww(p), cop2lc); - p = ZTWO_PADDR(copdisplay.list[currentcop][1]); - (cops++)->l = CMOVE(highw(p), cop2lc); - (cops++)->l = CMOVE2(loww(p), cop2lc); - copdisplay.rebuild[0] = cops; - } else { - (copl++)->l = CMOVE(diwstrt2hw(par->diwstrt_h, par->diwstrt_v), diwstrt); - (copl++)->l = CMOVE(diwstop2hw(par->diwstop_h, par->diwstop_v), diwstop); - if (!IS_OCS) { - (copl++)->l = CMOVE(diwhigh2hw(par->diwstrt_h, par->diwstrt_v, - par->diwstop_h, par->diwstop_v), diwhigh); -#if 0 - if (par->beamcon0 & BMC0_VARBEAMEN) { - (copl++)->l = CMOVE(vtotal2hw(par->vtotal), vtotal); - (copl++)->l = CMOVE(vbstrt2hw(par->vbstrt), vbstrt); - (copl++)->l = CMOVE(vbstop2hw(par->vbstop), vbstop); - } -#endif - } - } - copdisplay.rebuild[1] = copl; - - ami_update_par(info); - ami_rebuild_copper(info->par); -} - - -static void __init amifb_setup_mcap(char *spec) -{ - char *p; - int vmin, vmax, hmin, hmax; - - /* Format for monitor capabilities is: ;;; - * vertical freq. in Hz - * horizontal freq. in kHz - */ - - if (!(p = strsep(&spec, ";")) || !*p) - return; - vmin = simple_strtoul(p, NULL, 10); - if (vmin <= 0) - return; - if (!(p = strsep(&spec, ";")) || !*p) - return; - vmax = simple_strtoul(p, NULL, 10); - if (vmax <= 0 || vmax <= vmin) - return; - if (!(p = strsep(&spec, ";")) || !*p) - return; - hmin = 1000 * simple_strtoul(p, NULL, 10); - if (hmin <= 0) - return; - if (!(p = strsep(&spec, "")) || !*p) - return; - hmax = 1000 * simple_strtoul(p, NULL, 10); - if (hmax <= 0 || hmax <= hmin) - return; - - amifb_hfmin = hmin; - amifb_hfmax = hmax; - amifb_vfmin = vmin; - amifb_vfmax = vmax; -} - -static int __init amifb_setup(char *options) -{ - char *this_opt; - - if (!options || !*options) - return 0; - - while ((this_opt = strsep(&options, ",")) != NULL) { - if (!*this_opt) - continue; - if (!strcmp(this_opt, "inverse")) { - fb_invert_cmaps(); - } else if (!strcmp(this_opt, "ilbm")) - amifb_ilbm = 1; - else if (!strncmp(this_opt, "monitorcap:", 11)) - amifb_setup_mcap(this_opt + 11); - else if (!strncmp(this_opt, "fstart:", 7)) - min_fstrt = simple_strtoul(this_opt + 7, NULL, 0); - else - mode_option = this_opt; - } - - if (min_fstrt < 48) - min_fstrt = 48; - - return 0; -} - - -static int amifb_check_var(struct fb_var_screeninfo *var, - struct fb_info *info) -{ - int err; - struct amifb_par par; - - /* Validate wanted screen parameters */ - err = ami_decode_var(var, &par, info); - if (err) - return err; - - /* Encode (possibly rounded) screen parameters */ - ami_encode_var(var, &par); - return 0; -} - - -static int amifb_set_par(struct fb_info *info) -{ - struct amifb_par *par = info->par; - int error; - - do_vmode_pan = 0; - do_vmode_full = 0; - - /* Decode wanted screen parameters */ - error = ami_decode_var(&info->var, par, info); - if (error) - return error; - - /* Set new videomode */ - ami_build_copper(info); - - /* Set VBlank trigger */ - do_vmode_full = 1; - - /* Update fix for new screen parameters */ - if (par->bpp == 1) { - info->fix.type = FB_TYPE_PACKED_PIXELS; - info->fix.type_aux = 0; - } else if (amifb_ilbm) { - info->fix.type = FB_TYPE_INTERLEAVED_PLANES; - info->fix.type_aux = par->next_line; - } else { - info->fix.type = FB_TYPE_PLANES; - info->fix.type_aux = 0; - } - info->fix.line_length = div8(upx(16 << maxfmode, par->vxres)); - - if (par->vmode & FB_VMODE_YWRAP) { - info->fix.ywrapstep = 1; - info->fix.xpanstep = 0; - info->fix.ypanstep = 0; - info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YWRAP | - FBINFO_READS_FAST; /* override SCROLL_REDRAW */ - } else { - info->fix.ywrapstep = 0; - if (par->vmode & FB_VMODE_SMOOTH_XPAN) - info->fix.xpanstep = 1; - else - info->fix.xpanstep = 16 << maxfmode; - info->fix.ypanstep = 1; - info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; - } - return 0; -} - - - /* - * Set a single color register. The values supplied are already - * rounded down to the hardware's capabilities (according to the - * entries in the var structure). Return != 0 for invalid regno. - */ - -static int amifb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, - u_int transp, struct fb_info *info) -{ - const struct amifb_par *par = info->par; - - if (IS_AGA) { - if (regno > 255) - return 1; - } else if (par->bplcon0 & BPC0_SHRES) { - if (regno > 3) - return 1; - } else { - if (regno > 31) - return 1; - } - red >>= 8; - green >>= 8; - blue >>= 8; - if (!regno) { - red0 = red; - green0 = green; - blue0 = blue; - } - - /* - * Update the corresponding Hardware Color Register, unless it's Color - * Register 0 and the screen is blanked. - * - * VBlank is switched off to protect bplcon3 or ecs_palette[] from - * being changed by ami_do_blank() during the VBlank. - */ - - if (regno || !is_blanked) { -#if defined(CONFIG_FB_AMIGA_AGA) - if (IS_AGA) { - u_short bplcon3 = par->bplcon3; - VBlankOff(); - custom.bplcon3 = bplcon3 | (regno << 8 & 0xe000); - custom.color[regno & 31] = rgb2hw8_high(red, green, - blue); - custom.bplcon3 = bplcon3 | (regno << 8 & 0xe000) | - BPC3_LOCT; - custom.color[regno & 31] = rgb2hw8_low(red, green, - blue); - custom.bplcon3 = bplcon3; - VBlankOn(); - } else -#endif -#if defined(CONFIG_FB_AMIGA_ECS) - if (par->bplcon0 & BPC0_SHRES) { - u_short color, mask; - int i; - - mask = 0x3333; - color = rgb2hw2(red, green, blue); - VBlankOff(); - for (i = regno + 12; i >= (int)regno; i -= 4) - custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color; - mask <<= 2; color >>= 2; - regno = down16(regno) + mul4(mod4(regno)); - for (i = regno + 3; i >= (int)regno; i--) - custom.color[i] = ecs_palette[i] = (ecs_palette[i] & mask) | color; - VBlankOn(); - } else -#endif - custom.color[regno] = rgb2hw4(red, green, blue); - } - return 0; -} - - - /* - * Blank the display. - */ - -static int amifb_blank(int blank, struct fb_info *info) -{ - do_blank = blank ? blank : -1; - - return 0; -} - - - /* - * Pan or Wrap the Display - * - * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag - */ - -static int amifb_pan_display(struct fb_var_screeninfo *var, - struct fb_info *info) -{ - if (var->vmode & FB_VMODE_YWRAP) { - if (var->yoffset < 0 || - var->yoffset >= info->var.yres_virtual || var->xoffset) - return -EINVAL; - } else { - /* - * TODO: There will be problems when xpan!=1, so some columns - * on the right side will never be seen - */ - if (var->xoffset + info->var.xres > - upx(16 << maxfmode, info->var.xres_virtual) || - var->yoffset + info->var.yres > info->var.yres_virtual) - return -EINVAL; - } - ami_pan_var(var, info); - info->var.xoffset = var->xoffset; - info->var.yoffset = var->yoffset; - if (var->vmode & FB_VMODE_YWRAP) - info->var.vmode |= FB_VMODE_YWRAP; - else - info->var.vmode &= ~FB_VMODE_YWRAP; - return 0; -} - - -#if BITS_PER_LONG == 32 -#define BYTES_PER_LONG 4 -#define SHIFT_PER_LONG 5 -#elif BITS_PER_LONG == 64 -#define BYTES_PER_LONG 8 -#define SHIFT_PER_LONG 6 -#else -#define Please update me -#endif - - - /* - * Compose two values, using a bitmask as decision value - * This is equivalent to (a & mask) | (b & ~mask) - */ - -static inline unsigned long comp(unsigned long a, unsigned long b, - unsigned long mask) -{ - return ((a ^ b) & mask) ^ b; -} - - -static inline unsigned long xor(unsigned long a, unsigned long b, - unsigned long mask) -{ - return (a & mask) ^ b; -} - - - /* - * Unaligned forward bit copy using 32-bit or 64-bit memory accesses - */ - -static void bitcpy(unsigned long *dst, int dst_idx, const unsigned long *src, - int src_idx, u32 n) -{ - unsigned long first, last; - int shift = dst_idx - src_idx, left, right; - unsigned long d0, d1; - int m; - - if (!n) - return; - - shift = dst_idx - src_idx; - first = ~0UL >> dst_idx; - last = ~(~0UL >> ((dst_idx + n) % BITS_PER_LONG)); - - if (!shift) { - // Same alignment for source and dest - - if (dst_idx + n <= BITS_PER_LONG) { - // Single word - if (last) - first &= last; - *dst = comp(*src, *dst, first); - } else { - // Multiple destination words - // Leading bits - if (first) { - *dst = comp(*src, *dst, first); - dst++; - src++; - n -= BITS_PER_LONG - dst_idx; - } - - // Main chunk - n /= BITS_PER_LONG; - while (n >= 8) { - *dst++ = *src++; - *dst++ = *src++; - *dst++ = *src++; - *dst++ = *src++; - *dst++ = *src++; - *dst++ = *src++; - *dst++ = *src++; - *dst++ = *src++; - n -= 8; - } - while (n--) - *dst++ = *src++; - - // Trailing bits - if (last) - *dst = comp(*src, *dst, last); - } - } else { - // Different alignment for source and dest - - right = shift & (BITS_PER_LONG - 1); - left = -shift & (BITS_PER_LONG - 1); - - if (dst_idx + n <= BITS_PER_LONG) { - // Single destination word - if (last) - first &= last; - if (shift > 0) { - // Single source word - *dst = comp(*src >> right, *dst, first); - } else if (src_idx + n <= BITS_PER_LONG) { - // Single source word - *dst = comp(*src << left, *dst, first); - } else { - // 2 source words - d0 = *src++; - d1 = *src; - *dst = comp(d0 << left | d1 >> right, *dst, - first); - } - } else { - // Multiple destination words - d0 = *src++; - // Leading bits - if (shift > 0) { - // Single source word - *dst = comp(d0 >> right, *dst, first); - dst++; - n -= BITS_PER_LONG - dst_idx; - } else { - // 2 source words - d1 = *src++; - *dst = comp(d0 << left | d1 >> right, *dst, - first); - d0 = d1; - dst++; - n -= BITS_PER_LONG - dst_idx; - } - - // Main chunk - m = n % BITS_PER_LONG; - n /= BITS_PER_LONG; - while (n >= 4) { - d1 = *src++; - *dst++ = d0 << left | d1 >> right; - d0 = d1; - d1 = *src++; - *dst++ = d0 << left | d1 >> right; - d0 = d1; - d1 = *src++; - *dst++ = d0 << left | d1 >> right; - d0 = d1; - d1 = *src++; - *dst++ = d0 << left | d1 >> right; - d0 = d1; - n -= 4; - } - while (n--) { - d1 = *src++; - *dst++ = d0 << left | d1 >> right; - d0 = d1; - } - - // Trailing bits - if (last) { - if (m <= right) { - // Single source word - *dst = comp(d0 << left, *dst, last); - } else { - // 2 source words - d1 = *src; - *dst = comp(d0 << left | d1 >> right, - *dst, last); - } - } - } - } -} - - - /* - * Unaligned reverse bit copy using 32-bit or 64-bit memory accesses - */ - -static void bitcpy_rev(unsigned long *dst, int dst_idx, - const unsigned long *src, int src_idx, u32 n) -{ - unsigned long first, last; - int shift = dst_idx - src_idx, left, right; - unsigned long d0, d1; - int m; - - if (!n) - return; - - dst += (n - 1) / BITS_PER_LONG; - src += (n - 1) / BITS_PER_LONG; - if ((n - 1) % BITS_PER_LONG) { - dst_idx += (n - 1) % BITS_PER_LONG; - dst += dst_idx >> SHIFT_PER_LONG; - dst_idx &= BITS_PER_LONG - 1; - src_idx += (n - 1) % BITS_PER_LONG; - src += src_idx >> SHIFT_PER_LONG; - src_idx &= BITS_PER_LONG - 1; - } - - shift = dst_idx - src_idx; - first = ~0UL << (BITS_PER_LONG - 1 - dst_idx); - last = ~(~0UL << (BITS_PER_LONG - 1 - ((dst_idx - n) % BITS_PER_LONG))); - - if (!shift) { - // Same alignment for source and dest - - if ((unsigned long)dst_idx + 1 >= n) { - // Single word - if (last) - first &= last; - *dst = comp(*src, *dst, first); - } else { - // Multiple destination words - // Leading bits - if (first) { - *dst = comp(*src, *dst, first); - dst--; - src--; - n -= dst_idx + 1; - } - - // Main chunk - n /= BITS_PER_LONG; - while (n >= 8) { - *dst-- = *src--; - *dst-- = *src--; - *dst-- = *src--; - *dst-- = *src--; - *dst-- = *src--; - *dst-- = *src--; - *dst-- = *src--; - *dst-- = *src--; - n -= 8; - } - while (n--) - *dst-- = *src--; - - // Trailing bits - if (last) - *dst = comp(*src, *dst, last); - } - } else { - // Different alignment for source and dest - - right = shift & (BITS_PER_LONG - 1); - left = -shift & (BITS_PER_LONG - 1); - - if ((unsigned long)dst_idx + 1 >= n) { - // Single destination word - if (last) - first &= last; - if (shift < 0) { - // Single source word - *dst = comp(*src << left, *dst, first); - } else if (1 + (unsigned long)src_idx >= n) { - // Single source word - *dst = comp(*src >> right, *dst, first); - } else { - // 2 source words - d0 = *src--; - d1 = *src; - *dst = comp(d0 >> right | d1 << left, *dst, - first); - } - } else { - // Multiple destination words - d0 = *src--; - // Leading bits - if (shift < 0) { - // Single source word - *dst = comp(d0 << left, *dst, first); - dst--; - n -= dst_idx + 1; - } else { - // 2 source words - d1 = *src--; - *dst = comp(d0 >> right | d1 << left, *dst, - first); - d0 = d1; - dst--; - n -= dst_idx + 1; - } - - // Main chunk - m = n % BITS_PER_LONG; - n /= BITS_PER_LONG; - while (n >= 4) { - d1 = *src--; - *dst-- = d0 >> right | d1 << left; - d0 = d1; - d1 = *src--; - *dst-- = d0 >> right | d1 << left; - d0 = d1; - d1 = *src--; - *dst-- = d0 >> right | d1 << left; - d0 = d1; - d1 = *src--; - *dst-- = d0 >> right | d1 << left; - d0 = d1; - n -= 4; - } - while (n--) { - d1 = *src--; - *dst-- = d0 >> right | d1 << left; - d0 = d1; - } - - // Trailing bits - if (last) { - if (m <= left) { - // Single source word - *dst = comp(d0 >> right, *dst, last); - } else { - // 2 source words - d1 = *src; - *dst = comp(d0 >> right | d1 << left, - *dst, last); - } - } - } - } -} - - - /* - * Unaligned forward inverting bit copy using 32-bit or 64-bit memory - * accesses - */ - -static void bitcpy_not(unsigned long *dst, int dst_idx, - const unsigned long *src, int src_idx, u32 n) -{ - unsigned long first, last; - int shift = dst_idx - src_idx, left, right; - unsigned long d0, d1; - int m; - - if (!n) - return; - - shift = dst_idx - src_idx; - first = ~0UL >> dst_idx; - last = ~(~0UL >> ((dst_idx + n) % BITS_PER_LONG)); - - if (!shift) { - // Same alignment for source and dest - - if (dst_idx + n <= BITS_PER_LONG) { - // Single word - if (last) - first &= last; - *dst = comp(~*src, *dst, first); - } else { - // Multiple destination words - // Leading bits - if (first) { - *dst = comp(~*src, *dst, first); - dst++; - src++; - n -= BITS_PER_LONG - dst_idx; - } - - // Main chunk - n /= BITS_PER_LONG; - while (n >= 8) { - *dst++ = ~*src++; - *dst++ = ~*src++; - *dst++ = ~*src++; - *dst++ = ~*src++; - *dst++ = ~*src++; - *dst++ = ~*src++; - *dst++ = ~*src++; - *dst++ = ~*src++; - n -= 8; - } - while (n--) - *dst++ = ~*src++; - - // Trailing bits - if (last) - *dst = comp(~*src, *dst, last); - } - } else { - // Different alignment for source and dest - - right = shift & (BITS_PER_LONG - 1); - left = -shift & (BITS_PER_LONG - 1); - - if (dst_idx + n <= BITS_PER_LONG) { - // Single destination word - if (last) - first &= last; - if (shift > 0) { - // Single source word - *dst = comp(~*src >> right, *dst, first); - } else if (src_idx + n <= BITS_PER_LONG) { - // Single source word - *dst = comp(~*src << left, *dst, first); - } else { - // 2 source words - d0 = ~*src++; - d1 = ~*src; - *dst = comp(d0 << left | d1 >> right, *dst, - first); - } - } else { - // Multiple destination words - d0 = ~*src++; - // Leading bits - if (shift > 0) { - // Single source word - *dst = comp(d0 >> right, *dst, first); - dst++; - n -= BITS_PER_LONG - dst_idx; - } else { - // 2 source words - d1 = ~*src++; - *dst = comp(d0 << left | d1 >> right, *dst, - first); - d0 = d1; - dst++; - n -= BITS_PER_LONG - dst_idx; - } - - // Main chunk - m = n % BITS_PER_LONG; - n /= BITS_PER_LONG; - while (n >= 4) { - d1 = ~*src++; - *dst++ = d0 << left | d1 >> right; - d0 = d1; - d1 = ~*src++; - *dst++ = d0 << left | d1 >> right; - d0 = d1; - d1 = ~*src++; - *dst++ = d0 << left | d1 >> right; - d0 = d1; - d1 = ~*src++; - *dst++ = d0 << left | d1 >> right; - d0 = d1; - n -= 4; - } - while (n--) { - d1 = ~*src++; - *dst++ = d0 << left | d1 >> right; - d0 = d1; - } - - // Trailing bits - if (last) { - if (m <= right) { - // Single source word - *dst = comp(d0 << left, *dst, last); - } else { - // 2 source words - d1 = ~*src; - *dst = comp(d0 << left | d1 >> right, - *dst, last); - } - } - } - } -} - - - /* - * Unaligned 32-bit pattern fill using 32/64-bit memory accesses - */ - -static void bitfill32(unsigned long *dst, int dst_idx, u32 pat, u32 n) -{ - unsigned long val = pat; - unsigned long first, last; - - if (!n) - return; - -#if BITS_PER_LONG == 64 - val |= val << 32; -#endif - - first = ~0UL >> dst_idx; - last = ~(~0UL >> ((dst_idx + n) % BITS_PER_LONG)); - - if (dst_idx + n <= BITS_PER_LONG) { - // Single word - if (last) - first &= last; - *dst = comp(val, *dst, first); - } else { - // Multiple destination words - // Leading bits - if (first) { - *dst = comp(val, *dst, first); - dst++; - n -= BITS_PER_LONG - dst_idx; - } - - // Main chunk - n /= BITS_PER_LONG; - while (n >= 8) { - *dst++ = val; - *dst++ = val; - *dst++ = val; - *dst++ = val; - *dst++ = val; - *dst++ = val; - *dst++ = val; - *dst++ = val; - n -= 8; - } - while (n--) - *dst++ = val; - - // Trailing bits - if (last) - *dst = comp(val, *dst, last); - } -} - - - /* - * Unaligned 32-bit pattern xor using 32/64-bit memory accesses - */ - -static void bitxor32(unsigned long *dst, int dst_idx, u32 pat, u32 n) -{ - unsigned long val = pat; - unsigned long first, last; - - if (!n) - return; - -#if BITS_PER_LONG == 64 - val |= val << 32; -#endif - - first = ~0UL >> dst_idx; - last = ~(~0UL >> ((dst_idx + n) % BITS_PER_LONG)); - - if (dst_idx + n <= BITS_PER_LONG) { - // Single word - if (last) - first &= last; - *dst = xor(val, *dst, first); - } else { - // Multiple destination words - // Leading bits - if (first) { - *dst = xor(val, *dst, first); - dst++; - n -= BITS_PER_LONG - dst_idx; - } - - // Main chunk - n /= BITS_PER_LONG; - while (n >= 4) { - *dst++ ^= val; - *dst++ ^= val; - *dst++ ^= val; - *dst++ ^= val; - n -= 4; - } - while (n--) - *dst++ ^= val; - - // Trailing bits - if (last) - *dst = xor(val, *dst, last); - } -} - -static inline void fill_one_line(int bpp, unsigned long next_plane, - unsigned long *dst, int dst_idx, u32 n, - u32 color) -{ - while (1) { - dst += dst_idx >> SHIFT_PER_LONG; - dst_idx &= (BITS_PER_LONG - 1); - bitfill32(dst, dst_idx, color & 1 ? ~0 : 0, n); - if (!--bpp) - break; - color >>= 1; - dst_idx += next_plane * 8; - } -} - -static inline void xor_one_line(int bpp, unsigned long next_plane, - unsigned long *dst, int dst_idx, u32 n, - u32 color) -{ - while (color) { - dst += dst_idx >> SHIFT_PER_LONG; - dst_idx &= (BITS_PER_LONG - 1); - bitxor32(dst, dst_idx, color & 1 ? ~0 : 0, n); - if (!--bpp) - break; - color >>= 1; - dst_idx += next_plane * 8; - } -} - - -static void amifb_fillrect(struct fb_info *info, - const struct fb_fillrect *rect) -{ - struct amifb_par *par = info->par; - int dst_idx, x2, y2; - unsigned long *dst; - u32 width, height; - - if (!rect->width || !rect->height) - return; - - /* - * We could use hardware clipping but on many cards you get around - * hardware clipping by writing to framebuffer directly. - * */ - x2 = rect->dx + rect->width; - y2 = rect->dy + rect->height; - x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual; - y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual; - width = x2 - rect->dx; - height = y2 - rect->dy; - - dst = (unsigned long *) - ((unsigned long)info->screen_base & ~(BYTES_PER_LONG - 1)); - dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG - 1)) * 8; - dst_idx += rect->dy * par->next_line * 8 + rect->dx; - while (height--) { - switch (rect->rop) { - case ROP_COPY: - fill_one_line(info->var.bits_per_pixel, - par->next_plane, dst, dst_idx, width, - rect->color); - break; - - case ROP_XOR: - xor_one_line(info->var.bits_per_pixel, par->next_plane, - dst, dst_idx, width, rect->color); - break; - } - dst_idx += par->next_line * 8; - } -} - -static inline void copy_one_line(int bpp, unsigned long next_plane, - unsigned long *dst, int dst_idx, - unsigned long *src, int src_idx, u32 n) -{ - while (1) { - dst += dst_idx >> SHIFT_PER_LONG; - dst_idx &= (BITS_PER_LONG - 1); - src += src_idx >> SHIFT_PER_LONG; - src_idx &= (BITS_PER_LONG - 1); - bitcpy(dst, dst_idx, src, src_idx, n); - if (!--bpp) - break; - dst_idx += next_plane * 8; - src_idx += next_plane * 8; - } -} - -static inline void copy_one_line_rev(int bpp, unsigned long next_plane, - unsigned long *dst, int dst_idx, - unsigned long *src, int src_idx, u32 n) -{ - while (1) { - dst += dst_idx >> SHIFT_PER_LONG; - dst_idx &= (BITS_PER_LONG - 1); - src += src_idx >> SHIFT_PER_LONG; - src_idx &= (BITS_PER_LONG - 1); - bitcpy_rev(dst, dst_idx, src, src_idx, n); - if (!--bpp) - break; - dst_idx += next_plane * 8; - src_idx += next_plane * 8; - } -} - - -static void amifb_copyarea(struct fb_info *info, - const struct fb_copyarea *area) -{ - struct amifb_par *par = info->par; - int x2, y2; - u32 dx, dy, sx, sy, width, height; - unsigned long *dst, *src; - int dst_idx, src_idx; - int rev_copy = 0; - - /* clip the destination */ - x2 = area->dx + area->width; - y2 = area->dy + area->height; - dx = area->dx > 0 ? area->dx : 0; - dy = area->dy > 0 ? area->dy : 0; - x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual; - y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual; - width = x2 - dx; - height = y2 - dy; - - if (area->sx + dx < area->dx || area->sy + dy < area->dy) - return; - - /* update sx,sy */ - sx = area->sx + (dx - area->dx); - sy = area->sy + (dy - area->dy); - - /* the source must be completely inside the virtual screen */ - if (sx + width > info->var.xres_virtual || - sy + height > info->var.yres_virtual) - return; - - if (dy > sy || (dy == sy && dx > sx)) { - dy += height; - sy += height; - rev_copy = 1; - } - dst = (unsigned long *) - ((unsigned long)info->screen_base & ~(BYTES_PER_LONG - 1)); - src = dst; - dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG - 1)) * 8; - src_idx = dst_idx; - dst_idx += dy * par->next_line * 8 + dx; - src_idx += sy * par->next_line * 8 + sx; - if (rev_copy) { - while (height--) { - dst_idx -= par->next_line * 8; - src_idx -= par->next_line * 8; - copy_one_line_rev(info->var.bits_per_pixel, - par->next_plane, dst, dst_idx, src, - src_idx, width); - } - } else { - while (height--) { - copy_one_line(info->var.bits_per_pixel, - par->next_plane, dst, dst_idx, src, - src_idx, width); - dst_idx += par->next_line * 8; - src_idx += par->next_line * 8; - } - } -} - - -static inline void expand_one_line(int bpp, unsigned long next_plane, - unsigned long *dst, int dst_idx, u32 n, - const u8 *data, u32 bgcolor, u32 fgcolor) -{ - const unsigned long *src; - int src_idx; - - while (1) { - dst += dst_idx >> SHIFT_PER_LONG; - dst_idx &= (BITS_PER_LONG - 1); - if ((bgcolor ^ fgcolor) & 1) { - src = (unsigned long *) - ((unsigned long)data & ~(BYTES_PER_LONG - 1)); - src_idx = ((unsigned long)data & (BYTES_PER_LONG - 1)) * 8; - if (fgcolor & 1) - bitcpy(dst, dst_idx, src, src_idx, n); - else - bitcpy_not(dst, dst_idx, src, src_idx, n); - /* set or clear */ - } else - bitfill32(dst, dst_idx, fgcolor & 1 ? ~0 : 0, n); - if (!--bpp) - break; - bgcolor >>= 1; - fgcolor >>= 1; - dst_idx += next_plane * 8; - } -} - - -static void amifb_imageblit(struct fb_info *info, const struct fb_image *image) -{ - struct amifb_par *par = info->par; - int x2, y2; - unsigned long *dst; - int dst_idx; - const char *src; - u32 dx, dy, width, height, pitch; - - /* - * We could use hardware clipping but on many cards you get around - * hardware clipping by writing to framebuffer directly like we are - * doing here. - */ - x2 = image->dx + image->width; - y2 = image->dy + image->height; - dx = image->dx; - dy = image->dy; - x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual; - y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual; - width = x2 - dx; - height = y2 - dy; - - if (image->depth == 1) { - dst = (unsigned long *) - ((unsigned long)info->screen_base & ~(BYTES_PER_LONG - 1)); - dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG - 1)) * 8; - dst_idx += dy * par->next_line * 8 + dx; - src = image->data; - pitch = (image->width + 7) / 8; - while (height--) { - expand_one_line(info->var.bits_per_pixel, - par->next_plane, dst, dst_idx, width, - src, image->bg_color, - image->fg_color); - dst_idx += par->next_line * 8; - src += pitch; - } - } else { - c2p_planar(info->screen_base, image->data, dx, dy, width, - height, par->next_line, par->next_plane, - image->width, info->var.bits_per_pixel); - } -} - - - /* - * Amiga Frame Buffer Specific ioctls - */ - -static int amifb_ioctl(struct fb_info *info, - unsigned int cmd, unsigned long arg) -{ - union { - struct fb_fix_cursorinfo fix; - struct fb_var_cursorinfo var; - struct fb_cursorstate state; - } crsr; - void __user *argp = (void __user *)arg; - int i; - - switch (cmd) { - case FBIOGET_FCURSORINFO: - i = ami_get_fix_cursorinfo(&crsr.fix, info->par); - if (i) - return i; - return copy_to_user(argp, &crsr.fix, - sizeof(crsr.fix)) ? -EFAULT : 0; - - case FBIOGET_VCURSORINFO: - i = ami_get_var_cursorinfo(&crsr.var, - ((struct fb_var_cursorinfo __user *)arg)->data, - info->par); - if (i) - return i; - return copy_to_user(argp, &crsr.var, - sizeof(crsr.var)) ? -EFAULT : 0; - - case FBIOPUT_VCURSORINFO: - if (copy_from_user(&crsr.var, argp, sizeof(crsr.var))) - return -EFAULT; - return ami_set_var_cursorinfo(&crsr.var, - ((struct fb_var_cursorinfo __user *)arg)->data, - info->par); - - case FBIOGET_CURSORSTATE: - i = ami_get_cursorstate(&crsr.state, info->par); - if (i) - return i; - return copy_to_user(argp, &crsr.state, - sizeof(crsr.state)) ? -EFAULT : 0; - - case FBIOPUT_CURSORSTATE: - if (copy_from_user(&crsr.state, argp, sizeof(crsr.state))) - return -EFAULT; - return ami_set_cursorstate(&crsr.state, info->par); - } - return -EINVAL; -} - - - /* - * Flash the cursor (called by VBlank interrupt) - */ - -static int flash_cursor(void) -{ - static int cursorcount = 1; - - if (cursormode == FB_CURSOR_FLASH) { - if (!--cursorcount) { - cursorstate = -cursorstate; - cursorcount = cursorrate; - if (!is_blanked) - return 1; - } - } - return 0; -} - - /* - * VBlank Display Interrupt - */ - -static irqreturn_t amifb_interrupt(int irq, void *dev_id) -{ - struct amifb_par *par = dev_id; - - if (do_vmode_pan || do_vmode_full) - ami_update_display(par); - - if (do_vmode_full) - ami_init_display(par); - - if (do_vmode_pan) { - flash_cursor(); - ami_rebuild_copper(par); - do_cursor = do_vmode_pan = 0; - } else if (do_cursor) { - flash_cursor(); - ami_set_sprite(par); - do_cursor = 0; - } else { - if (flash_cursor()) - ami_set_sprite(par); - } - - if (do_blank) { - ami_do_blank(par); - do_blank = 0; - } - - if (do_vmode_full) { - ami_reinit_copper(par); - do_vmode_full = 0; - } - return IRQ_HANDLED; -} - - -static struct fb_ops amifb_ops = { - .owner = THIS_MODULE, - .fb_check_var = amifb_check_var, - .fb_set_par = amifb_set_par, - .fb_setcolreg = amifb_setcolreg, - .fb_blank = amifb_blank, - .fb_pan_display = amifb_pan_display, - .fb_fillrect = amifb_fillrect, - .fb_copyarea = amifb_copyarea, - .fb_imageblit = amifb_imageblit, - .fb_ioctl = amifb_ioctl, -}; - - - /* - * Allocate, Clear and Align a Block of Chip Memory - */ - -static void *aligned_chipptr; - -static inline u_long __init chipalloc(u_long size) -{ - aligned_chipptr = amiga_chip_alloc(size, "amifb [RAM]"); - if (!aligned_chipptr) { - pr_err("amifb: No Chip RAM for frame buffer"); - return 0; - } - memset(aligned_chipptr, 0, size); - return (u_long)aligned_chipptr; -} - -static inline void chipfree(void) -{ - if (aligned_chipptr) - amiga_chip_free(aligned_chipptr); -} - - - /* - * Initialisation - */ - -static int __init amifb_probe(struct platform_device *pdev) -{ - struct fb_info *info; - int tag, i, err = 0; - u_long chipptr; - u_int defmode; - -#ifndef MODULE - char *option = NULL; - - if (fb_get_options("amifb", &option)) { - amifb_video_off(); - return -ENODEV; - } - amifb_setup(option); -#endif - custom.dmacon = DMAF_ALL | DMAF_MASTER; - - info = framebuffer_alloc(sizeof(struct amifb_par), &pdev->dev); - if (!info) { - dev_err(&pdev->dev, "framebuffer_alloc failed\n"); - return -ENOMEM; - } - - strcpy(info->fix.id, "Amiga "); - info->fix.visual = FB_VISUAL_PSEUDOCOLOR; - info->fix.accel = FB_ACCEL_AMIGABLITT; - - switch (amiga_chipset) { -#ifdef CONFIG_FB_AMIGA_OCS - case CS_OCS: - strcat(info->fix.id, "OCS"); -default_chipset: - chipset = TAG_OCS; - maxdepth[TAG_SHRES] = 0; /* OCS means no SHRES */ - maxdepth[TAG_HIRES] = 4; - maxdepth[TAG_LORES] = 6; - maxfmode = TAG_FMODE_1; - defmode = amiga_vblank == 50 ? DEFMODE_PAL : DEFMODE_NTSC; - info->fix.smem_len = VIDEOMEMSIZE_OCS; - break; -#endif /* CONFIG_FB_AMIGA_OCS */ - -#ifdef CONFIG_FB_AMIGA_ECS - case CS_ECS: - strcat(info->fix.id, "ECS"); - chipset = TAG_ECS; - maxdepth[TAG_SHRES] = 2; - maxdepth[TAG_HIRES] = 4; - maxdepth[TAG_LORES] = 6; - maxfmode = TAG_FMODE_1; - if (AMIGAHW_PRESENT(AMBER_FF)) - defmode = amiga_vblank == 50 ? DEFMODE_AMBER_PAL - : DEFMODE_AMBER_NTSC; - else - defmode = amiga_vblank == 50 ? DEFMODE_PAL - : DEFMODE_NTSC; - if (amiga_chip_avail() - CHIPRAM_SAFETY_LIMIT > - VIDEOMEMSIZE_ECS_2M) - info->fix.smem_len = VIDEOMEMSIZE_ECS_2M; - else - info->fix.smem_len = VIDEOMEMSIZE_ECS_1M; - break; -#endif /* CONFIG_FB_AMIGA_ECS */ - -#ifdef CONFIG_FB_AMIGA_AGA - case CS_AGA: - strcat(info->fix.id, "AGA"); - chipset = TAG_AGA; - maxdepth[TAG_SHRES] = 8; - maxdepth[TAG_HIRES] = 8; - maxdepth[TAG_LORES] = 8; - maxfmode = TAG_FMODE_4; - defmode = DEFMODE_AGA; - if (amiga_chip_avail() - CHIPRAM_SAFETY_LIMIT > - VIDEOMEMSIZE_AGA_2M) - info->fix.smem_len = VIDEOMEMSIZE_AGA_2M; - else - info->fix.smem_len = VIDEOMEMSIZE_AGA_1M; - break; -#endif /* CONFIG_FB_AMIGA_AGA */ - - default: -#ifdef CONFIG_FB_AMIGA_OCS - printk("Unknown graphics chipset, defaulting to OCS\n"); - strcat(info->fix.id, "Unknown"); - goto default_chipset; -#else /* CONFIG_FB_AMIGA_OCS */ - err = -ENODEV; - goto release; -#endif /* CONFIG_FB_AMIGA_OCS */ - break; - } - - /* - * Calculate the Pixel Clock Values for this Machine - */ - - { - u_long tmp = DIVUL(200000000000ULL, amiga_eclock); - - pixclock[TAG_SHRES] = (tmp + 4) / 8; /* SHRES: 35 ns / 28 MHz */ - pixclock[TAG_HIRES] = (tmp + 2) / 4; /* HIRES: 70 ns / 14 MHz */ - pixclock[TAG_LORES] = (tmp + 1) / 2; /* LORES: 140 ns / 7 MHz */ - } - - /* - * Replace the Tag Values with the Real Pixel Clock Values - */ - - for (i = 0; i < NUM_TOTAL_MODES; i++) { - struct fb_videomode *mode = &ami_modedb[i]; - tag = mode->pixclock; - if (tag == TAG_SHRES || tag == TAG_HIRES || tag == TAG_LORES) { - mode->pixclock = pixclock[tag]; - } - } - - if (amifb_hfmin) { - info->monspecs.hfmin = amifb_hfmin; - info->monspecs.hfmax = amifb_hfmax; - info->monspecs.vfmin = amifb_vfmin; - info->monspecs.vfmax = amifb_vfmax; - } else { - /* - * These are for a typical Amiga monitor (e.g. A1960) - */ - info->monspecs.hfmin = 15000; - info->monspecs.hfmax = 38000; - info->monspecs.vfmin = 49; - info->monspecs.vfmax = 90; - } - - info->fbops = &amifb_ops; - info->flags = FBINFO_DEFAULT; - info->device = &pdev->dev; - - if (!fb_find_mode(&info->var, info, mode_option, ami_modedb, - NUM_TOTAL_MODES, &ami_modedb[defmode], 4)) { - err = -EINVAL; - goto release; - } - - fb_videomode_to_modelist(ami_modedb, NUM_TOTAL_MODES, - &info->modelist); - - round_down_bpp = 0; - chipptr = chipalloc(info->fix.smem_len + SPRITEMEMSIZE + - DUMMYSPRITEMEMSIZE + COPINITSIZE + - 4 * COPLISTSIZE); - if (!chipptr) { - err = -ENOMEM; - goto release; - } - - assignchunk(videomemory, u_long, chipptr, info->fix.smem_len); - assignchunk(spritememory, u_long, chipptr, SPRITEMEMSIZE); - assignchunk(dummysprite, u_short *, chipptr, DUMMYSPRITEMEMSIZE); - assignchunk(copdisplay.init, copins *, chipptr, COPINITSIZE); - assignchunk(copdisplay.list[0][0], copins *, chipptr, COPLISTSIZE); - assignchunk(copdisplay.list[0][1], copins *, chipptr, COPLISTSIZE); - assignchunk(copdisplay.list[1][0], copins *, chipptr, COPLISTSIZE); - assignchunk(copdisplay.list[1][1], copins *, chipptr, COPLISTSIZE); - - /* - * access the videomem with writethrough cache - */ - info->fix.smem_start = (u_long)ZTWO_PADDR(videomemory); - videomemory = (u_long)ioremap_writethrough(info->fix.smem_start, - info->fix.smem_len); - if (!videomemory) { - dev_warn(&pdev->dev, - "Unable to map videomem cached writethrough\n"); - info->screen_base = ZTWO_VADDR(info->fix.smem_start); - } else - info->screen_base = (char *)videomemory; - - memset(dummysprite, 0, DUMMYSPRITEMEMSIZE); - - /* - * Make sure the Copper has something to do - */ - ami_init_copper(); - - /* - * Enable Display DMA - */ - custom.dmacon = DMAF_SETCLR | DMAF_MASTER | DMAF_RASTER | DMAF_COPPER | - DMAF_BLITTER | DMAF_SPRITE; - - err = request_irq(IRQ_AMIGA_COPPER, amifb_interrupt, 0, - "fb vertb handler", info->par); - if (err) - goto disable_dma; - - err = fb_alloc_cmap(&info->cmap, 1 << info->var.bits_per_pixel, 0); - if (err) - goto free_irq; - - dev_set_drvdata(&pdev->dev, info); - - err = register_framebuffer(info); - if (err) - goto unset_drvdata; - - fb_info(info, "%s frame buffer device, using %dK of video memory\n", - info->fix.id, info->fix.smem_len>>10); - - return 0; - -unset_drvdata: - fb_dealloc_cmap(&info->cmap); -free_irq: - free_irq(IRQ_AMIGA_COPPER, info->par); -disable_dma: - custom.dmacon = DMAF_ALL | DMAF_MASTER; - if (videomemory) - iounmap((void *)videomemory); - chipfree(); -release: - framebuffer_release(info); - return err; -} - - -static int __exit amifb_remove(struct platform_device *pdev) -{ - struct fb_info *info = dev_get_drvdata(&pdev->dev); - - unregister_framebuffer(info); - fb_dealloc_cmap(&info->cmap); - free_irq(IRQ_AMIGA_COPPER, info->par); - custom.dmacon = DMAF_ALL | DMAF_MASTER; - if (videomemory) - iounmap((void *)videomemory); - chipfree(); - framebuffer_release(info); - amifb_video_off(); - return 0; -} - -static struct platform_driver amifb_driver = { - .remove = __exit_p(amifb_remove), - .driver = { - .name = "amiga-video", - .owner = THIS_MODULE, - }, -}; - -module_platform_driver_probe(amifb_driver, amifb_probe); - -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:amiga-video"); diff --git a/drivers/video/arcfb.c b/drivers/video/arcfb.c deleted file mode 100644 index 1b0b233b8b3..00000000000 --- a/drivers/video/arcfb.c +++ /dev/null @@ -1,667 +0,0 @@ -/* - * linux/drivers/video/arcfb.c -- FB driver for Arc monochrome LCD board - * - * Copyright (C) 2005, Jaya Kumar - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive for - * more details. - * - * Layout is based on skeletonfb.c by James Simmons and Geert Uytterhoeven. - * - * This driver was written to be used with the Arc LCD board. Arc uses a - * set of KS108 chips that control individual 64x64 LCD matrices. The board - * can be paneled in a variety of setups such as 2x1=128x64, 4x4=256x256 and - * so on. The interface between the board and the host is TTL based GPIO. The - * GPIO requirements are 8 writable data lines and 4+n lines for control. On a - * GPIO-less system, the board can be tested by connecting the respective sigs - * up to a parallel port connector. The driver requires the IO addresses for - * data and control GPIO at load time. It is unable to probe for the - * existence of the LCD so it must be told at load time whether it should - * be enabled or not. - * - * Todo: - * - testing with 4x4 - * - testing with interrupt hw - * - * General notes: - * - User must set tuhold. It's in microseconds. According to the 108 spec, - * the hold time is supposed to be at least 1 microsecond. - * - User must set num_cols=x num_rows=y, eg: x=2 means 128 - * - User must set arcfb_enable=1 to enable it - * - User must set dio_addr=0xIOADDR cio_addr=0xIOADDR - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#define floor8(a) (a&(~0x07)) -#define floorXres(a,xres) (a&(~(xres - 1))) -#define iceil8(a) (((int)((a+7)/8))*8) -#define ceil64(a) (a|0x3F) -#define ceilXres(a,xres) (a|(xres - 1)) - -/* ks108 chipset specific defines and code */ - -#define KS_SET_DPY_START_LINE 0xC0 -#define KS_SET_PAGE_NUM 0xB8 -#define KS_SET_X 0x40 -#define KS_CEHI 0x01 -#define KS_CELO 0x00 -#define KS_SEL_CMD 0x08 -#define KS_SEL_DATA 0x00 -#define KS_DPY_ON 0x3F -#define KS_DPY_OFF 0x3E -#define KS_INTACK 0x40 -#define KS_CLRINT 0x02 - -struct arcfb_par { - unsigned long dio_addr; - unsigned long cio_addr; - unsigned long c2io_addr; - atomic_t ref_count; - unsigned char cslut[9]; - struct fb_info *info; - unsigned int irq; - spinlock_t lock; -}; - -static struct fb_fix_screeninfo arcfb_fix = { - .id = "arcfb", - .type = FB_TYPE_PACKED_PIXELS, - .visual = FB_VISUAL_MONO01, - .xpanstep = 0, - .ypanstep = 1, - .ywrapstep = 0, - .accel = FB_ACCEL_NONE, -}; - -static struct fb_var_screeninfo arcfb_var = { - .xres = 128, - .yres = 64, - .xres_virtual = 128, - .yres_virtual = 64, - .bits_per_pixel = 1, - .nonstd = 1, -}; - -static unsigned long num_cols; -static unsigned long num_rows; -static unsigned long dio_addr; -static unsigned long cio_addr; -static unsigned long c2io_addr; -static unsigned long splashval; -static unsigned long tuhold; -static unsigned int nosplash; -static unsigned int arcfb_enable; -static unsigned int irq; - -static DECLARE_WAIT_QUEUE_HEAD(arcfb_waitq); - -static void ks108_writeb_ctl(struct arcfb_par *par, - unsigned int chipindex, unsigned char value) -{ - unsigned char chipselval = par->cslut[chipindex]; - - outb(chipselval|KS_CEHI|KS_SEL_CMD, par->cio_addr); - outb(value, par->dio_addr); - udelay(tuhold); - outb(chipselval|KS_CELO|KS_SEL_CMD, par->cio_addr); -} - -static void ks108_writeb_mainctl(struct arcfb_par *par, unsigned char value) -{ - - outb(value, par->cio_addr); - udelay(tuhold); -} - -static unsigned char ks108_readb_ctl2(struct arcfb_par *par) -{ - return inb(par->c2io_addr); -} - -static void ks108_writeb_data(struct arcfb_par *par, - unsigned int chipindex, unsigned char value) -{ - unsigned char chipselval = par->cslut[chipindex]; - - outb(chipselval|KS_CEHI|KS_SEL_DATA, par->cio_addr); - outb(value, par->dio_addr); - udelay(tuhold); - outb(chipselval|KS_CELO|KS_SEL_DATA, par->cio_addr); -} - -static void ks108_set_start_line(struct arcfb_par *par, - unsigned int chipindex, unsigned char y) -{ - ks108_writeb_ctl(par, chipindex, KS_SET_DPY_START_LINE|y); -} - -static void ks108_set_yaddr(struct arcfb_par *par, - unsigned int chipindex, unsigned char y) -{ - ks108_writeb_ctl(par, chipindex, KS_SET_PAGE_NUM|y); -} - -static void ks108_set_xaddr(struct arcfb_par *par, - unsigned int chipindex, unsigned char x) -{ - ks108_writeb_ctl(par, chipindex, KS_SET_X|x); -} - -static void ks108_clear_lcd(struct arcfb_par *par, unsigned int chipindex) -{ - int i,j; - - for (i = 0; i <= 8; i++) { - ks108_set_yaddr(par, chipindex, i); - ks108_set_xaddr(par, chipindex, 0); - for (j = 0; j < 64; j++) { - ks108_writeb_data(par, chipindex, - (unsigned char) splashval); - } - } -} - -/* main arcfb functions */ - -static int arcfb_open(struct fb_info *info, int user) -{ - struct arcfb_par *par = info->par; - - atomic_inc(&par->ref_count); - return 0; -} - -static int arcfb_release(struct fb_info *info, int user) -{ - struct arcfb_par *par = info->par; - int count = atomic_read(&par->ref_count); - - if (!count) - return -EINVAL; - atomic_dec(&par->ref_count); - return 0; -} - -static int arcfb_pan_display(struct fb_var_screeninfo *var, - struct fb_info *info) -{ - int i; - struct arcfb_par *par = info->par; - - if ((var->vmode & FB_VMODE_YWRAP) && (var->yoffset < 64) - && (info->var.yres <= 64)) { - for (i = 0; i < num_cols; i++) { - ks108_set_start_line(par, i, var->yoffset); - } - info->var.yoffset = var->yoffset; - return 0; - } - - return -EINVAL; -} - -static irqreturn_t arcfb_interrupt(int vec, void *dev_instance) -{ - struct fb_info *info = dev_instance; - unsigned char ctl2status; - struct arcfb_par *par = info->par; - - ctl2status = ks108_readb_ctl2(par); - - if (!(ctl2status & KS_INTACK)) /* not arc generated interrupt */ - return IRQ_NONE; - - ks108_writeb_mainctl(par, KS_CLRINT); - - spin_lock(&par->lock); - if (waitqueue_active(&arcfb_waitq)) { - wake_up(&arcfb_waitq); - } - spin_unlock(&par->lock); - - return IRQ_HANDLED; -} - -/* - * here we handle a specific page on the lcd. the complexity comes from - * the fact that the fb is laidout in 8xX vertical columns. we extract - * each write of 8 vertical pixels. then we shift out as we move along - * X. That's what rightshift does. bitmask selects the desired input bit. - */ -static void arcfb_lcd_update_page(struct arcfb_par *par, unsigned int upper, - unsigned int left, unsigned int right, unsigned int distance) -{ - unsigned char *src; - unsigned int xindex, yindex, chipindex, linesize; - int i; - unsigned char val; - unsigned char bitmask, rightshift; - - xindex = left >> 6; - yindex = upper >> 6; - chipindex = (xindex + (yindex*num_cols)); - - ks108_set_yaddr(par, chipindex, upper/8); - - linesize = par->info->var.xres/8; - src = (unsigned char __force *) par->info->screen_base + (left/8) + - (upper * linesize); - ks108_set_xaddr(par, chipindex, left); - - bitmask=1; - rightshift=0; - while (left <= right) { - val = 0; - for (i = 0; i < 8; i++) { - if ( i > rightshift) { - val |= (*(src + (i*linesize)) & bitmask) - << (i - rightshift); - } else { - val |= (*(src + (i*linesize)) & bitmask) - >> (rightshift - i); - } - } - ks108_writeb_data(par, chipindex, val); - left++; - if (bitmask == 0x80) { - bitmask = 1; - src++; - rightshift=0; - } else { - bitmask <<= 1; - rightshift++; - } - } -} - -/* - * here we handle the entire vertical page of the update. we write across - * lcd chips. update_page uses the upper/left values to decide which - * chip to select for the right. upper is needed for setting the page - * desired for the write. - */ -static void arcfb_lcd_update_vert(struct arcfb_par *par, unsigned int top, - unsigned int bottom, unsigned int left, unsigned int right) -{ - unsigned int distance, upper, lower; - - distance = (bottom - top) + 1; - upper = top; - lower = top + 7; - - while (distance > 0) { - distance -= 8; - arcfb_lcd_update_page(par, upper, left, right, 8); - upper = lower + 1; - lower = upper + 7; - } -} - -/* - * here we handle horizontal blocks for the update. update_vert will - * handle spaning multiple pages. we break out each horizontal - * block in to individual blocks no taller than 64 pixels. - */ -static void arcfb_lcd_update_horiz(struct arcfb_par *par, unsigned int left, - unsigned int right, unsigned int top, unsigned int h) -{ - unsigned int distance, upper, lower; - - distance = h; - upper = floor8(top); - lower = min(upper + distance - 1, ceil64(upper)); - - while (distance > 0) { - distance -= ((lower - upper) + 1 ); - arcfb_lcd_update_vert(par, upper, lower, left, right); - upper = lower + 1; - lower = min(upper + distance - 1, ceil64(upper)); - } -} - -/* - * here we start the process of splitting out the fb update into - * individual blocks of pixels. we end up splitting into 64x64 blocks - * and finally down to 64x8 pages. - */ -static void arcfb_lcd_update(struct arcfb_par *par, unsigned int dx, - unsigned int dy, unsigned int w, unsigned int h) -{ - unsigned int left, right, distance, y; - - /* align the request first */ - y = floor8(dy); - h += dy - y; - h = iceil8(h); - - distance = w; - left = dx; - right = min(left + w - 1, ceil64(left)); - - while (distance > 0) { - arcfb_lcd_update_horiz(par, left, right, y, h); - distance -= ((right - left) + 1); - left = right + 1; - right = min(left + distance - 1, ceil64(left)); - } -} - -static void arcfb_fillrect(struct fb_info *info, - const struct fb_fillrect *rect) -{ - struct arcfb_par *par = info->par; - - sys_fillrect(info, rect); - - /* update the physical lcd */ - arcfb_lcd_update(par, rect->dx, rect->dy, rect->width, rect->height); -} - -static void arcfb_copyarea(struct fb_info *info, - const struct fb_copyarea *area) -{ - struct arcfb_par *par = info->par; - - sys_copyarea(info, area); - - /* update the physical lcd */ - arcfb_lcd_update(par, area->dx, area->dy, area->width, area->height); -} - -static void arcfb_imageblit(struct fb_info *info, const struct fb_image *image) -{ - struct arcfb_par *par = info->par; - - sys_imageblit(info, image); - - /* update the physical lcd */ - arcfb_lcd_update(par, image->dx, image->dy, image->width, - image->height); -} - -static int arcfb_ioctl(struct fb_info *info, - unsigned int cmd, unsigned long arg) -{ - void __user *argp = (void __user *)arg; - struct arcfb_par *par = info->par; - unsigned long flags; - - switch (cmd) { - case FBIO_WAITEVENT: - { - DEFINE_WAIT(wait); - /* illegal to wait on arc if no irq will occur */ - if (!par->irq) - return -EINVAL; - - /* wait until the Arc has generated an interrupt - * which will wake us up */ - spin_lock_irqsave(&par->lock, flags); - prepare_to_wait(&arcfb_waitq, &wait, - TASK_INTERRUPTIBLE); - spin_unlock_irqrestore(&par->lock, flags); - schedule(); - finish_wait(&arcfb_waitq, &wait); - } - case FBIO_GETCONTROL2: - { - unsigned char ctl2; - - ctl2 = ks108_readb_ctl2(info->par); - if (copy_to_user(argp, &ctl2, sizeof(ctl2))) - return -EFAULT; - return 0; - } - default: - return -EINVAL; - } -} - -/* - * this is the access path from userspace. they can seek and write to - * the fb. it's inefficient for them to do anything less than 64*8 - * writes since we update the lcd in each write() anyway. - */ -static ssize_t arcfb_write(struct fb_info *info, const char __user *buf, - size_t count, loff_t *ppos) -{ - /* modded from epson 1355 */ - - unsigned long p; - int err=-EINVAL; - unsigned int fbmemlength,x,y,w,h, bitppos, startpos, endpos, bitcount; - struct arcfb_par *par; - unsigned int xres; - - p = *ppos; - par = info->par; - xres = info->var.xres; - fbmemlength = (xres * info->var.yres)/8; - - if (p > fbmemlength) - return -ENOSPC; - - err = 0; - if ((count + p) > fbmemlength) { - count = fbmemlength - p; - err = -ENOSPC; - } - - if (count) { - char *base_addr; - - base_addr = (char __force *)info->screen_base; - count -= copy_from_user(base_addr + p, buf, count); - *ppos += count; - err = -EFAULT; - } - - - bitppos = p*8; - startpos = floorXres(bitppos, xres); - endpos = ceilXres((bitppos + (count*8)), xres); - bitcount = endpos - startpos; - - x = startpos % xres; - y = startpos / xres; - w = xres; - h = bitcount / xres; - arcfb_lcd_update(par, x, y, w, h); - - if (count) - return count; - return err; -} - -static struct fb_ops arcfb_ops = { - .owner = THIS_MODULE, - .fb_open = arcfb_open, - .fb_read = fb_sys_read, - .fb_write = arcfb_write, - .fb_release = arcfb_release, - .fb_pan_display = arcfb_pan_display, - .fb_fillrect = arcfb_fillrect, - .fb_copyarea = arcfb_copyarea, - .fb_imageblit = arcfb_imageblit, - .fb_ioctl = arcfb_ioctl, -}; - -static int arcfb_probe(struct platform_device *dev) -{ - struct fb_info *info; - int retval = -ENOMEM; - int videomemorysize; - unsigned char *videomemory; - struct arcfb_par *par; - int i; - - videomemorysize = (((64*64)*num_cols)*num_rows)/8; - - /* We need a flat backing store for the Arc's - less-flat actual paged framebuffer */ - videomemory = vzalloc(videomemorysize); - if (!videomemory) - return retval; - - info = framebuffer_alloc(sizeof(struct arcfb_par), &dev->dev); - if (!info) - goto err; - - info->screen_base = (char __iomem *)videomemory; - info->fbops = &arcfb_ops; - - info->var = arcfb_var; - info->fix = arcfb_fix; - par = info->par; - par->info = info; - - if (!dio_addr || !cio_addr || !c2io_addr) { - printk(KERN_WARNING "no IO addresses supplied\n"); - goto err1; - } - par->dio_addr = dio_addr; - par->cio_addr = cio_addr; - par->c2io_addr = c2io_addr; - par->cslut[0] = 0x00; - par->cslut[1] = 0x06; - info->flags = FBINFO_FLAG_DEFAULT; - spin_lock_init(&par->lock); - retval = register_framebuffer(info); - if (retval < 0) - goto err1; - platform_set_drvdata(dev, info); - if (irq) { - par->irq = irq; - if (request_irq(par->irq, &arcfb_interrupt, IRQF_SHARED, - "arcfb", info)) { - printk(KERN_INFO - "arcfb: Failed req IRQ %d\n", par->irq); - retval = -EBUSY; - goto err1; - } - } - fb_info(info, "Arc frame buffer device, using %dK of video memory\n", - videomemorysize >> 10); - - /* this inits the lcd but doesn't clear dirty pixels */ - for (i = 0; i < num_cols * num_rows; i++) { - ks108_writeb_ctl(par, i, KS_DPY_OFF); - ks108_set_start_line(par, i, 0); - ks108_set_yaddr(par, i, 0); - ks108_set_xaddr(par, i, 0); - ks108_writeb_ctl(par, i, KS_DPY_ON); - } - - /* if we were told to splash the screen, we just clear it */ - if (!nosplash) { - for (i = 0; i < num_cols * num_rows; i++) { - fb_info(info, "splashing lcd %d\n", i); - ks108_set_start_line(par, i, 0); - ks108_clear_lcd(par, i); - } - } - - return 0; -err1: - framebuffer_release(info); -err: - vfree(videomemory); - return retval; -} - -static int arcfb_remove(struct platform_device *dev) -{ - struct fb_info *info = platform_get_drvdata(dev); - - if (info) { - unregister_framebuffer(info); - vfree((void __force *)info->screen_base); - framebuffer_release(info); - } - return 0; -} - -static struct platform_driver arcfb_driver = { - .probe = arcfb_probe, - .remove = arcfb_remove, - .driver = { - .name = "arcfb", - }, -}; - -static struct platform_device *arcfb_device; - -static int __init arcfb_init(void) -{ - int ret; - - if (!arcfb_enable) - return -ENXIO; - - ret = platform_driver_register(&arcfb_driver); - if (!ret) { - arcfb_device = platform_device_alloc("arcfb", 0); - if (arcfb_device) { - ret = platform_device_add(arcfb_device); - } else { - ret = -ENOMEM; - } - if (ret) { - platform_device_put(arcfb_device); - platform_driver_unregister(&arcfb_driver); - } - } - return ret; - -} - -static void __exit arcfb_exit(void) -{ - platform_device_unregister(arcfb_device); - platform_driver_unregister(&arcfb_driver); -} - -module_param(num_cols, ulong, 0); -MODULE_PARM_DESC(num_cols, "Num horiz panels, eg: 2 = 128 bit wide"); -module_param(num_rows, ulong, 0); -MODULE_PARM_DESC(num_rows, "Num vert panels, eg: 1 = 64 bit high"); -module_param(nosplash, uint, 0); -MODULE_PARM_DESC(nosplash, "Disable doing the splash screen"); -module_param(arcfb_enable, uint, 0); -MODULE_PARM_DESC(arcfb_enable, "Enable communication with Arc board"); -module_param(dio_addr, ulong, 0); -MODULE_PARM_DESC(dio_addr, "IO address for data, eg: 0x480"); -module_param(cio_addr, ulong, 0); -MODULE_PARM_DESC(cio_addr, "IO address for control, eg: 0x400"); -module_param(c2io_addr, ulong, 0); -MODULE_PARM_DESC(c2io_addr, "IO address for secondary control, eg: 0x408"); -module_param(splashval, ulong, 0); -MODULE_PARM_DESC(splashval, "Splash pattern: 0xFF is black, 0x00 is green"); -module_param(tuhold, ulong, 0); -MODULE_PARM_DESC(tuhold, "Time to hold between strobing data to Arc board"); -module_param(irq, uint, 0); -MODULE_PARM_DESC(irq, "IRQ for the Arc board"); - -module_init(arcfb_init); -module_exit(arcfb_exit); - -MODULE_DESCRIPTION("fbdev driver for Arc monochrome LCD board"); -MODULE_AUTHOR("Jaya Kumar"); -MODULE_LICENSE("GPL"); - diff --git a/drivers/video/arkfb.c b/drivers/video/arkfb.c deleted file mode 100644 index adc4ea2cc5a..00000000000 --- a/drivers/video/arkfb.c +++ /dev/null @@ -1,1231 +0,0 @@ -/* - * linux/drivers/video/arkfb.c -- Frame buffer device driver for ARK 2000PV - * with ICS 5342 dac (it is easy to add support for different dacs). - * - * Copyright (c) 2007 Ondrej Zajicek - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive for - * more details. - * - * Code is based on s3fb - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* Why should fb driver call console functions? because console_lock() */ -#include Frame Buffer Memory -!Edrivers/video/fbdev/fbmem.c +!Edrivers/video/fbdev/core/fbmem.c Frame Buffer Colormap -!Edrivers/video/fbdev/fbcmap.c +!Edrivers/video/fbdev/core/fbcmap.c Frame Buffer Video Mode Database -!Idrivers/video/fbdev/modedb.c -!Edrivers/video/fbdev/modedb.c +!Idrivers/video/fbdev/core/modedb.c +!Edrivers/video/fbdev/core/modedb.c Frame Buffer Macintosh Video Mode Database !Edrivers/video/fbdev/macmodes.c diff --git a/drivers/video/fbdev/Makefile b/drivers/video/fbdev/Makefile index 8a79eec2113..0284f2a1253 100644 --- a/drivers/video/fbdev/Makefile +++ b/drivers/video/fbdev/Makefile @@ -4,25 +4,11 @@ # Each configuration option enables a list of files. -obj-y += fb_notify.o -obj-$(CONFIG_FB) += fb.o -fb-y := fbmem.o fbmon.o fbcmap.o fbsysfs.o \ - modedb.o fbcvt.o -fb-objs := $(fb-y) +obj-y += core/ obj-$(CONFIG_EXYNOS_VIDEO) += exynos/ -obj-$(CONFIG_FB_CFB_FILLRECT) += cfbfillrect.o -obj-$(CONFIG_FB_CFB_COPYAREA) += cfbcopyarea.o -obj-$(CONFIG_FB_CFB_IMAGEBLIT) += cfbimgblt.o -obj-$(CONFIG_FB_SYS_FILLRECT) += sysfillrect.o -obj-$(CONFIG_FB_SYS_COPYAREA) += syscopyarea.o -obj-$(CONFIG_FB_SYS_IMAGEBLIT) += sysimgblt.o -obj-$(CONFIG_FB_SYS_FOPS) += fb_sys_fops.o -obj-$(CONFIG_FB_SVGALIB) += svgalib.o obj-$(CONFIG_FB_MACMODES) += macmodes.o -obj-$(CONFIG_FB_DDC) += fb_ddc.o -obj-$(CONFIG_FB_DEFERRED_IO) += fb_defio.o obj-$(CONFIG_FB_WMT_GE_ROPS) += wmt_ge_rops.o # Hardware specific drivers go first diff --git a/drivers/video/fbdev/aty/mach64_cursor.c b/drivers/video/fbdev/aty/mach64_cursor.c index 0fe02e22d9a..2fa0317ab3c 100644 --- a/drivers/video/fbdev/aty/mach64_cursor.c +++ b/drivers/video/fbdev/aty/mach64_cursor.c @@ -5,7 +5,7 @@ #include #include #include -#include "../fb_draw.h" +#include "../core/fb_draw.h" #include diff --git a/drivers/video/fbdev/cfbcopyarea.c b/drivers/video/fbdev/cfbcopyarea.c deleted file mode 100644 index bcb57235fcc..00000000000 --- a/drivers/video/fbdev/cfbcopyarea.c +++ /dev/null @@ -1,434 +0,0 @@ -/* - * Generic function for frame buffer with packed pixels of any depth. - * - * Copyright (C) 1999-2005 James Simmons - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive for - * more details. - * - * NOTES: - * - * This is for cfb packed pixels. Iplan and such are incorporated in the - * drivers that need them. - * - * FIXME - * - * Also need to add code to deal with cards endians that are different than - * the native cpu endians. I also need to deal with MSB position in the word. - * - * The two functions or copying forward and backward could be split up like - * the ones for filling, i.e. in aligned and unaligned versions. This would - * help moving some redundant computations and branches out of the loop, too. - */ - -#include -#include -#include -#include -#include -#include -#include "fb_draw.h" - -#if BITS_PER_LONG == 32 -# define FB_WRITEL fb_writel -# define FB_READL fb_readl -#else -# define FB_WRITEL fb_writeq -# define FB_READL fb_readq -#endif - - /* - * Generic bitwise copy algorithm - */ - -static void -bitcpy(struct fb_info *p, unsigned long __iomem *dst, unsigned dst_idx, - const unsigned long __iomem *src, unsigned src_idx, int bits, - unsigned n, u32 bswapmask) -{ - unsigned long first, last; - int const shift = dst_idx-src_idx; - -#if 0 - /* - * If you suspect bug in this function, compare it with this simple - * memmove implementation. - */ - fb_memmove((char *)dst + ((dst_idx & (bits - 1))) / 8, - (char *)src + ((src_idx & (bits - 1))) / 8, n / 8); - return; -#endif - - first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask); - last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask); - - if (!shift) { - // Same alignment for source and dest - - if (dst_idx+n <= bits) { - // Single word - if (last) - first &= last; - FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst); - } else { - // Multiple destination words - - // Leading bits - if (first != ~0UL) { - FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst); - dst++; - src++; - n -= bits - dst_idx; - } - - // Main chunk - n /= bits; - while (n >= 8) { - FB_WRITEL(FB_READL(src++), dst++); - FB_WRITEL(FB_READL(src++), dst++); - FB_WRITEL(FB_READL(src++), dst++); - FB_WRITEL(FB_READL(src++), dst++); - FB_WRITEL(FB_READL(src++), dst++); - FB_WRITEL(FB_READL(src++), dst++); - FB_WRITEL(FB_READL(src++), dst++); - FB_WRITEL(FB_READL(src++), dst++); - n -= 8; - } - while (n--) - FB_WRITEL(FB_READL(src++), dst++); - - // Trailing bits - if (last) - FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst); - } - } else { - /* Different alignment for source and dest */ - unsigned long d0, d1; - int m; - - int const left = shift & (bits - 1); - int const right = -shift & (bits - 1); - - if (dst_idx+n <= bits) { - // Single destination word - if (last) - first &= last; - d0 = FB_READL(src); - d0 = fb_rev_pixels_in_long(d0, bswapmask); - if (shift > 0) { - // Single source word - d0 <<= left; - } else if (src_idx+n <= bits) { - // Single source word - d0 >>= right; - } else { - // 2 source words - d1 = FB_READL(src + 1); - d1 = fb_rev_pixels_in_long(d1, bswapmask); - d0 = d0 >> right | d1 << left; - } - d0 = fb_rev_pixels_in_long(d0, bswapmask); - FB_WRITEL(comp(d0, FB_READL(dst), first), dst); - } else { - // Multiple destination words - /** We must always remember the last value read, because in case - SRC and DST overlap bitwise (e.g. when moving just one pixel in - 1bpp), we always collect one full long for DST and that might - overlap with the current long from SRC. We store this value in - 'd0'. */ - d0 = FB_READL(src++); - d0 = fb_rev_pixels_in_long(d0, bswapmask); - // Leading bits - if (shift > 0) { - // Single source word - d1 = d0; - d0 <<= left; - n -= bits - dst_idx; - } else { - // 2 source words - d1 = FB_READL(src++); - d1 = fb_rev_pixels_in_long(d1, bswapmask); - - d0 = d0 >> right | d1 << left; - n -= bits - dst_idx; - } - d0 = fb_rev_pixels_in_long(d0, bswapmask); - FB_WRITEL(comp(d0, FB_READL(dst), first), dst); - d0 = d1; - dst++; - - // Main chunk - m = n % bits; - n /= bits; - while ((n >= 4) && !bswapmask) { - d1 = FB_READL(src++); - FB_WRITEL(d0 >> right | d1 << left, dst++); - d0 = d1; - d1 = FB_READL(src++); - FB_WRITEL(d0 >> right | d1 << left, dst++); - d0 = d1; - d1 = FB_READL(src++); - FB_WRITEL(d0 >> right | d1 << left, dst++); - d0 = d1; - d1 = FB_READL(src++); - FB_WRITEL(d0 >> right | d1 << left, dst++); - d0 = d1; - n -= 4; - } - while (n--) { - d1 = FB_READL(src++); - d1 = fb_rev_pixels_in_long(d1, bswapmask); - d0 = d0 >> right | d1 << left; - d0 = fb_rev_pixels_in_long(d0, bswapmask); - FB_WRITEL(d0, dst++); - d0 = d1; - } - - // Trailing bits - if (m) { - if (m <= bits - right) { - // Single source word - d0 >>= right; - } else { - // 2 source words - d1 = FB_READL(src); - d1 = fb_rev_pixels_in_long(d1, - bswapmask); - d0 = d0 >> right | d1 << left; - } - d0 = fb_rev_pixels_in_long(d0, bswapmask); - FB_WRITEL(comp(d0, FB_READL(dst), last), dst); - } - } - } -} - - /* - * Generic bitwise copy algorithm, operating backward - */ - -static void -bitcpy_rev(struct fb_info *p, unsigned long __iomem *dst, unsigned dst_idx, - const unsigned long __iomem *src, unsigned src_idx, int bits, - unsigned n, u32 bswapmask) -{ - unsigned long first, last; - int shift; - -#if 0 - /* - * If you suspect bug in this function, compare it with this simple - * memmove implementation. - */ - fb_memmove((char *)dst + ((dst_idx & (bits - 1))) / 8, - (char *)src + ((src_idx & (bits - 1))) / 8, n / 8); - return; -#endif - - dst += (dst_idx + n - 1) / bits; - src += (src_idx + n - 1) / bits; - dst_idx = (dst_idx + n - 1) % bits; - src_idx = (src_idx + n - 1) % bits; - - shift = dst_idx-src_idx; - - first = ~fb_shifted_pixels_mask_long(p, (dst_idx + 1) % bits, bswapmask); - last = fb_shifted_pixels_mask_long(p, (bits + dst_idx + 1 - n) % bits, bswapmask); - - if (!shift) { - // Same alignment for source and dest - - if ((unsigned long)dst_idx+1 >= n) { - // Single word - if (first) - last &= first; - FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst); - } else { - // Multiple destination words - - // Leading bits - if (first) { - FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst); - dst--; - src--; - n -= dst_idx+1; - } - - // Main chunk - n /= bits; - while (n >= 8) { - FB_WRITEL(FB_READL(src--), dst--); - FB_WRITEL(FB_READL(src--), dst--); - FB_WRITEL(FB_READL(src--), dst--); - FB_WRITEL(FB_READL(src--), dst--); - FB_WRITEL(FB_READL(src--), dst--); - FB_WRITEL(FB_READL(src--), dst--); - FB_WRITEL(FB_READL(src--), dst--); - FB_WRITEL(FB_READL(src--), dst--); - n -= 8; - } - while (n--) - FB_WRITEL(FB_READL(src--), dst--); - - // Trailing bits - if (last != -1UL) - FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst); - } - } else { - // Different alignment for source and dest - unsigned long d0, d1; - int m; - - int const left = shift & (bits-1); - int const right = -shift & (bits-1); - - if ((unsigned long)dst_idx+1 >= n) { - // Single destination word - if (first) - last &= first; - d0 = FB_READL(src); - if (shift < 0) { - // Single source word - d0 >>= right; - } else if (1+(unsigned long)src_idx >= n) { - // Single source word - d0 <<= left; - } else { - // 2 source words - d1 = FB_READL(src - 1); - d1 = fb_rev_pixels_in_long(d1, bswapmask); - d0 = d0 << left | d1 >> right; - } - d0 = fb_rev_pixels_in_long(d0, bswapmask); - FB_WRITEL(comp(d0, FB_READL(dst), last), dst); - } else { - // Multiple destination words - /** We must always remember the last value read, because in case - SRC and DST overlap bitwise (e.g. when moving just one pixel in - 1bpp), we always collect one full long for DST and that might - overlap with the current long from SRC. We store this value in - 'd0'. */ - - d0 = FB_READL(src--); - d0 = fb_rev_pixels_in_long(d0, bswapmask); - // Leading bits - if (shift < 0) { - // Single source word - d1 = d0; - d0 >>= right; - } else { - // 2 source words - d1 = FB_READL(src--); - d1 = fb_rev_pixels_in_long(d1, bswapmask); - d0 = d0 << left | d1 >> right; - } - d0 = fb_rev_pixels_in_long(d0, bswapmask); - FB_WRITEL(comp(d0, FB_READL(dst), first), dst); - d0 = d1; - dst--; - n -= dst_idx+1; - - // Main chunk - m = n % bits; - n /= bits; - while ((n >= 4) && !bswapmask) { - d1 = FB_READL(src--); - FB_WRITEL(d0 << left | d1 >> right, dst--); - d0 = d1; - d1 = FB_READL(src--); - FB_WRITEL(d0 << left | d1 >> right, dst--); - d0 = d1; - d1 = FB_READL(src--); - FB_WRITEL(d0 << left | d1 >> right, dst--); - d0 = d1; - d1 = FB_READL(src--); - FB_WRITEL(d0 << left | d1 >> right, dst--); - d0 = d1; - n -= 4; - } - while (n--) { - d1 = FB_READL(src--); - d1 = fb_rev_pixels_in_long(d1, bswapmask); - d0 = d0 << left | d1 >> right; - d0 = fb_rev_pixels_in_long(d0, bswapmask); - FB_WRITEL(d0, dst--); - d0 = d1; - } - - // Trailing bits - if (m) { - if (m <= bits - left) { - // Single source word - d0 <<= left; - } else { - // 2 source words - d1 = FB_READL(src); - d1 = fb_rev_pixels_in_long(d1, - bswapmask); - d0 = d0 << left | d1 >> right; - } - d0 = fb_rev_pixels_in_long(d0, bswapmask); - FB_WRITEL(comp(d0, FB_READL(dst), last), dst); - } - } - } -} - -void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) -{ - u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy; - u32 height = area->height, width = area->width; - unsigned long const bits_per_line = p->fix.line_length*8u; - unsigned long __iomem *base = NULL; - int bits = BITS_PER_LONG, bytes = bits >> 3; - unsigned dst_idx = 0, src_idx = 0, rev_copy = 0; - u32 bswapmask = fb_compute_bswapmask(p); - - if (p->state != FBINFO_STATE_RUNNING) - return; - - /* if the beginning of the target area might overlap with the end of - the source area, be have to copy the area reverse. */ - if ((dy == sy && dx > sx) || (dy > sy)) { - dy += height; - sy += height; - rev_copy = 1; - } - - // split the base of the framebuffer into a long-aligned address and the - // index of the first bit - base = (unsigned long __iomem *)((unsigned long)p->screen_base & ~(bytes-1)); - dst_idx = src_idx = 8*((unsigned long)p->screen_base & (bytes-1)); - // add offset of source and target area - dst_idx += dy*bits_per_line + dx*p->var.bits_per_pixel; - src_idx += sy*bits_per_line + sx*p->var.bits_per_pixel; - - if (p->fbops->fb_sync) - p->fbops->fb_sync(p); - - if (rev_copy) { - while (height--) { - dst_idx -= bits_per_line; - src_idx -= bits_per_line; - bitcpy_rev(p, base + (dst_idx / bits), dst_idx % bits, - base + (src_idx / bits), src_idx % bits, bits, - width*p->var.bits_per_pixel, bswapmask); - } - } else { - while (height--) { - bitcpy(p, base + (dst_idx / bits), dst_idx % bits, - base + (src_idx / bits), src_idx % bits, bits, - width*p->var.bits_per_pixel, bswapmask); - dst_idx += bits_per_line; - src_idx += bits_per_line; - } - } -} - -EXPORT_SYMBOL(cfb_copyarea); - -MODULE_AUTHOR("James Simmons "); -MODULE_DESCRIPTION("Generic software accelerated copyarea"); -MODULE_LICENSE("GPL"); - diff --git a/drivers/video/fbdev/cfbfillrect.c b/drivers/video/fbdev/cfbfillrect.c deleted file mode 100644 index ba9f58b2a5e..00000000000 --- a/drivers/video/fbdev/cfbfillrect.c +++ /dev/null @@ -1,371 +0,0 @@ -/* - * Generic fillrect for frame buffers with packed pixels of any depth. - * - * Copyright (C) 2000 James Simmons (jsimmons@linux-fbdev.org) - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive for - * more details. - * - * NOTES: - * - * Also need to add code to deal with cards endians that are different than - * the native cpu endians. I also need to deal with MSB position in the word. - * - */ -#include -#include -#include -#include -#include "fb_draw.h" - -#if BITS_PER_LONG == 32 -# define FB_WRITEL fb_writel -# define FB_READL fb_readl -#else -# define FB_WRITEL fb_writeq -# define FB_READL fb_readq -#endif - - /* - * Aligned pattern fill using 32/64-bit memory accesses - */ - -static void -bitfill_aligned(struct fb_info *p, unsigned long __iomem *dst, int dst_idx, - unsigned long pat, unsigned n, int bits, u32 bswapmask) -{ - unsigned long first, last; - - if (!n) - return; - - first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask); - last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask); - - if (dst_idx+n <= bits) { - // Single word - if (last) - first &= last; - FB_WRITEL(comp(pat, FB_READL(dst), first), dst); - } else { - // Multiple destination words - - // Leading bits - if (first!= ~0UL) { - FB_WRITEL(comp(pat, FB_READL(dst), first), dst); - dst++; - n -= bits - dst_idx; - } - - // Main chunk - n /= bits; - while (n >= 8) { - FB_WRITEL(pat, dst++); - FB_WRITEL(pat, dst++); - FB_WRITEL(pat, dst++); - FB_WRITEL(pat, dst++); - FB_WRITEL(pat, dst++); - FB_WRITEL(pat, dst++); - FB_WRITEL(pat, dst++); - FB_WRITEL(pat, dst++); - n -= 8; - } - while (n--) - FB_WRITEL(pat, dst++); - - // Trailing bits - if (last) - FB_WRITEL(comp(pat, FB_READL(dst), last), dst); - } -} - - - /* - * Unaligned generic pattern fill using 32/64-bit memory accesses - * The pattern must have been expanded to a full 32/64-bit value - * Left/right are the appropriate shifts to convert to the pattern to be - * used for the next 32/64-bit word - */ - -static void -bitfill_unaligned(struct fb_info *p, unsigned long __iomem *dst, int dst_idx, - unsigned long pat, int left, int right, unsigned n, int bits) -{ - unsigned long first, last; - - if (!n) - return; - - first = FB_SHIFT_HIGH(p, ~0UL, dst_idx); - last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits)); - - if (dst_idx+n <= bits) { - // Single word - if (last) - first &= last; - FB_WRITEL(comp(pat, FB_READL(dst), first), dst); - } else { - // Multiple destination words - // Leading bits - if (first) { - FB_WRITEL(comp(pat, FB_READL(dst), first), dst); - dst++; - pat = pat << left | pat >> right; - n -= bits - dst_idx; - } - - // Main chunk - n /= bits; - while (n >= 4) { - FB_WRITEL(pat, dst++); - pat = pat << left | pat >> right; - FB_WRITEL(pat, dst++); - pat = pat << left | pat >> right; - FB_WRITEL(pat, dst++); - pat = pat << left | pat >> right; - FB_WRITEL(pat, dst++); - pat = pat << left | pat >> right; - n -= 4; - } - while (n--) { - FB_WRITEL(pat, dst++); - pat = pat << left | pat >> right; - } - - // Trailing bits - if (last) - FB_WRITEL(comp(pat, FB_READL(dst), last), dst); - } -} - - /* - * Aligned pattern invert using 32/64-bit memory accesses - */ -static void -bitfill_aligned_rev(struct fb_info *p, unsigned long __iomem *dst, - int dst_idx, unsigned long pat, unsigned n, int bits, - u32 bswapmask) -{ - unsigned long val = pat, dat; - unsigned long first, last; - - if (!n) - return; - - first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask); - last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask); - - if (dst_idx+n <= bits) { - // Single word - if (last) - first &= last; - dat = FB_READL(dst); - FB_WRITEL(comp(dat ^ val, dat, first), dst); - } else { - // Multiple destination words - // Leading bits - if (first!=0UL) { - dat = FB_READL(dst); - FB_WRITEL(comp(dat ^ val, dat, first), dst); - dst++; - n -= bits - dst_idx; - } - - // Main chunk - n /= bits; - while (n >= 8) { - FB_WRITEL(FB_READL(dst) ^ val, dst); - dst++; - FB_WRITEL(FB_READL(dst) ^ val, dst); - dst++; - FB_WRITEL(FB_READL(dst) ^ val, dst); - dst++; - FB_WRITEL(FB_READL(dst) ^ val, dst); - dst++; - FB_WRITEL(FB_READL(dst) ^ val, dst); - dst++; - FB_WRITEL(FB_READL(dst) ^ val, dst); - dst++; - FB_WRITEL(FB_READL(dst) ^ val, dst); - dst++; - FB_WRITEL(FB_READL(dst) ^ val, dst); - dst++; - n -= 8; - } - while (n--) { - FB_WRITEL(FB_READL(dst) ^ val, dst); - dst++; - } - // Trailing bits - if (last) { - dat = FB_READL(dst); - FB_WRITEL(comp(dat ^ val, dat, last), dst); - } - } -} - - - /* - * Unaligned generic pattern invert using 32/64-bit memory accesses - * The pattern must have been expanded to a full 32/64-bit value - * Left/right are the appropriate shifts to convert to the pattern to be - * used for the next 32/64-bit word - */ - -static void -bitfill_unaligned_rev(struct fb_info *p, unsigned long __iomem *dst, - int dst_idx, unsigned long pat, int left, int right, - unsigned n, int bits) -{ - unsigned long first, last, dat; - - if (!n) - return; - - first = FB_SHIFT_HIGH(p, ~0UL, dst_idx); - last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits)); - - if (dst_idx+n <= bits) { - // Single word - if (last) - first &= last; - dat = FB_READL(dst); - FB_WRITEL(comp(dat ^ pat, dat, first), dst); - } else { - // Multiple destination words - - // Leading bits - if (first != 0UL) { - dat = FB_READL(dst); - FB_WRITEL(comp(dat ^ pat, dat, first), dst); - dst++; - pat = pat << left | pat >> right; - n -= bits - dst_idx; - } - - // Main chunk - n /= bits; - while (n >= 4) { - FB_WRITEL(FB_READL(dst) ^ pat, dst); - dst++; - pat = pat << left | pat >> right; - FB_WRITEL(FB_READL(dst) ^ pat, dst); - dst++; - pat = pat << left | pat >> right; - FB_WRITEL(FB_READL(dst) ^ pat, dst); - dst++; - pat = pat << left | pat >> right; - FB_WRITEL(FB_READL(dst) ^ pat, dst); - dst++; - pat = pat << left | pat >> right; - n -= 4; - } - while (n--) { - FB_WRITEL(FB_READL(dst) ^ pat, dst); - dst++; - pat = pat << left | pat >> right; - } - - // Trailing bits - if (last) { - dat = FB_READL(dst); - FB_WRITEL(comp(dat ^ pat, dat, last), dst); - } - } -} - -void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect) -{ - unsigned long pat, pat2, fg; - unsigned long width = rect->width, height = rect->height; - int bits = BITS_PER_LONG, bytes = bits >> 3; - u32 bpp = p->var.bits_per_pixel; - unsigned long __iomem *dst; - int dst_idx, left; - - if (p->state != FBINFO_STATE_RUNNING) - return; - - if (p->fix.visual == FB_VISUAL_TRUECOLOR || - p->fix.visual == FB_VISUAL_DIRECTCOLOR ) - fg = ((u32 *) (p->pseudo_palette))[rect->color]; - else - fg = rect->color; - - pat = pixel_to_pat(bpp, fg); - - dst = (unsigned long __iomem *)((unsigned long)p->screen_base & ~(bytes-1)); - dst_idx = ((unsigned long)p->screen_base & (bytes - 1))*8; - dst_idx += rect->dy*p->fix.line_length*8+rect->dx*bpp; - /* FIXME For now we support 1-32 bpp only */ - left = bits % bpp; - if (p->fbops->fb_sync) - p->fbops->fb_sync(p); - if (!left) { - u32 bswapmask = fb_compute_bswapmask(p); - void (*fill_op32)(struct fb_info *p, - unsigned long __iomem *dst, int dst_idx, - unsigned long pat, unsigned n, int bits, - u32 bswapmask) = NULL; - - switch (rect->rop) { - case ROP_XOR: - fill_op32 = bitfill_aligned_rev; - break; - case ROP_COPY: - fill_op32 = bitfill_aligned; - break; - default: - printk( KERN_ERR "cfb_fillrect(): unknown rop, defaulting to ROP_COPY\n"); - fill_op32 = bitfill_aligned; - break; - } - while (height--) { - dst += dst_idx >> (ffs(bits) - 1); - dst_idx &= (bits - 1); - fill_op32(p, dst, dst_idx, pat, width*bpp, bits, - bswapmask); - dst_idx += p->fix.line_length*8; - } - } else { - int right, r; - void (*fill_op)(struct fb_info *p, unsigned long __iomem *dst, - int dst_idx, unsigned long pat, int left, - int right, unsigned n, int bits) = NULL; -#ifdef __LITTLE_ENDIAN - right = left; - left = bpp - right; -#else - right = bpp - left; -#endif - switch (rect->rop) { - case ROP_XOR: - fill_op = bitfill_unaligned_rev; - break; - case ROP_COPY: - fill_op = bitfill_unaligned; - break; - default: - printk(KERN_ERR "cfb_fillrect(): unknown rop, defaulting to ROP_COPY\n"); - fill_op = bitfill_unaligned; - break; - } - while (height--) { - dst += dst_idx / bits; - dst_idx &= (bits - 1); - r = dst_idx % bpp; - /* rotate pattern to the correct start position */ - pat2 = le_long_to_cpu(rolx(cpu_to_le_long(pat), r, bpp)); - fill_op(p, dst, dst_idx, pat2, left, right, - width*bpp, bits); - dst_idx += p->fix.line_length*8; - } - } -} - -EXPORT_SYMBOL(cfb_fillrect); - -MODULE_AUTHOR("James Simmons "); -MODULE_DESCRIPTION("Generic software accelerated fill rectangle"); -MODULE_LICENSE("GPL"); diff --git a/drivers/video/fbdev/cfbimgblt.c b/drivers/video/fbdev/cfbimgblt.c deleted file mode 100644 index a2bb276a8b2..00000000000 --- a/drivers/video/fbdev/cfbimgblt.c +++ /dev/null @@ -1,313 +0,0 @@ -/* - * Generic BitBLT function for frame buffer with packed pixels of any depth. - * - * Copyright (C) June 1999 James Simmons - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive for - * more details. - * - * NOTES: - * - * This function copys a image from system memory to video memory. The - * image can be a bitmap where each 0 represents the background color and - * each 1 represents the foreground color. Great for font handling. It can - * also be a color image. This is determined by image_depth. The color image - * must be laid out exactly in the same format as the framebuffer. Yes I know - * their are cards with hardware that coverts images of various depths to the - * framebuffer depth. But not every card has this. All images must be rounded - * up to the nearest byte. For example a bitmap 12 bits wide must be two - * bytes width. - * - * Tony: - * Incorporate mask tables similar to fbcon-cfb*.c in 2.4 API. This speeds - * up the code significantly. - * - * Code for depths not multiples of BITS_PER_LONG is still kludgy, which is - * still processed a bit at a time. - * - * Also need to add code to deal with cards endians that are different than - * the native cpu endians. I also need to deal with MSB position in the word. - */ -#include -#include -#include -#include -#include "fb_draw.h" - -#define DEBUG - -#ifdef DEBUG -#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt,__func__,## args) -#else -#define DPRINTK(fmt, args...) -#endif - -static const u32 cfb_tab8_be[] = { - 0x00000000,0x000000ff,0x0000ff00,0x0000ffff, - 0x00ff0000,0x00ff00ff,0x00ffff00,0x00ffffff, - 0xff000000,0xff0000ff,0xff00ff00,0xff00ffff, - 0xffff0000,0xffff00ff,0xffffff00,0xffffffff -}; - -static const u32 cfb_tab8_le[] = { - 0x00000000,0xff000000,0x00ff0000,0xffff0000, - 0x0000ff00,0xff00ff00,0x00ffff00,0xffffff00, - 0x000000ff,0xff0000ff,0x00ff00ff,0xffff00ff, - 0x0000ffff,0xff00ffff,0x00ffffff,0xffffffff -}; - -static const u32 cfb_tab16_be[] = { - 0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff -}; - -static const u32 cfb_tab16_le[] = { - 0x00000000, 0xffff0000, 0x0000ffff, 0xffffffff -}; - -static const u32 cfb_tab32[] = { - 0x00000000, 0xffffffff -}; - -#define FB_WRITEL fb_writel -#define FB_READL fb_readl - -static inline void color_imageblit(const struct fb_image *image, - struct fb_info *p, u8 __iomem *dst1, - u32 start_index, - u32 pitch_index) -{ - /* Draw the penguin */ - u32 __iomem *dst, *dst2; - u32 color = 0, val, shift; - int i, n, bpp = p->var.bits_per_pixel; - u32 null_bits = 32 - bpp; - u32 *palette = (u32 *) p->pseudo_palette; - const u8 *src = image->data; - u32 bswapmask = fb_compute_bswapmask(p); - - dst2 = (u32 __iomem *) dst1; - for (i = image->height; i--; ) { - n = image->width; - dst = (u32 __iomem *) dst1; - shift = 0; - val = 0; - - if (start_index) { - u32 start_mask = ~fb_shifted_pixels_mask_u32(p, - start_index, bswapmask); - val = FB_READL(dst) & start_mask; - shift = start_index; - } - while (n--) { - if (p->fix.visual == FB_VISUAL_TRUECOLOR || - p->fix.visual == FB_VISUAL_DIRECTCOLOR ) - color = palette[*src]; - else - color = *src; - color <<= FB_LEFT_POS(p, bpp); - val |= FB_SHIFT_HIGH(p, color, shift ^ bswapmask); - if (shift >= null_bits) { - FB_WRITEL(val, dst++); - - val = (shift == null_bits) ? 0 : - FB_SHIFT_LOW(p, color, 32 - shift); - } - shift += bpp; - shift &= (32 - 1); - src++; - } - if (shift) { - u32 end_mask = fb_shifted_pixels_mask_u32(p, shift, - bswapmask); - - FB_WRITEL((FB_READL(dst) & end_mask) | val, dst); - } - dst1 += p->fix.line_length; - if (pitch_index) { - dst2 += p->fix.line_length; - dst1 = (u8 __iomem *)((long __force)dst2 & ~(sizeof(u32) - 1)); - - start_index += pitch_index; - start_index &= 32 - 1; - } - } -} - -static inline void slow_imageblit(const struct fb_image *image, struct fb_info *p, - u8 __iomem *dst1, u32 fgcolor, - u32 bgcolor, - u32 start_index, - u32 pitch_index) -{ - u32 shift, color = 0, bpp = p->var.bits_per_pixel; - u32 __iomem *dst, *dst2; - u32 val, pitch = p->fix.line_length; - u32 null_bits = 32 - bpp; - u32 spitch = (image->width+7)/8; - const u8 *src = image->data, *s; - u32 i, j, l; - u32 bswapmask = fb_compute_bswapmask(p); - - dst2 = (u32 __iomem *) dst1; - fgcolor <<= FB_LEFT_POS(p, bpp); - bgcolor <<= FB_LEFT_POS(p, bpp); - - for (i = image->height; i--; ) { - shift = val = 0; - l = 8; - j = image->width; - dst = (u32 __iomem *) dst1; - s = src; - - /* write leading bits */ - if (start_index) { - u32 start_mask = ~fb_shifted_pixels_mask_u32(p, - start_index, bswapmask); - val = FB_READL(dst) & start_mask; - shift = start_index; - } - - while (j--) { - l--; - color = (*s & (1 << l)) ? fgcolor : bgcolor; - val |= FB_SHIFT_HIGH(p, color, shift ^ bswapmask); - - /* Did the bitshift spill bits to the next long? */ - if (shift >= null_bits) { - FB_WRITEL(val, dst++); - val = (shift == null_bits) ? 0 : - FB_SHIFT_LOW(p, color, 32 - shift); - } - shift += bpp; - shift &= (32 - 1); - if (!l) { l = 8; s++; } - } - - /* write trailing bits */ - if (shift) { - u32 end_mask = fb_shifted_pixels_mask_u32(p, shift, - bswapmask); - - FB_WRITEL((FB_READL(dst) & end_mask) | val, dst); - } - - dst1 += pitch; - src += spitch; - if (pitch_index) { - dst2 += pitch; - dst1 = (u8 __iomem *)((long __force)dst2 & ~(sizeof(u32) - 1)); - start_index += pitch_index; - start_index &= 32 - 1; - } - - } -} - -/* - * fast_imageblit - optimized monochrome color expansion - * - * Only if: bits_per_pixel == 8, 16, or 32 - * image->width is divisible by pixel/dword (ppw); - * fix->line_legth is divisible by 4; - * beginning and end of a scanline is dword aligned - */ -static inline void fast_imageblit(const struct fb_image *image, struct fb_info *p, - u8 __iomem *dst1, u32 fgcolor, - u32 bgcolor) -{ - u32 fgx = fgcolor, bgx = bgcolor, bpp = p->var.bits_per_pixel; - u32 ppw = 32/bpp, spitch = (image->width + 7)/8; - u32 bit_mask, end_mask, eorx, shift; - const char *s = image->data, *src; - u32 __iomem *dst; - const u32 *tab = NULL; - int i, j, k; - - switch (bpp) { - case 8: - tab = fb_be_math(p) ? cfb_tab8_be : cfb_tab8_le; - break; - case 16: - tab = fb_be_math(p) ? cfb_tab16_be : cfb_tab16_le; - break; - case 32: - default: - tab = cfb_tab32; - break; - } - - for (i = ppw-1; i--; ) { - fgx <<= bpp; - bgx <<= bpp; - fgx |= fgcolor; - bgx |= bgcolor; - } - - bit_mask = (1 << ppw) - 1; - eorx = fgx ^ bgx; - k = image->width/ppw; - - for (i = image->height; i--; ) { - dst = (u32 __iomem *) dst1, shift = 8; src = s; - - for (j = k; j--; ) { - shift -= ppw; - end_mask = tab[(*src >> shift) & bit_mask]; - FB_WRITEL((end_mask & eorx)^bgx, dst++); - if (!shift) { shift = 8; src++; } - } - dst1 += p->fix.line_length; - s += spitch; - } -} - -void cfb_imageblit(struct fb_info *p, const struct fb_image *image) -{ - u32 fgcolor, bgcolor, start_index, bitstart, pitch_index = 0; - u32 bpl = sizeof(u32), bpp = p->var.bits_per_pixel; - u32 width = image->width; - u32 dx = image->dx, dy = image->dy; - u8 __iomem *dst1; - - if (p->state != FBINFO_STATE_RUNNING) - return; - - bitstart = (dy * p->fix.line_length * 8) + (dx * bpp); - start_index = bitstart & (32 - 1); - pitch_index = (p->fix.line_length & (bpl - 1)) * 8; - - bitstart /= 8; - bitstart &= ~(bpl - 1); - dst1 = p->screen_base + bitstart; - - if (p->fbops->fb_sync) - p->fbops->fb_sync(p); - - if (image->depth == 1) { - if (p->fix.visual == FB_VISUAL_TRUECOLOR || - p->fix.visual == FB_VISUAL_DIRECTCOLOR) { - fgcolor = ((u32*)(p->pseudo_palette))[image->fg_color]; - bgcolor = ((u32*)(p->pseudo_palette))[image->bg_color]; - } else { - fgcolor = image->fg_color; - bgcolor = image->bg_color; - } - - if (32 % bpp == 0 && !start_index && !pitch_index && - ((width & (32/bpp-1)) == 0) && - bpp >= 8 && bpp <= 32) - fast_imageblit(image, p, dst1, fgcolor, bgcolor); - else - slow_imageblit(image, p, dst1, fgcolor, bgcolor, - start_index, pitch_index); - } else - color_imageblit(image, p, dst1, start_index, pitch_index); -} - -EXPORT_SYMBOL(cfb_imageblit); - -MODULE_AUTHOR("James Simmons "); -MODULE_DESCRIPTION("Generic software accelerated imaging drawing"); -MODULE_LICENSE("GPL"); - diff --git a/drivers/video/fbdev/core/Makefile b/drivers/video/fbdev/core/Makefile new file mode 100644 index 00000000000..fa306538dac --- /dev/null +++ b/drivers/video/fbdev/core/Makefile @@ -0,0 +1,16 @@ +obj-y += fb_notify.o +obj-$(CONFIG_FB) += fb.o +fb-y := fbmem.o fbmon.o fbcmap.o fbsysfs.o \ + modedb.o fbcvt.o +fb-objs := $(fb-y) + +obj-$(CONFIG_FB_CFB_FILLRECT) += cfbfillrect.o +obj-$(CONFIG_FB_CFB_COPYAREA) += cfbcopyarea.o +obj-$(CONFIG_FB_CFB_IMAGEBLIT) += cfbimgblt.o +obj-$(CONFIG_FB_SYS_FILLRECT) += sysfillrect.o +obj-$(CONFIG_FB_SYS_COPYAREA) += syscopyarea.o +obj-$(CONFIG_FB_SYS_IMAGEBLIT) += sysimgblt.o +obj-$(CONFIG_FB_SYS_FOPS) += fb_sys_fops.o +obj-$(CONFIG_FB_SVGALIB) += svgalib.o +obj-$(CONFIG_FB_DDC) += fb_ddc.o +obj-$(CONFIG_FB_DEFERRED_IO) += fb_defio.o diff --git a/drivers/video/fbdev/core/cfbcopyarea.c b/drivers/video/fbdev/core/cfbcopyarea.c new file mode 100644 index 00000000000..bcb57235fcc --- /dev/null +++ b/drivers/video/fbdev/core/cfbcopyarea.c @@ -0,0 +1,434 @@ +/* + * Generic function for frame buffer with packed pixels of any depth. + * + * Copyright (C) 1999-2005 James Simmons + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + * + * NOTES: + * + * This is for cfb packed pixels. Iplan and such are incorporated in the + * drivers that need them. + * + * FIXME + * + * Also need to add code to deal with cards endians that are different than + * the native cpu endians. I also need to deal with MSB position in the word. + * + * The two functions or copying forward and backward could be split up like + * the ones for filling, i.e. in aligned and unaligned versions. This would + * help moving some redundant computations and branches out of the loop, too. + */ + +#include +#include +#include +#include +#include +#include +#include "fb_draw.h" + +#if BITS_PER_LONG == 32 +# define FB_WRITEL fb_writel +# define FB_READL fb_readl +#else +# define FB_WRITEL fb_writeq +# define FB_READL fb_readq +#endif + + /* + * Generic bitwise copy algorithm + */ + +static void +bitcpy(struct fb_info *p, unsigned long __iomem *dst, unsigned dst_idx, + const unsigned long __iomem *src, unsigned src_idx, int bits, + unsigned n, u32 bswapmask) +{ + unsigned long first, last; + int const shift = dst_idx-src_idx; + +#if 0 + /* + * If you suspect bug in this function, compare it with this simple + * memmove implementation. + */ + fb_memmove((char *)dst + ((dst_idx & (bits - 1))) / 8, + (char *)src + ((src_idx & (bits - 1))) / 8, n / 8); + return; +#endif + + first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask); + last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask); + + if (!shift) { + // Same alignment for source and dest + + if (dst_idx+n <= bits) { + // Single word + if (last) + first &= last; + FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst); + } else { + // Multiple destination words + + // Leading bits + if (first != ~0UL) { + FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst); + dst++; + src++; + n -= bits - dst_idx; + } + + // Main chunk + n /= bits; + while (n >= 8) { + FB_WRITEL(FB_READL(src++), dst++); + FB_WRITEL(FB_READL(src++), dst++); + FB_WRITEL(FB_READL(src++), dst++); + FB_WRITEL(FB_READL(src++), dst++); + FB_WRITEL(FB_READL(src++), dst++); + FB_WRITEL(FB_READL(src++), dst++); + FB_WRITEL(FB_READL(src++), dst++); + FB_WRITEL(FB_READL(src++), dst++); + n -= 8; + } + while (n--) + FB_WRITEL(FB_READL(src++), dst++); + + // Trailing bits + if (last) + FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst); + } + } else { + /* Different alignment for source and dest */ + unsigned long d0, d1; + int m; + + int const left = shift & (bits - 1); + int const right = -shift & (bits - 1); + + if (dst_idx+n <= bits) { + // Single destination word + if (last) + first &= last; + d0 = FB_READL(src); + d0 = fb_rev_pixels_in_long(d0, bswapmask); + if (shift > 0) { + // Single source word + d0 <<= left; + } else if (src_idx+n <= bits) { + // Single source word + d0 >>= right; + } else { + // 2 source words + d1 = FB_READL(src + 1); + d1 = fb_rev_pixels_in_long(d1, bswapmask); + d0 = d0 >> right | d1 << left; + } + d0 = fb_rev_pixels_in_long(d0, bswapmask); + FB_WRITEL(comp(d0, FB_READL(dst), first), dst); + } else { + // Multiple destination words + /** We must always remember the last value read, because in case + SRC and DST overlap bitwise (e.g. when moving just one pixel in + 1bpp), we always collect one full long for DST and that might + overlap with the current long from SRC. We store this value in + 'd0'. */ + d0 = FB_READL(src++); + d0 = fb_rev_pixels_in_long(d0, bswapmask); + // Leading bits + if (shift > 0) { + // Single source word + d1 = d0; + d0 <<= left; + n -= bits - dst_idx; + } else { + // 2 source words + d1 = FB_READL(src++); + d1 = fb_rev_pixels_in_long(d1, bswapmask); + + d0 = d0 >> right | d1 << left; + n -= bits - dst_idx; + } + d0 = fb_rev_pixels_in_long(d0, bswapmask); + FB_WRITEL(comp(d0, FB_READL(dst), first), dst); + d0 = d1; + dst++; + + // Main chunk + m = n % bits; + n /= bits; + while ((n >= 4) && !bswapmask) { + d1 = FB_READL(src++); + FB_WRITEL(d0 >> right | d1 << left, dst++); + d0 = d1; + d1 = FB_READL(src++); + FB_WRITEL(d0 >> right | d1 << left, dst++); + d0 = d1; + d1 = FB_READL(src++); + FB_WRITEL(d0 >> right | d1 << left, dst++); + d0 = d1; + d1 = FB_READL(src++); + FB_WRITEL(d0 >> right | d1 << left, dst++); + d0 = d1; + n -= 4; + } + while (n--) { + d1 = FB_READL(src++); + d1 = fb_rev_pixels_in_long(d1, bswapmask); + d0 = d0 >> right | d1 << left; + d0 = fb_rev_pixels_in_long(d0, bswapmask); + FB_WRITEL(d0, dst++); + d0 = d1; + } + + // Trailing bits + if (m) { + if (m <= bits - right) { + // Single source word + d0 >>= right; + } else { + // 2 source words + d1 = FB_READL(src); + d1 = fb_rev_pixels_in_long(d1, + bswapmask); + d0 = d0 >> right | d1 << left; + } + d0 = fb_rev_pixels_in_long(d0, bswapmask); + FB_WRITEL(comp(d0, FB_READL(dst), last), dst); + } + } + } +} + + /* + * Generic bitwise copy algorithm, operating backward + */ + +static void +bitcpy_rev(struct fb_info *p, unsigned long __iomem *dst, unsigned dst_idx, + const unsigned long __iomem *src, unsigned src_idx, int bits, + unsigned n, u32 bswapmask) +{ + unsigned long first, last; + int shift; + +#if 0 + /* + * If you suspect bug in this function, compare it with this simple + * memmove implementation. + */ + fb_memmove((char *)dst + ((dst_idx & (bits - 1))) / 8, + (char *)src + ((src_idx & (bits - 1))) / 8, n / 8); + return; +#endif + + dst += (dst_idx + n - 1) / bits; + src += (src_idx + n - 1) / bits; + dst_idx = (dst_idx + n - 1) % bits; + src_idx = (src_idx + n - 1) % bits; + + shift = dst_idx-src_idx; + + first = ~fb_shifted_pixels_mask_long(p, (dst_idx + 1) % bits, bswapmask); + last = fb_shifted_pixels_mask_long(p, (bits + dst_idx + 1 - n) % bits, bswapmask); + + if (!shift) { + // Same alignment for source and dest + + if ((unsigned long)dst_idx+1 >= n) { + // Single word + if (first) + last &= first; + FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst); + } else { + // Multiple destination words + + // Leading bits + if (first) { + FB_WRITEL( comp( FB_READL(src), FB_READL(dst), first), dst); + dst--; + src--; + n -= dst_idx+1; + } + + // Main chunk + n /= bits; + while (n >= 8) { + FB_WRITEL(FB_READL(src--), dst--); + FB_WRITEL(FB_READL(src--), dst--); + FB_WRITEL(FB_READL(src--), dst--); + FB_WRITEL(FB_READL(src--), dst--); + FB_WRITEL(FB_READL(src--), dst--); + FB_WRITEL(FB_READL(src--), dst--); + FB_WRITEL(FB_READL(src--), dst--); + FB_WRITEL(FB_READL(src--), dst--); + n -= 8; + } + while (n--) + FB_WRITEL(FB_READL(src--), dst--); + + // Trailing bits + if (last != -1UL) + FB_WRITEL( comp( FB_READL(src), FB_READL(dst), last), dst); + } + } else { + // Different alignment for source and dest + unsigned long d0, d1; + int m; + + int const left = shift & (bits-1); + int const right = -shift & (bits-1); + + if ((unsigned long)dst_idx+1 >= n) { + // Single destination word + if (first) + last &= first; + d0 = FB_READL(src); + if (shift < 0) { + // Single source word + d0 >>= right; + } else if (1+(unsigned long)src_idx >= n) { + // Single source word + d0 <<= left; + } else { + // 2 source words + d1 = FB_READL(src - 1); + d1 = fb_rev_pixels_in_long(d1, bswapmask); + d0 = d0 << left | d1 >> right; + } + d0 = fb_rev_pixels_in_long(d0, bswapmask); + FB_WRITEL(comp(d0, FB_READL(dst), last), dst); + } else { + // Multiple destination words + /** We must always remember the last value read, because in case + SRC and DST overlap bitwise (e.g. when moving just one pixel in + 1bpp), we always collect one full long for DST and that might + overlap with the current long from SRC. We store this value in + 'd0'. */ + + d0 = FB_READL(src--); + d0 = fb_rev_pixels_in_long(d0, bswapmask); + // Leading bits + if (shift < 0) { + // Single source word + d1 = d0; + d0 >>= right; + } else { + // 2 source words + d1 = FB_READL(src--); + d1 = fb_rev_pixels_in_long(d1, bswapmask); + d0 = d0 << left | d1 >> right; + } + d0 = fb_rev_pixels_in_long(d0, bswapmask); + FB_WRITEL(comp(d0, FB_READL(dst), first), dst); + d0 = d1; + dst--; + n -= dst_idx+1; + + // Main chunk + m = n % bits; + n /= bits; + while ((n >= 4) && !bswapmask) { + d1 = FB_READL(src--); + FB_WRITEL(d0 << left | d1 >> right, dst--); + d0 = d1; + d1 = FB_READL(src--); + FB_WRITEL(d0 << left | d1 >> right, dst--); + d0 = d1; + d1 = FB_READL(src--); + FB_WRITEL(d0 << left | d1 >> right, dst--); + d0 = d1; + d1 = FB_READL(src--); + FB_WRITEL(d0 << left | d1 >> right, dst--); + d0 = d1; + n -= 4; + } + while (n--) { + d1 = FB_READL(src--); + d1 = fb_rev_pixels_in_long(d1, bswapmask); + d0 = d0 << left | d1 >> right; + d0 = fb_rev_pixels_in_long(d0, bswapmask); + FB_WRITEL(d0, dst--); + d0 = d1; + } + + // Trailing bits + if (m) { + if (m <= bits - left) { + // Single source word + d0 <<= left; + } else { + // 2 source words + d1 = FB_READL(src); + d1 = fb_rev_pixels_in_long(d1, + bswapmask); + d0 = d0 << left | d1 >> right; + } + d0 = fb_rev_pixels_in_long(d0, bswapmask); + FB_WRITEL(comp(d0, FB_READL(dst), last), dst); + } + } + } +} + +void cfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) +{ + u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy; + u32 height = area->height, width = area->width; + unsigned long const bits_per_line = p->fix.line_length*8u; + unsigned long __iomem *base = NULL; + int bits = BITS_PER_LONG, bytes = bits >> 3; + unsigned dst_idx = 0, src_idx = 0, rev_copy = 0; + u32 bswapmask = fb_compute_bswapmask(p); + + if (p->state != FBINFO_STATE_RUNNING) + return; + + /* if the beginning of the target area might overlap with the end of + the source area, be have to copy the area reverse. */ + if ((dy == sy && dx > sx) || (dy > sy)) { + dy += height; + sy += height; + rev_copy = 1; + } + + // split the base of the framebuffer into a long-aligned address and the + // index of the first bit + base = (unsigned long __iomem *)((unsigned long)p->screen_base & ~(bytes-1)); + dst_idx = src_idx = 8*((unsigned long)p->screen_base & (bytes-1)); + // add offset of source and target area + dst_idx += dy*bits_per_line + dx*p->var.bits_per_pixel; + src_idx += sy*bits_per_line + sx*p->var.bits_per_pixel; + + if (p->fbops->fb_sync) + p->fbops->fb_sync(p); + + if (rev_copy) { + while (height--) { + dst_idx -= bits_per_line; + src_idx -= bits_per_line; + bitcpy_rev(p, base + (dst_idx / bits), dst_idx % bits, + base + (src_idx / bits), src_idx % bits, bits, + width*p->var.bits_per_pixel, bswapmask); + } + } else { + while (height--) { + bitcpy(p, base + (dst_idx / bits), dst_idx % bits, + base + (src_idx / bits), src_idx % bits, bits, + width*p->var.bits_per_pixel, bswapmask); + dst_idx += bits_per_line; + src_idx += bits_per_line; + } + } +} + +EXPORT_SYMBOL(cfb_copyarea); + +MODULE_AUTHOR("James Simmons "); +MODULE_DESCRIPTION("Generic software accelerated copyarea"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/video/fbdev/core/cfbfillrect.c b/drivers/video/fbdev/core/cfbfillrect.c new file mode 100644 index 00000000000..ba9f58b2a5e --- /dev/null +++ b/drivers/video/fbdev/core/cfbfillrect.c @@ -0,0 +1,371 @@ +/* + * Generic fillrect for frame buffers with packed pixels of any depth. + * + * Copyright (C) 2000 James Simmons (jsimmons@linux-fbdev.org) + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + * + * NOTES: + * + * Also need to add code to deal with cards endians that are different than + * the native cpu endians. I also need to deal with MSB position in the word. + * + */ +#include +#include +#include +#include +#include "fb_draw.h" + +#if BITS_PER_LONG == 32 +# define FB_WRITEL fb_writel +# define FB_READL fb_readl +#else +# define FB_WRITEL fb_writeq +# define FB_READL fb_readq +#endif + + /* + * Aligned pattern fill using 32/64-bit memory accesses + */ + +static void +bitfill_aligned(struct fb_info *p, unsigned long __iomem *dst, int dst_idx, + unsigned long pat, unsigned n, int bits, u32 bswapmask) +{ + unsigned long first, last; + + if (!n) + return; + + first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask); + last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask); + + if (dst_idx+n <= bits) { + // Single word + if (last) + first &= last; + FB_WRITEL(comp(pat, FB_READL(dst), first), dst); + } else { + // Multiple destination words + + // Leading bits + if (first!= ~0UL) { + FB_WRITEL(comp(pat, FB_READL(dst), first), dst); + dst++; + n -= bits - dst_idx; + } + + // Main chunk + n /= bits; + while (n >= 8) { + FB_WRITEL(pat, dst++); + FB_WRITEL(pat, dst++); + FB_WRITEL(pat, dst++); + FB_WRITEL(pat, dst++); + FB_WRITEL(pat, dst++); + FB_WRITEL(pat, dst++); + FB_WRITEL(pat, dst++); + FB_WRITEL(pat, dst++); + n -= 8; + } + while (n--) + FB_WRITEL(pat, dst++); + + // Trailing bits + if (last) + FB_WRITEL(comp(pat, FB_READL(dst), last), dst); + } +} + + + /* + * Unaligned generic pattern fill using 32/64-bit memory accesses + * The pattern must have been expanded to a full 32/64-bit value + * Left/right are the appropriate shifts to convert to the pattern to be + * used for the next 32/64-bit word + */ + +static void +bitfill_unaligned(struct fb_info *p, unsigned long __iomem *dst, int dst_idx, + unsigned long pat, int left, int right, unsigned n, int bits) +{ + unsigned long first, last; + + if (!n) + return; + + first = FB_SHIFT_HIGH(p, ~0UL, dst_idx); + last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits)); + + if (dst_idx+n <= bits) { + // Single word + if (last) + first &= last; + FB_WRITEL(comp(pat, FB_READL(dst), first), dst); + } else { + // Multiple destination words + // Leading bits + if (first) { + FB_WRITEL(comp(pat, FB_READL(dst), first), dst); + dst++; + pat = pat << left | pat >> right; + n -= bits - dst_idx; + } + + // Main chunk + n /= bits; + while (n >= 4) { + FB_WRITEL(pat, dst++); + pat = pat << left | pat >> right; + FB_WRITEL(pat, dst++); + pat = pat << left | pat >> right; + FB_WRITEL(pat, dst++); + pat = pat << left | pat >> right; + FB_WRITEL(pat, dst++); + pat = pat << left | pat >> right; + n -= 4; + } + while (n--) { + FB_WRITEL(pat, dst++); + pat = pat << left | pat >> right; + } + + // Trailing bits + if (last) + FB_WRITEL(comp(pat, FB_READL(dst), last), dst); + } +} + + /* + * Aligned pattern invert using 32/64-bit memory accesses + */ +static void +bitfill_aligned_rev(struct fb_info *p, unsigned long __iomem *dst, + int dst_idx, unsigned long pat, unsigned n, int bits, + u32 bswapmask) +{ + unsigned long val = pat, dat; + unsigned long first, last; + + if (!n) + return; + + first = fb_shifted_pixels_mask_long(p, dst_idx, bswapmask); + last = ~fb_shifted_pixels_mask_long(p, (dst_idx+n) % bits, bswapmask); + + if (dst_idx+n <= bits) { + // Single word + if (last) + first &= last; + dat = FB_READL(dst); + FB_WRITEL(comp(dat ^ val, dat, first), dst); + } else { + // Multiple destination words + // Leading bits + if (first!=0UL) { + dat = FB_READL(dst); + FB_WRITEL(comp(dat ^ val, dat, first), dst); + dst++; + n -= bits - dst_idx; + } + + // Main chunk + n /= bits; + while (n >= 8) { + FB_WRITEL(FB_READL(dst) ^ val, dst); + dst++; + FB_WRITEL(FB_READL(dst) ^ val, dst); + dst++; + FB_WRITEL(FB_READL(dst) ^ val, dst); + dst++; + FB_WRITEL(FB_READL(dst) ^ val, dst); + dst++; + FB_WRITEL(FB_READL(dst) ^ val, dst); + dst++; + FB_WRITEL(FB_READL(dst) ^ val, dst); + dst++; + FB_WRITEL(FB_READL(dst) ^ val, dst); + dst++; + FB_WRITEL(FB_READL(dst) ^ val, dst); + dst++; + n -= 8; + } + while (n--) { + FB_WRITEL(FB_READL(dst) ^ val, dst); + dst++; + } + // Trailing bits + if (last) { + dat = FB_READL(dst); + FB_WRITEL(comp(dat ^ val, dat, last), dst); + } + } +} + + + /* + * Unaligned generic pattern invert using 32/64-bit memory accesses + * The pattern must have been expanded to a full 32/64-bit value + * Left/right are the appropriate shifts to convert to the pattern to be + * used for the next 32/64-bit word + */ + +static void +bitfill_unaligned_rev(struct fb_info *p, unsigned long __iomem *dst, + int dst_idx, unsigned long pat, int left, int right, + unsigned n, int bits) +{ + unsigned long first, last, dat; + + if (!n) + return; + + first = FB_SHIFT_HIGH(p, ~0UL, dst_idx); + last = ~(FB_SHIFT_HIGH(p, ~0UL, (dst_idx+n) % bits)); + + if (dst_idx+n <= bits) { + // Single word + if (last) + first &= last; + dat = FB_READL(dst); + FB_WRITEL(comp(dat ^ pat, dat, first), dst); + } else { + // Multiple destination words + + // Leading bits + if (first != 0UL) { + dat = FB_READL(dst); + FB_WRITEL(comp(dat ^ pat, dat, first), dst); + dst++; + pat = pat << left | pat >> right; + n -= bits - dst_idx; + } + + // Main chunk + n /= bits; + while (n >= 4) { + FB_WRITEL(FB_READL(dst) ^ pat, dst); + dst++; + pat = pat << left | pat >> right; + FB_WRITEL(FB_READL(dst) ^ pat, dst); + dst++; + pat = pat << left | pat >> right; + FB_WRITEL(FB_READL(dst) ^ pat, dst); + dst++; + pat = pat << left | pat >> right; + FB_WRITEL(FB_READL(dst) ^ pat, dst); + dst++; + pat = pat << left | pat >> right; + n -= 4; + } + while (n--) { + FB_WRITEL(FB_READL(dst) ^ pat, dst); + dst++; + pat = pat << left | pat >> right; + } + + // Trailing bits + if (last) { + dat = FB_READL(dst); + FB_WRITEL(comp(dat ^ pat, dat, last), dst); + } + } +} + +void cfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect) +{ + unsigned long pat, pat2, fg; + unsigned long width = rect->width, height = rect->height; + int bits = BITS_PER_LONG, bytes = bits >> 3; + u32 bpp = p->var.bits_per_pixel; + unsigned long __iomem *dst; + int dst_idx, left; + + if (p->state != FBINFO_STATE_RUNNING) + return; + + if (p->fix.visual == FB_VISUAL_TRUECOLOR || + p->fix.visual == FB_VISUAL_DIRECTCOLOR ) + fg = ((u32 *) (p->pseudo_palette))[rect->color]; + else + fg = rect->color; + + pat = pixel_to_pat(bpp, fg); + + dst = (unsigned long __iomem *)((unsigned long)p->screen_base & ~(bytes-1)); + dst_idx = ((unsigned long)p->screen_base & (bytes - 1))*8; + dst_idx += rect->dy*p->fix.line_length*8+rect->dx*bpp; + /* FIXME For now we support 1-32 bpp only */ + left = bits % bpp; + if (p->fbops->fb_sync) + p->fbops->fb_sync(p); + if (!left) { + u32 bswapmask = fb_compute_bswapmask(p); + void (*fill_op32)(struct fb_info *p, + unsigned long __iomem *dst, int dst_idx, + unsigned long pat, unsigned n, int bits, + u32 bswapmask) = NULL; + + switch (rect->rop) { + case ROP_XOR: + fill_op32 = bitfill_aligned_rev; + break; + case ROP_COPY: + fill_op32 = bitfill_aligned; + break; + default: + printk( KERN_ERR "cfb_fillrect(): unknown rop, defaulting to ROP_COPY\n"); + fill_op32 = bitfill_aligned; + break; + } + while (height--) { + dst += dst_idx >> (ffs(bits) - 1); + dst_idx &= (bits - 1); + fill_op32(p, dst, dst_idx, pat, width*bpp, bits, + bswapmask); + dst_idx += p->fix.line_length*8; + } + } else { + int right, r; + void (*fill_op)(struct fb_info *p, unsigned long __iomem *dst, + int dst_idx, unsigned long pat, int left, + int right, unsigned n, int bits) = NULL; +#ifdef __LITTLE_ENDIAN + right = left; + left = bpp - right; +#else + right = bpp - left; +#endif + switch (rect->rop) { + case ROP_XOR: + fill_op = bitfill_unaligned_rev; + break; + case ROP_COPY: + fill_op = bitfill_unaligned; + break; + default: + printk(KERN_ERR "cfb_fillrect(): unknown rop, defaulting to ROP_COPY\n"); + fill_op = bitfill_unaligned; + break; + } + while (height--) { + dst += dst_idx / bits; + dst_idx &= (bits - 1); + r = dst_idx % bpp; + /* rotate pattern to the correct start position */ + pat2 = le_long_to_cpu(rolx(cpu_to_le_long(pat), r, bpp)); + fill_op(p, dst, dst_idx, pat2, left, right, + width*bpp, bits); + dst_idx += p->fix.line_length*8; + } + } +} + +EXPORT_SYMBOL(cfb_fillrect); + +MODULE_AUTHOR("James Simmons "); +MODULE_DESCRIPTION("Generic software accelerated fill rectangle"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/fbdev/core/cfbimgblt.c b/drivers/video/fbdev/core/cfbimgblt.c new file mode 100644 index 00000000000..a2bb276a8b2 --- /dev/null +++ b/drivers/video/fbdev/core/cfbimgblt.c @@ -0,0 +1,313 @@ +/* + * Generic BitBLT function for frame buffer with packed pixels of any depth. + * + * Copyright (C) June 1999 James Simmons + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + * + * NOTES: + * + * This function copys a image from system memory to video memory. The + * image can be a bitmap where each 0 represents the background color and + * each 1 represents the foreground color. Great for font handling. It can + * also be a color image. This is determined by image_depth. The color image + * must be laid out exactly in the same format as the framebuffer. Yes I know + * their are cards with hardware that coverts images of various depths to the + * framebuffer depth. But not every card has this. All images must be rounded + * up to the nearest byte. For example a bitmap 12 bits wide must be two + * bytes width. + * + * Tony: + * Incorporate mask tables similar to fbcon-cfb*.c in 2.4 API. This speeds + * up the code significantly. + * + * Code for depths not multiples of BITS_PER_LONG is still kludgy, which is + * still processed a bit at a time. + * + * Also need to add code to deal with cards endians that are different than + * the native cpu endians. I also need to deal with MSB position in the word. + */ +#include +#include +#include +#include +#include "fb_draw.h" + +#define DEBUG + +#ifdef DEBUG +#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt,__func__,## args) +#else +#define DPRINTK(fmt, args...) +#endif + +static const u32 cfb_tab8_be[] = { + 0x00000000,0x000000ff,0x0000ff00,0x0000ffff, + 0x00ff0000,0x00ff00ff,0x00ffff00,0x00ffffff, + 0xff000000,0xff0000ff,0xff00ff00,0xff00ffff, + 0xffff0000,0xffff00ff,0xffffff00,0xffffffff +}; + +static const u32 cfb_tab8_le[] = { + 0x00000000,0xff000000,0x00ff0000,0xffff0000, + 0x0000ff00,0xff00ff00,0x00ffff00,0xffffff00, + 0x000000ff,0xff0000ff,0x00ff00ff,0xffff00ff, + 0x0000ffff,0xff00ffff,0x00ffffff,0xffffffff +}; + +static const u32 cfb_tab16_be[] = { + 0x00000000, 0x0000ffff, 0xffff0000, 0xffffffff +}; + +static const u32 cfb_tab16_le[] = { + 0x00000000, 0xffff0000, 0x0000ffff, 0xffffffff +}; + +static const u32 cfb_tab32[] = { + 0x00000000, 0xffffffff +}; + +#define FB_WRITEL fb_writel +#define FB_READL fb_readl + +static inline void color_imageblit(const struct fb_image *image, + struct fb_info *p, u8 __iomem *dst1, + u32 start_index, + u32 pitch_index) +{ + /* Draw the penguin */ + u32 __iomem *dst, *dst2; + u32 color = 0, val, shift; + int i, n, bpp = p->var.bits_per_pixel; + u32 null_bits = 32 - bpp; + u32 *palette = (u32 *) p->pseudo_palette; + const u8 *src = image->data; + u32 bswapmask = fb_compute_bswapmask(p); + + dst2 = (u32 __iomem *) dst1; + for (i = image->height; i--; ) { + n = image->width; + dst = (u32 __iomem *) dst1; + shift = 0; + val = 0; + + if (start_index) { + u32 start_mask = ~fb_shifted_pixels_mask_u32(p, + start_index, bswapmask); + val = FB_READL(dst) & start_mask; + shift = start_index; + } + while (n--) { + if (p->fix.visual == FB_VISUAL_TRUECOLOR || + p->fix.visual == FB_VISUAL_DIRECTCOLOR ) + color = palette[*src]; + else + color = *src; + color <<= FB_LEFT_POS(p, bpp); + val |= FB_SHIFT_HIGH(p, color, shift ^ bswapmask); + if (shift >= null_bits) { + FB_WRITEL(val, dst++); + + val = (shift == null_bits) ? 0 : + FB_SHIFT_LOW(p, color, 32 - shift); + } + shift += bpp; + shift &= (32 - 1); + src++; + } + if (shift) { + u32 end_mask = fb_shifted_pixels_mask_u32(p, shift, + bswapmask); + + FB_WRITEL((FB_READL(dst) & end_mask) | val, dst); + } + dst1 += p->fix.line_length; + if (pitch_index) { + dst2 += p->fix.line_length; + dst1 = (u8 __iomem *)((long __force)dst2 & ~(sizeof(u32) - 1)); + + start_index += pitch_index; + start_index &= 32 - 1; + } + } +} + +static inline void slow_imageblit(const struct fb_image *image, struct fb_info *p, + u8 __iomem *dst1, u32 fgcolor, + u32 bgcolor, + u32 start_index, + u32 pitch_index) +{ + u32 shift, color = 0, bpp = p->var.bits_per_pixel; + u32 __iomem *dst, *dst2; + u32 val, pitch = p->fix.line_length; + u32 null_bits = 32 - bpp; + u32 spitch = (image->width+7)/8; + const u8 *src = image->data, *s; + u32 i, j, l; + u32 bswapmask = fb_compute_bswapmask(p); + + dst2 = (u32 __iomem *) dst1; + fgcolor <<= FB_LEFT_POS(p, bpp); + bgcolor <<= FB_LEFT_POS(p, bpp); + + for (i = image->height; i--; ) { + shift = val = 0; + l = 8; + j = image->width; + dst = (u32 __iomem *) dst1; + s = src; + + /* write leading bits */ + if (start_index) { + u32 start_mask = ~fb_shifted_pixels_mask_u32(p, + start_index, bswapmask); + val = FB_READL(dst) & start_mask; + shift = start_index; + } + + while (j--) { + l--; + color = (*s & (1 << l)) ? fgcolor : bgcolor; + val |= FB_SHIFT_HIGH(p, color, shift ^ bswapmask); + + /* Did the bitshift spill bits to the next long? */ + if (shift >= null_bits) { + FB_WRITEL(val, dst++); + val = (shift == null_bits) ? 0 : + FB_SHIFT_LOW(p, color, 32 - shift); + } + shift += bpp; + shift &= (32 - 1); + if (!l) { l = 8; s++; } + } + + /* write trailing bits */ + if (shift) { + u32 end_mask = fb_shifted_pixels_mask_u32(p, shift, + bswapmask); + + FB_WRITEL((FB_READL(dst) & end_mask) | val, dst); + } + + dst1 += pitch; + src += spitch; + if (pitch_index) { + dst2 += pitch; + dst1 = (u8 __iomem *)((long __force)dst2 & ~(sizeof(u32) - 1)); + start_index += pitch_index; + start_index &= 32 - 1; + } + + } +} + +/* + * fast_imageblit - optimized monochrome color expansion + * + * Only if: bits_per_pixel == 8, 16, or 32 + * image->width is divisible by pixel/dword (ppw); + * fix->line_legth is divisible by 4; + * beginning and end of a scanline is dword aligned + */ +static inline void fast_imageblit(const struct fb_image *image, struct fb_info *p, + u8 __iomem *dst1, u32 fgcolor, + u32 bgcolor) +{ + u32 fgx = fgcolor, bgx = bgcolor, bpp = p->var.bits_per_pixel; + u32 ppw = 32/bpp, spitch = (image->width + 7)/8; + u32 bit_mask, end_mask, eorx, shift; + const char *s = image->data, *src; + u32 __iomem *dst; + const u32 *tab = NULL; + int i, j, k; + + switch (bpp) { + case 8: + tab = fb_be_math(p) ? cfb_tab8_be : cfb_tab8_le; + break; + case 16: + tab = fb_be_math(p) ? cfb_tab16_be : cfb_tab16_le; + break; + case 32: + default: + tab = cfb_tab32; + break; + } + + for (i = ppw-1; i--; ) { + fgx <<= bpp; + bgx <<= bpp; + fgx |= fgcolor; + bgx |= bgcolor; + } + + bit_mask = (1 << ppw) - 1; + eorx = fgx ^ bgx; + k = image->width/ppw; + + for (i = image->height; i--; ) { + dst = (u32 __iomem *) dst1, shift = 8; src = s; + + for (j = k; j--; ) { + shift -= ppw; + end_mask = tab[(*src >> shift) & bit_mask]; + FB_WRITEL((end_mask & eorx)^bgx, dst++); + if (!shift) { shift = 8; src++; } + } + dst1 += p->fix.line_length; + s += spitch; + } +} + +void cfb_imageblit(struct fb_info *p, const struct fb_image *image) +{ + u32 fgcolor, bgcolor, start_index, bitstart, pitch_index = 0; + u32 bpl = sizeof(u32), bpp = p->var.bits_per_pixel; + u32 width = image->width; + u32 dx = image->dx, dy = image->dy; + u8 __iomem *dst1; + + if (p->state != FBINFO_STATE_RUNNING) + return; + + bitstart = (dy * p->fix.line_length * 8) + (dx * bpp); + start_index = bitstart & (32 - 1); + pitch_index = (p->fix.line_length & (bpl - 1)) * 8; + + bitstart /= 8; + bitstart &= ~(bpl - 1); + dst1 = p->screen_base + bitstart; + + if (p->fbops->fb_sync) + p->fbops->fb_sync(p); + + if (image->depth == 1) { + if (p->fix.visual == FB_VISUAL_TRUECOLOR || + p->fix.visual == FB_VISUAL_DIRECTCOLOR) { + fgcolor = ((u32*)(p->pseudo_palette))[image->fg_color]; + bgcolor = ((u32*)(p->pseudo_palette))[image->bg_color]; + } else { + fgcolor = image->fg_color; + bgcolor = image->bg_color; + } + + if (32 % bpp == 0 && !start_index && !pitch_index && + ((width & (32/bpp-1)) == 0) && + bpp >= 8 && bpp <= 32) + fast_imageblit(image, p, dst1, fgcolor, bgcolor); + else + slow_imageblit(image, p, dst1, fgcolor, bgcolor, + start_index, pitch_index); + } else + color_imageblit(image, p, dst1, start_index, pitch_index); +} + +EXPORT_SYMBOL(cfb_imageblit); + +MODULE_AUTHOR("James Simmons "); +MODULE_DESCRIPTION("Generic software accelerated imaging drawing"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/video/fbdev/core/fb_ddc.c b/drivers/video/fbdev/core/fb_ddc.c new file mode 100644 index 00000000000..94322ccfedd --- /dev/null +++ b/drivers/video/fbdev/core/fb_ddc.c @@ -0,0 +1,119 @@ +/* + * drivers/video/fb_ddc.c - DDC/EDID read support. + * + * Copyright (C) 2006 Dennis Munsie + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + +#include +#include +#include +#include +#include +#include + +#include "../edid.h" + +#define DDC_ADDR 0x50 + +static unsigned char *fb_do_probe_ddc_edid(struct i2c_adapter *adapter) +{ + unsigned char start = 0x0; + unsigned char *buf = kmalloc(EDID_LENGTH, GFP_KERNEL); + struct i2c_msg msgs[] = { + { + .addr = DDC_ADDR, + .flags = 0, + .len = 1, + .buf = &start, + }, { + .addr = DDC_ADDR, + .flags = I2C_M_RD, + .len = EDID_LENGTH, + .buf = buf, + } + }; + + if (!buf) { + dev_warn(&adapter->dev, "unable to allocate memory for EDID " + "block.\n"); + return NULL; + } + + if (i2c_transfer(adapter, msgs, 2) == 2) + return buf; + + dev_warn(&adapter->dev, "unable to read EDID block.\n"); + kfree(buf); + return NULL; +} + +unsigned char *fb_ddc_read(struct i2c_adapter *adapter) +{ + struct i2c_algo_bit_data *algo_data = adapter->algo_data; + unsigned char *edid = NULL; + int i, j; + + algo_data->setscl(algo_data->data, 1); + + for (i = 0; i < 3; i++) { + /* For some old monitors we need the + * following process to initialize/stop DDC + */ + algo_data->setsda(algo_data->data, 1); + msleep(13); + + algo_data->setscl(algo_data->data, 1); + for (j = 0; j < 5; j++) { + msleep(10); + if (algo_data->getscl(algo_data->data)) + break; + } + if (j == 5) + continue; + + algo_data->setsda(algo_data->data, 0); + msleep(15); + algo_data->setscl(algo_data->data, 0); + msleep(15); + algo_data->setsda(algo_data->data, 1); + msleep(15); + + /* Do the real work */ + edid = fb_do_probe_ddc_edid(adapter); + algo_data->setsda(algo_data->data, 0); + algo_data->setscl(algo_data->data, 0); + msleep(15); + + algo_data->setscl(algo_data->data, 1); + for (j = 0; j < 10; j++) { + msleep(10); + if (algo_data->getscl(algo_data->data)) + break; + } + + algo_data->setsda(algo_data->data, 1); + msleep(15); + algo_data->setscl(algo_data->data, 0); + algo_data->setsda(algo_data->data, 0); + if (edid) + break; + } + /* Release the DDC lines when done or the Apple Cinema HD display + * will switch off + */ + algo_data->setsda(algo_data->data, 1); + algo_data->setscl(algo_data->data, 1); + + adapter->class |= I2C_CLASS_DDC; + return edid; +} + +EXPORT_SYMBOL_GPL(fb_ddc_read); + +MODULE_AUTHOR("Dennis Munsie "); +MODULE_DESCRIPTION("DDC/EDID reading support"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/fbdev/core/fb_defio.c b/drivers/video/fbdev/core/fb_defio.c new file mode 100644 index 00000000000..900aa4ecd61 --- /dev/null +++ b/drivers/video/fbdev/core/fb_defio.c @@ -0,0 +1,245 @@ +/* + * linux/drivers/video/fb_defio.c + * + * Copyright (C) 2006 Jaya Kumar + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* to support deferred IO */ +#include +#include + +static struct page *fb_deferred_io_page(struct fb_info *info, unsigned long offs) +{ + void *screen_base = (void __force *) info->screen_base; + struct page *page; + + if (is_vmalloc_addr(screen_base + offs)) + page = vmalloc_to_page(screen_base + offs); + else + page = pfn_to_page((info->fix.smem_start + offs) >> PAGE_SHIFT); + + return page; +} + +/* this is to find and return the vmalloc-ed fb pages */ +static int fb_deferred_io_fault(struct vm_area_struct *vma, + struct vm_fault *vmf) +{ + unsigned long offset; + struct page *page; + struct fb_info *info = vma->vm_private_data; + + offset = vmf->pgoff << PAGE_SHIFT; + if (offset >= info->fix.smem_len) + return VM_FAULT_SIGBUS; + + page = fb_deferred_io_page(info, offset); + if (!page) + return VM_FAULT_SIGBUS; + + get_page(page); + + if (vma->vm_file) + page->mapping = vma->vm_file->f_mapping; + else + printk(KERN_ERR "no mapping available\n"); + + BUG_ON(!page->mapping); + page->index = vmf->pgoff; + + vmf->page = page; + return 0; +} + +int fb_deferred_io_fsync(struct file *file, loff_t start, loff_t end, int datasync) +{ + struct fb_info *info = file->private_data; + struct inode *inode = file_inode(file); + int err = filemap_write_and_wait_range(inode->i_mapping, start, end); + if (err) + return err; + + /* Skip if deferred io is compiled-in but disabled on this fbdev */ + if (!info->fbdefio) + return 0; + + mutex_lock(&inode->i_mutex); + /* Kill off the delayed work */ + cancel_delayed_work_sync(&info->deferred_work); + + /* Run it immediately */ + err = schedule_delayed_work(&info->deferred_work, 0); + mutex_unlock(&inode->i_mutex); + return err; +} +EXPORT_SYMBOL_GPL(fb_deferred_io_fsync); + +/* vm_ops->page_mkwrite handler */ +static int fb_deferred_io_mkwrite(struct vm_area_struct *vma, + struct vm_fault *vmf) +{ + struct page *page = vmf->page; + struct fb_info *info = vma->vm_private_data; + struct fb_deferred_io *fbdefio = info->fbdefio; + struct page *cur; + + /* this is a callback we get when userspace first tries to + write to the page. we schedule a workqueue. that workqueue + will eventually mkclean the touched pages and execute the + deferred framebuffer IO. then if userspace touches a page + again, we repeat the same scheme */ + + file_update_time(vma->vm_file); + + /* protect against the workqueue changing the page list */ + mutex_lock(&fbdefio->lock); + + /* first write in this cycle, notify the driver */ + if (fbdefio->first_io && list_empty(&fbdefio->pagelist)) + fbdefio->first_io(info); + + /* + * We want the page to remain locked from ->page_mkwrite until + * the PTE is marked dirty to avoid page_mkclean() being called + * before the PTE is updated, which would leave the page ignored + * by defio. + * Do this by locking the page here and informing the caller + * about it with VM_FAULT_LOCKED. + */ + lock_page(page); + + /* we loop through the pagelist before adding in order + to keep the pagelist sorted */ + list_for_each_entry(cur, &fbdefio->pagelist, lru) { + /* this check is to catch the case where a new + process could start writing to the same page + through a new pte. this new access can cause the + mkwrite even when the original ps's pte is marked + writable */ + if (unlikely(cur == page)) + goto page_already_added; + else if (cur->index > page->index) + break; + } + + list_add_tail(&page->lru, &cur->lru); + +page_already_added: + mutex_unlock(&fbdefio->lock); + + /* come back after delay to process the deferred IO */ + schedule_delayed_work(&info->deferred_work, fbdefio->delay); + return VM_FAULT_LOCKED; +} + +static const struct vm_operations_struct fb_deferred_io_vm_ops = { + .fault = fb_deferred_io_fault, + .page_mkwrite = fb_deferred_io_mkwrite, +}; + +static int fb_deferred_io_set_page_dirty(struct page *page) +{ + if (!PageDirty(page)) + SetPageDirty(page); + return 0; +} + +static const struct address_space_operations fb_deferred_io_aops = { + .set_page_dirty = fb_deferred_io_set_page_dirty, +}; + +static int fb_deferred_io_mmap(struct fb_info *info, struct vm_area_struct *vma) +{ + vma->vm_ops = &fb_deferred_io_vm_ops; + vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP; + if (!(info->flags & FBINFO_VIRTFB)) + vma->vm_flags |= VM_IO; + vma->vm_private_data = info; + return 0; +} + +/* workqueue callback */ +static void fb_deferred_io_work(struct work_struct *work) +{ + struct fb_info *info = container_of(work, struct fb_info, + deferred_work.work); + struct list_head *node, *next; + struct page *cur; + struct fb_deferred_io *fbdefio = info->fbdefio; + + /* here we mkclean the pages, then do all deferred IO */ + mutex_lock(&fbdefio->lock); + list_for_each_entry(cur, &fbdefio->pagelist, lru) { + lock_page(cur); + page_mkclean(cur); + unlock_page(cur); + } + + /* driver's callback with pagelist */ + fbdefio->deferred_io(info, &fbdefio->pagelist); + + /* clear the list */ + list_for_each_safe(node, next, &fbdefio->pagelist) { + list_del(node); + } + mutex_unlock(&fbdefio->lock); +} + +void fb_deferred_io_init(struct fb_info *info) +{ + struct fb_deferred_io *fbdefio = info->fbdefio; + + BUG_ON(!fbdefio); + mutex_init(&fbdefio->lock); + info->fbops->fb_mmap = fb_deferred_io_mmap; + INIT_DELAYED_WORK(&info->deferred_work, fb_deferred_io_work); + INIT_LIST_HEAD(&fbdefio->pagelist); + if (fbdefio->delay == 0) /* set a default of 1 s */ + fbdefio->delay = HZ; +} +EXPORT_SYMBOL_GPL(fb_deferred_io_init); + +void fb_deferred_io_open(struct fb_info *info, + struct inode *inode, + struct file *file) +{ + file->f_mapping->a_ops = &fb_deferred_io_aops; +} +EXPORT_SYMBOL_GPL(fb_deferred_io_open); + +void fb_deferred_io_cleanup(struct fb_info *info) +{ + struct fb_deferred_io *fbdefio = info->fbdefio; + struct page *page; + int i; + + BUG_ON(!fbdefio); + cancel_delayed_work_sync(&info->deferred_work); + + /* clear out the mapping that we setup */ + for (i = 0 ; i < info->fix.smem_len; i += PAGE_SIZE) { + page = fb_deferred_io_page(info, i); + page->mapping = NULL; + } + + info->fbops->fb_mmap = NULL; + mutex_destroy(&fbdefio->lock); +} +EXPORT_SYMBOL_GPL(fb_deferred_io_cleanup); + +MODULE_LICENSE("GPL"); diff --git a/drivers/video/fbdev/core/fb_draw.h b/drivers/video/fbdev/core/fb_draw.h new file mode 100644 index 00000000000..624ee115f12 --- /dev/null +++ b/drivers/video/fbdev/core/fb_draw.h @@ -0,0 +1,186 @@ +#ifndef _FB_DRAW_H +#define _FB_DRAW_H + +#include +#include +#include + + /* + * Compose two values, using a bitmask as decision value + * This is equivalent to (a & mask) | (b & ~mask) + */ + +static inline unsigned long +comp(unsigned long a, unsigned long b, unsigned long mask) +{ + return ((a ^ b) & mask) ^ b; +} + + /* + * Create a pattern with the given pixel's color + */ + +#if BITS_PER_LONG == 64 +static inline unsigned long +pixel_to_pat( u32 bpp, u32 pixel) +{ + switch (bpp) { + case 1: + return 0xfffffffffffffffful*pixel; + case 2: + return 0x5555555555555555ul*pixel; + case 4: + return 0x1111111111111111ul*pixel; + case 8: + return 0x0101010101010101ul*pixel; + case 12: + return 0x1001001001001001ul*pixel; + case 16: + return 0x0001000100010001ul*pixel; + case 24: + return 0x0001000001000001ul*pixel; + case 32: + return 0x0000000100000001ul*pixel; + default: + WARN(1, "pixel_to_pat(): unsupported pixelformat %d\n", bpp); + return 0; + } +} +#else +static inline unsigned long +pixel_to_pat( u32 bpp, u32 pixel) +{ + switch (bpp) { + case 1: + return 0xfffffffful*pixel; + case 2: + return 0x55555555ul*pixel; + case 4: + return 0x11111111ul*pixel; + case 8: + return 0x01010101ul*pixel; + case 12: + return 0x01001001ul*pixel; + case 16: + return 0x00010001ul*pixel; + case 24: + return 0x01000001ul*pixel; + case 32: + return 0x00000001ul*pixel; + default: + WARN(1, "pixel_to_pat(): unsupported pixelformat %d\n", bpp); + return 0; + } +} +#endif + +#ifdef CONFIG_FB_CFB_REV_PIXELS_IN_BYTE +#if BITS_PER_LONG == 64 +#define REV_PIXELS_MASK1 0x5555555555555555ul +#define REV_PIXELS_MASK2 0x3333333333333333ul +#define REV_PIXELS_MASK4 0x0f0f0f0f0f0f0f0ful +#else +#define REV_PIXELS_MASK1 0x55555555ul +#define REV_PIXELS_MASK2 0x33333333ul +#define REV_PIXELS_MASK4 0x0f0f0f0ful +#endif + +static inline unsigned long fb_rev_pixels_in_long(unsigned long val, + u32 bswapmask) +{ + if (bswapmask & 1) + val = comp(val >> 1, val << 1, REV_PIXELS_MASK1); + if (bswapmask & 2) + val = comp(val >> 2, val << 2, REV_PIXELS_MASK2); + if (bswapmask & 3) + val = comp(val >> 4, val << 4, REV_PIXELS_MASK4); + return val; +} + +static inline u32 fb_shifted_pixels_mask_u32(struct fb_info *p, u32 index, + u32 bswapmask) +{ + u32 mask; + + if (!bswapmask) { + mask = FB_SHIFT_HIGH(p, ~(u32)0, index); + } else { + mask = 0xff << FB_LEFT_POS(p, 8); + mask = FB_SHIFT_LOW(p, mask, index & (bswapmask)) & mask; + mask = FB_SHIFT_HIGH(p, mask, index & ~(bswapmask)); +#if defined(__i386__) || defined(__x86_64__) + /* Shift argument is limited to 0 - 31 on x86 based CPU's */ + if(index + bswapmask < 32) +#endif + mask |= FB_SHIFT_HIGH(p, ~(u32)0, + (index + bswapmask) & ~(bswapmask)); + } + return mask; +} + +static inline unsigned long fb_shifted_pixels_mask_long(struct fb_info *p, + u32 index, + u32 bswapmask) +{ + unsigned long mask; + + if (!bswapmask) { + mask = FB_SHIFT_HIGH(p, ~0UL, index); + } else { + mask = 0xff << FB_LEFT_POS(p, 8); + mask = FB_SHIFT_LOW(p, mask, index & (bswapmask)) & mask; + mask = FB_SHIFT_HIGH(p, mask, index & ~(bswapmask)); +#if defined(__i386__) || defined(__x86_64__) + /* Shift argument is limited to 0 - 31 on x86 based CPU's */ + if(index + bswapmask < BITS_PER_LONG) +#endif + mask |= FB_SHIFT_HIGH(p, ~0UL, + (index + bswapmask) & ~(bswapmask)); + } + return mask; +} + + +static inline u32 fb_compute_bswapmask(struct fb_info *info) +{ + u32 bswapmask = 0; + unsigned bpp = info->var.bits_per_pixel; + + if ((bpp < 8) && (info->var.nonstd & FB_NONSTD_REV_PIX_IN_B)) { + /* + * Reversed order of pixel layout in bytes + * works only for 1, 2 and 4 bpp + */ + bswapmask = 7 - bpp + 1; + } + return bswapmask; +} + +#else /* CONFIG_FB_CFB_REV_PIXELS_IN_BYTE */ + +static inline unsigned long fb_rev_pixels_in_long(unsigned long val, + u32 bswapmask) +{ + return val; +} + +#define fb_shifted_pixels_mask_u32(p, i, b) FB_SHIFT_HIGH((p), ~(u32)0, (i)) +#define fb_shifted_pixels_mask_long(p, i, b) FB_SHIFT_HIGH((p), ~0UL, (i)) +#define fb_compute_bswapmask(...) 0 + +#endif /* CONFIG_FB_CFB_REV_PIXELS_IN_BYTE */ + +#define cpu_to_le_long _cpu_to_le_long(BITS_PER_LONG) +#define _cpu_to_le_long(x) __cpu_to_le_long(x) +#define __cpu_to_le_long(x) cpu_to_le##x + +#define le_long_to_cpu _le_long_to_cpu(BITS_PER_LONG) +#define _le_long_to_cpu(x) __le_long_to_cpu(x) +#define __le_long_to_cpu(x) le##x##_to_cpu + +static inline unsigned long rolx(unsigned long word, unsigned int shift, unsigned int x) +{ + return (word << shift) | (word >> (x - shift)); +} + +#endif /* FB_DRAW_H */ diff --git a/drivers/video/fbdev/core/fb_notify.c b/drivers/video/fbdev/core/fb_notify.c new file mode 100644 index 00000000000..74c2da52888 --- /dev/null +++ b/drivers/video/fbdev/core/fb_notify.c @@ -0,0 +1,47 @@ +/* + * linux/drivers/video/fb_notify.c + * + * Copyright (C) 2006 Antonino Daplas + * + * 2001 - Documented with DocBook + * - Brad Douglas + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ +#include +#include +#include + +static BLOCKING_NOTIFIER_HEAD(fb_notifier_list); + +/** + * fb_register_client - register a client notifier + * @nb: notifier block to callback on events + */ +int fb_register_client(struct notifier_block *nb) +{ + return blocking_notifier_chain_register(&fb_notifier_list, nb); +} +EXPORT_SYMBOL(fb_register_client); + +/** + * fb_unregister_client - unregister a client notifier + * @nb: notifier block to callback on events + */ +int fb_unregister_client(struct notifier_block *nb) +{ + return blocking_notifier_chain_unregister(&fb_notifier_list, nb); +} +EXPORT_SYMBOL(fb_unregister_client); + +/** + * fb_notifier_call_chain - notify clients of fb_events + * + */ +int fb_notifier_call_chain(unsigned long val, void *v) +{ + return blocking_notifier_call_chain(&fb_notifier_list, val, v); +} +EXPORT_SYMBOL_GPL(fb_notifier_call_chain); diff --git a/drivers/video/fbdev/core/fb_sys_fops.c b/drivers/video/fbdev/core/fb_sys_fops.c new file mode 100644 index 00000000000..ff275d7f3ea --- /dev/null +++ b/drivers/video/fbdev/core/fb_sys_fops.c @@ -0,0 +1,104 @@ +/* + * linux/drivers/video/fb_sys_read.c - Generic file operations where + * framebuffer is in system RAM + * + * Copyright (C) 2007 Antonino Daplas + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + * + */ +#include +#include +#include + +ssize_t fb_sys_read(struct fb_info *info, char __user *buf, size_t count, + loff_t *ppos) +{ + unsigned long p = *ppos; + void *src; + int err = 0; + unsigned long total_size; + + if (info->state != FBINFO_STATE_RUNNING) + return -EPERM; + + total_size = info->screen_size; + + if (total_size == 0) + total_size = info->fix.smem_len; + + if (p >= total_size) + return 0; + + if (count >= total_size) + count = total_size; + + if (count + p > total_size) + count = total_size - p; + + src = (void __force *)(info->screen_base + p); + + if (info->fbops->fb_sync) + info->fbops->fb_sync(info); + + if (copy_to_user(buf, src, count)) + err = -EFAULT; + + if (!err) + *ppos += count; + + return (err) ? err : count; +} +EXPORT_SYMBOL_GPL(fb_sys_read); + +ssize_t fb_sys_write(struct fb_info *info, const char __user *buf, + size_t count, loff_t *ppos) +{ + unsigned long p = *ppos; + void *dst; + int err = 0; + unsigned long total_size; + + if (info->state != FBINFO_STATE_RUNNING) + return -EPERM; + + total_size = info->screen_size; + + if (total_size == 0) + total_size = info->fix.smem_len; + + if (p > total_size) + return -EFBIG; + + if (count > total_size) { + err = -EFBIG; + count = total_size; + } + + if (count + p > total_size) { + if (!err) + err = -ENOSPC; + + count = total_size - p; + } + + dst = (void __force *) (info->screen_base + p); + + if (info->fbops->fb_sync) + info->fbops->fb_sync(info); + + if (copy_from_user(dst, buf, count)) + err = -EFAULT; + + if (!err) + *ppos += count; + + return (err) ? err : count; +} +EXPORT_SYMBOL_GPL(fb_sys_write); + +MODULE_AUTHOR("Antonino Daplas "); +MODULE_DESCRIPTION("Generic file read (fb in system RAM)"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/fbdev/core/fbcmap.c b/drivers/video/fbdev/core/fbcmap.c new file mode 100644 index 00000000000..f89245b8ba8 --- /dev/null +++ b/drivers/video/fbdev/core/fbcmap.c @@ -0,0 +1,362 @@ +/* + * linux/drivers/video/fbcmap.c -- Colormap handling for frame buffer devices + * + * Created 15 Jun 1997 by Geert Uytterhoeven + * + * 2001 - Documented with DocBook + * - Brad Douglas + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ + +#include +#include +#include +#include +#include + +static u16 red2[] __read_mostly = { + 0x0000, 0xaaaa +}; +static u16 green2[] __read_mostly = { + 0x0000, 0xaaaa +}; +static u16 blue2[] __read_mostly = { + 0x0000, 0xaaaa +}; + +static u16 red4[] __read_mostly = { + 0x0000, 0xaaaa, 0x5555, 0xffff +}; +static u16 green4[] __read_mostly = { + 0x0000, 0xaaaa, 0x5555, 0xffff +}; +static u16 blue4[] __read_mostly = { + 0x0000, 0xaaaa, 0x5555, 0xffff +}; + +static u16 red8[] __read_mostly = { + 0x0000, 0x0000, 0x0000, 0x0000, 0xaaaa, 0xaaaa, 0xaaaa, 0xaaaa +}; +static u16 green8[] __read_mostly = { + 0x0000, 0x0000, 0xaaaa, 0xaaaa, 0x0000, 0x0000, 0x5555, 0xaaaa +}; +static u16 blue8[] __read_mostly = { + 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa +}; + +static u16 red16[] __read_mostly = { + 0x0000, 0x0000, 0x0000, 0x0000, 0xaaaa, 0xaaaa, 0xaaaa, 0xaaaa, + 0x5555, 0x5555, 0x5555, 0x5555, 0xffff, 0xffff, 0xffff, 0xffff +}; +static u16 green16[] __read_mostly = { + 0x0000, 0x0000, 0xaaaa, 0xaaaa, 0x0000, 0x0000, 0x5555, 0xaaaa, + 0x5555, 0x5555, 0xffff, 0xffff, 0x5555, 0x5555, 0xffff, 0xffff +}; +static u16 blue16[] __read_mostly = { + 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa, 0x0000, 0xaaaa, + 0x5555, 0xffff, 0x5555, 0xffff, 0x5555, 0xffff, 0x5555, 0xffff +}; + +static const struct fb_cmap default_2_colors = { + .len=2, .red=red2, .green=green2, .blue=blue2 +}; +static const struct fb_cmap default_8_colors = { + .len=8, .red=red8, .green=green8, .blue=blue8 +}; +static const struct fb_cmap default_4_colors = { + .len=4, .red=red4, .green=green4, .blue=blue4 +}; +static const struct fb_cmap default_16_colors = { + .len=16, .red=red16, .green=green16, .blue=blue16 +}; + + + +/** + * fb_alloc_cmap - allocate a colormap + * @cmap: frame buffer colormap structure + * @len: length of @cmap + * @transp: boolean, 1 if there is transparency, 0 otherwise + * @flags: flags for kmalloc memory allocation + * + * Allocates memory for a colormap @cmap. @len is the + * number of entries in the palette. + * + * Returns negative errno on error, or zero on success. + * + */ + +int fb_alloc_cmap_gfp(struct fb_cmap *cmap, int len, int transp, gfp_t flags) +{ + int size = len * sizeof(u16); + int ret = -ENOMEM; + + if (cmap->len != len) { + fb_dealloc_cmap(cmap); + if (!len) + return 0; + + cmap->red = kmalloc(size, flags); + if (!cmap->red) + goto fail; + cmap->green = kmalloc(size, flags); + if (!cmap->green) + goto fail; + cmap->blue = kmalloc(size, flags); + if (!cmap->blue) + goto fail; + if (transp) { + cmap->transp = kmalloc(size, flags); + if (!cmap->transp) + goto fail; + } else { + cmap->transp = NULL; + } + } + cmap->start = 0; + cmap->len = len; + ret = fb_copy_cmap(fb_default_cmap(len), cmap); + if (ret) + goto fail; + return 0; + +fail: + fb_dealloc_cmap(cmap); + return ret; +} + +int fb_alloc_cmap(struct fb_cmap *cmap, int len, int transp) +{ + return fb_alloc_cmap_gfp(cmap, len, transp, GFP_ATOMIC); +} + +/** + * fb_dealloc_cmap - deallocate a colormap + * @cmap: frame buffer colormap structure + * + * Deallocates a colormap that was previously allocated with + * fb_alloc_cmap(). + * + */ + +void fb_dealloc_cmap(struct fb_cmap *cmap) +{ + kfree(cmap->red); + kfree(cmap->green); + kfree(cmap->blue); + kfree(cmap->transp); + + cmap->red = cmap->green = cmap->blue = cmap->transp = NULL; + cmap->len = 0; +} + +/** + * fb_copy_cmap - copy a colormap + * @from: frame buffer colormap structure + * @to: frame buffer colormap structure + * + * Copy contents of colormap from @from to @to. + */ + +int fb_copy_cmap(const struct fb_cmap *from, struct fb_cmap *to) +{ + int tooff = 0, fromoff = 0; + int size; + + if (to->start > from->start) + fromoff = to->start - from->start; + else + tooff = from->start - to->start; + size = to->len - tooff; + if (size > (int) (from->len - fromoff)) + size = from->len - fromoff; + if (size <= 0) + return -EINVAL; + size *= sizeof(u16); + + memcpy(to->red+tooff, from->red+fromoff, size); + memcpy(to->green+tooff, from->green+fromoff, size); + memcpy(to->blue+tooff, from->blue+fromoff, size); + if (from->transp && to->transp) + memcpy(to->transp+tooff, from->transp+fromoff, size); + return 0; +} + +int fb_cmap_to_user(const struct fb_cmap *from, struct fb_cmap_user *to) +{ + int tooff = 0, fromoff = 0; + int size; + + if (to->start > from->start) + fromoff = to->start - from->start; + else + tooff = from->start - to->start; + size = to->len - tooff; + if (size > (int) (from->len - fromoff)) + size = from->len - fromoff; + if (size <= 0) + return -EINVAL; + size *= sizeof(u16); + + if (copy_to_user(to->red+tooff, from->red+fromoff, size)) + return -EFAULT; + if (copy_to_user(to->green+tooff, from->green+fromoff, size)) + return -EFAULT; + if (copy_to_user(to->blue+tooff, from->blue+fromoff, size)) + return -EFAULT; + if (from->transp && to->transp) + if (copy_to_user(to->transp+tooff, from->transp+fromoff, size)) + return -EFAULT; + return 0; +} + +/** + * fb_set_cmap - set the colormap + * @cmap: frame buffer colormap structure + * @info: frame buffer info structure + * + * Sets the colormap @cmap for a screen of device @info. + * + * Returns negative errno on error, or zero on success. + * + */ + +int fb_set_cmap(struct fb_cmap *cmap, struct fb_info *info) +{ + int i, start, rc = 0; + u16 *red, *green, *blue, *transp; + u_int hred, hgreen, hblue, htransp = 0xffff; + + red = cmap->red; + green = cmap->green; + blue = cmap->blue; + transp = cmap->transp; + start = cmap->start; + + if (start < 0 || (!info->fbops->fb_setcolreg && + !info->fbops->fb_setcmap)) + return -EINVAL; + if (info->fbops->fb_setcmap) { + rc = info->fbops->fb_setcmap(cmap, info); + } else { + for (i = 0; i < cmap->len; i++) { + hred = *red++; + hgreen = *green++; + hblue = *blue++; + if (transp) + htransp = *transp++; + if (info->fbops->fb_setcolreg(start++, + hred, hgreen, hblue, + htransp, info)) + break; + } + } + if (rc == 0) + fb_copy_cmap(cmap, &info->cmap); + + return rc; +} + +int fb_set_user_cmap(struct fb_cmap_user *cmap, struct fb_info *info) +{ + int rc, size = cmap->len * sizeof(u16); + struct fb_cmap umap; + + if (size < 0 || size < cmap->len) + return -E2BIG; + + memset(&umap, 0, sizeof(struct fb_cmap)); + rc = fb_alloc_cmap_gfp(&umap, cmap->len, cmap->transp != NULL, + GFP_KERNEL); + if (rc) + return rc; + if (copy_from_user(umap.red, cmap->red, size) || + copy_from_user(umap.green, cmap->green, size) || + copy_from_user(umap.blue, cmap->blue, size) || + (cmap->transp && copy_from_user(umap.transp, cmap->transp, size))) { + rc = -EFAULT; + goto out; + } + umap.start = cmap->start; + if (!lock_fb_info(info)) { + rc = -ENODEV; + goto out; + } + + rc = fb_set_cmap(&umap, info); + unlock_fb_info(info); +out: + fb_dealloc_cmap(&umap); + return rc; +} + +/** + * fb_default_cmap - get default colormap + * @len: size of palette for a depth + * + * Gets the default colormap for a specific screen depth. @len + * is the size of the palette for a particular screen depth. + * + * Returns pointer to a frame buffer colormap structure. + * + */ + +const struct fb_cmap *fb_default_cmap(int len) +{ + if (len <= 2) + return &default_2_colors; + if (len <= 4) + return &default_4_colors; + if (len <= 8) + return &default_8_colors; + return &default_16_colors; +} + + +/** + * fb_invert_cmaps - invert all defaults colormaps + * + * Invert all default colormaps. + * + */ + +void fb_invert_cmaps(void) +{ + u_int i; + + for (i = 0; i < ARRAY_SIZE(red2); i++) { + red2[i] = ~red2[i]; + green2[i] = ~green2[i]; + blue2[i] = ~blue2[i]; + } + for (i = 0; i < ARRAY_SIZE(red4); i++) { + red4[i] = ~red4[i]; + green4[i] = ~green4[i]; + blue4[i] = ~blue4[i]; + } + for (i = 0; i < ARRAY_SIZE(red8); i++) { + red8[i] = ~red8[i]; + green8[i] = ~green8[i]; + blue8[i] = ~blue8[i]; + } + for (i = 0; i < ARRAY_SIZE(red16); i++) { + red16[i] = ~red16[i]; + green16[i] = ~green16[i]; + blue16[i] = ~blue16[i]; + } +} + + + /* + * Visible symbols for modules + */ + +EXPORT_SYMBOL(fb_alloc_cmap); +EXPORT_SYMBOL(fb_dealloc_cmap); +EXPORT_SYMBOL(fb_copy_cmap); +EXPORT_SYMBOL(fb_set_cmap); +EXPORT_SYMBOL(fb_default_cmap); +EXPORT_SYMBOL(fb_invert_cmaps); diff --git a/drivers/video/fbdev/core/fbcvt.c b/drivers/video/fbdev/core/fbcvt.c new file mode 100644 index 00000000000..7cb715dfc0e --- /dev/null +++ b/drivers/video/fbdev/core/fbcvt.c @@ -0,0 +1,379 @@ +/* + * linux/drivers/video/fbcvt.c - VESA(TM) Coordinated Video Timings + * + * Copyright (C) 2005 Antonino Daplas + * + * Based from the VESA(TM) Coordinated Video Timing Generator by + * Graham Loveridge April 9, 2003 available at + * http://www.elo.utfsm.cl/~elo212/docs/CVTd6r1.xls + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + * + */ +#include +#include + +#define FB_CVT_CELLSIZE 8 +#define FB_CVT_GTF_C 40 +#define FB_CVT_GTF_J 20 +#define FB_CVT_GTF_K 128 +#define FB_CVT_GTF_M 600 +#define FB_CVT_MIN_VSYNC_BP 550 +#define FB_CVT_MIN_VPORCH 3 +#define FB_CVT_MIN_BPORCH 6 + +#define FB_CVT_RB_MIN_VBLANK 460 +#define FB_CVT_RB_HBLANK 160 +#define FB_CVT_RB_V_FPORCH 3 + +#define FB_CVT_FLAG_REDUCED_BLANK 1 +#define FB_CVT_FLAG_MARGINS 2 +#define FB_CVT_FLAG_INTERLACED 4 + +struct fb_cvt_data { + u32 xres; + u32 yres; + u32 refresh; + u32 f_refresh; + u32 pixclock; + u32 hperiod; + u32 hblank; + u32 hfreq; + u32 htotal; + u32 vtotal; + u32 vsync; + u32 hsync; + u32 h_front_porch; + u32 h_back_porch; + u32 v_front_porch; + u32 v_back_porch; + u32 h_margin; + u32 v_margin; + u32 interlace; + u32 aspect_ratio; + u32 active_pixels; + u32 flags; + u32 status; +}; + +static const unsigned char fb_cvt_vbi_tab[] = { + 4, /* 4:3 */ + 5, /* 16:9 */ + 6, /* 16:10 */ + 7, /* 5:4 */ + 7, /* 15:9 */ + 8, /* reserved */ + 9, /* reserved */ + 10 /* custom */ +}; + +/* returns hperiod * 1000 */ +static u32 fb_cvt_hperiod(struct fb_cvt_data *cvt) +{ + u32 num = 1000000000/cvt->f_refresh; + u32 den; + + if (cvt->flags & FB_CVT_FLAG_REDUCED_BLANK) { + num -= FB_CVT_RB_MIN_VBLANK * 1000; + den = 2 * (cvt->yres/cvt->interlace + 2 * cvt->v_margin); + } else { + num -= FB_CVT_MIN_VSYNC_BP * 1000; + den = 2 * (cvt->yres/cvt->interlace + cvt->v_margin * 2 + + FB_CVT_MIN_VPORCH + cvt->interlace/2); + } + + return 2 * (num/den); +} + +/* returns ideal duty cycle * 1000 */ +static u32 fb_cvt_ideal_duty_cycle(struct fb_cvt_data *cvt) +{ + u32 c_prime = (FB_CVT_GTF_C - FB_CVT_GTF_J) * + (FB_CVT_GTF_K) + 256 * FB_CVT_GTF_J; + u32 m_prime = (FB_CVT_GTF_K * FB_CVT_GTF_M); + u32 h_period_est = cvt->hperiod; + + return (1000 * c_prime - ((m_prime * h_period_est)/1000))/256; +} + +static u32 fb_cvt_hblank(struct fb_cvt_data *cvt) +{ + u32 hblank = 0; + + if (cvt->flags & FB_CVT_FLAG_REDUCED_BLANK) + hblank = FB_CVT_RB_HBLANK; + else { + u32 ideal_duty_cycle = fb_cvt_ideal_duty_cycle(cvt); + u32 active_pixels = cvt->active_pixels; + + if (ideal_duty_cycle < 20000) + hblank = (active_pixels * 20000)/ + (100000 - 20000); + else { + hblank = (active_pixels * ideal_duty_cycle)/ + (100000 - ideal_duty_cycle); + } + } + + hblank &= ~((2 * FB_CVT_CELLSIZE) - 1); + + return hblank; +} + +static u32 fb_cvt_hsync(struct fb_cvt_data *cvt) +{ + u32 hsync; + + if (cvt->flags & FB_CVT_FLAG_REDUCED_BLANK) + hsync = 32; + else + hsync = (FB_CVT_CELLSIZE * cvt->htotal)/100; + + hsync &= ~(FB_CVT_CELLSIZE - 1); + return hsync; +} + +static u32 fb_cvt_vbi_lines(struct fb_cvt_data *cvt) +{ + u32 vbi_lines, min_vbi_lines, act_vbi_lines; + + if (cvt->flags & FB_CVT_FLAG_REDUCED_BLANK) { + vbi_lines = (1000 * FB_CVT_RB_MIN_VBLANK)/cvt->hperiod + 1; + min_vbi_lines = FB_CVT_RB_V_FPORCH + cvt->vsync + + FB_CVT_MIN_BPORCH; + + } else { + vbi_lines = (FB_CVT_MIN_VSYNC_BP * 1000)/cvt->hperiod + 1 + + FB_CVT_MIN_VPORCH; + min_vbi_lines = cvt->vsync + FB_CVT_MIN_BPORCH + + FB_CVT_MIN_VPORCH; + } + + if (vbi_lines < min_vbi_lines) + act_vbi_lines = min_vbi_lines; + else + act_vbi_lines = vbi_lines; + + return act_vbi_lines; +} + +static u32 fb_cvt_vtotal(struct fb_cvt_data *cvt) +{ + u32 vtotal = cvt->yres/cvt->interlace; + + vtotal += 2 * cvt->v_margin + cvt->interlace/2 + fb_cvt_vbi_lines(cvt); + vtotal |= cvt->interlace/2; + + return vtotal; +} + +static u32 fb_cvt_pixclock(struct fb_cvt_data *cvt) +{ + u32 pixclock; + + if (cvt->flags & FB_CVT_FLAG_REDUCED_BLANK) + pixclock = (cvt->f_refresh * cvt->vtotal * cvt->htotal)/1000; + else + pixclock = (cvt->htotal * 1000000)/cvt->hperiod; + + pixclock /= 250; + pixclock *= 250; + pixclock *= 1000; + + return pixclock; +} + +static u32 fb_cvt_aspect_ratio(struct fb_cvt_data *cvt) +{ + u32 xres = cvt->xres; + u32 yres = cvt->yres; + u32 aspect = -1; + + if (xres == (yres * 4)/3 && !((yres * 4) % 3)) + aspect = 0; + else if (xres == (yres * 16)/9 && !((yres * 16) % 9)) + aspect = 1; + else if (xres == (yres * 16)/10 && !((yres * 16) % 10)) + aspect = 2; + else if (xres == (yres * 5)/4 && !((yres * 5) % 4)) + aspect = 3; + else if (xres == (yres * 15)/9 && !((yres * 15) % 9)) + aspect = 4; + else { + printk(KERN_INFO "fbcvt: Aspect ratio not CVT " + "standard\n"); + aspect = 7; + cvt->status = 1; + } + + return aspect; +} + +static void fb_cvt_print_name(struct fb_cvt_data *cvt) +{ + u32 pixcount, pixcount_mod; + int cnt = 255, offset = 0, read = 0; + u8 *buf = kzalloc(256, GFP_KERNEL); + + if (!buf) + return; + + pixcount = (cvt->xres * (cvt->yres/cvt->interlace))/1000000; + pixcount_mod = (cvt->xres * (cvt->yres/cvt->interlace)) % 1000000; + pixcount_mod /= 1000; + + read = snprintf(buf+offset, cnt, "fbcvt: %dx%d@%d: CVT Name - ", + cvt->xres, cvt->yres, cvt->refresh); + offset += read; + cnt -= read; + + if (cvt->status) + snprintf(buf+offset, cnt, "Not a CVT standard - %d.%03d Mega " + "Pixel Image\n", pixcount, pixcount_mod); + else { + if (pixcount) { + read = snprintf(buf+offset, cnt, "%d", pixcount); + cnt -= read; + offset += read; + } + + read = snprintf(buf+offset, cnt, ".%03dM", pixcount_mod); + cnt -= read; + offset += read; + + if (cvt->aspect_ratio == 0) + read = snprintf(buf+offset, cnt, "3"); + else if (cvt->aspect_ratio == 3) + read = snprintf(buf+offset, cnt, "4"); + else if (cvt->aspect_ratio == 1 || cvt->aspect_ratio == 4) + read = snprintf(buf+offset, cnt, "9"); + else if (cvt->aspect_ratio == 2) + read = snprintf(buf+offset, cnt, "A"); + else + read = 0; + cnt -= read; + offset += read; + + if (cvt->flags & FB_CVT_FLAG_REDUCED_BLANK) { + read = snprintf(buf+offset, cnt, "-R"); + cnt -= read; + offset += read; + } + } + + printk(KERN_INFO "%s\n", buf); + kfree(buf); +} + +static void fb_cvt_convert_to_mode(struct fb_cvt_data *cvt, + struct fb_videomode *mode) +{ + mode->refresh = cvt->f_refresh; + mode->pixclock = KHZ2PICOS(cvt->pixclock/1000); + mode->left_margin = cvt->h_back_porch; + mode->right_margin = cvt->h_front_porch; + mode->hsync_len = cvt->hsync; + mode->upper_margin = cvt->v_back_porch; + mode->lower_margin = cvt->v_front_porch; + mode->vsync_len = cvt->vsync; + + mode->sync &= ~(FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT); + + if (cvt->flags & FB_CVT_FLAG_REDUCED_BLANK) + mode->sync |= FB_SYNC_HOR_HIGH_ACT; + else + mode->sync |= FB_SYNC_VERT_HIGH_ACT; +} + +/* + * fb_find_mode_cvt - calculate mode using VESA(TM) CVT + * @mode: pointer to fb_videomode; xres, yres, refresh and vmode must be + * pre-filled with the desired values + * @margins: add margin to calculation (1.8% of xres and yres) + * @rb: compute with reduced blanking (for flatpanels) + * + * RETURNS: + * 0 for success + * @mode is filled with computed values. If interlaced, the refresh field + * will be filled with the field rate (2x the frame rate) + * + * DESCRIPTION: + * Computes video timings using VESA(TM) Coordinated Video Timings + */ +int fb_find_mode_cvt(struct fb_videomode *mode, int margins, int rb) +{ + struct fb_cvt_data cvt; + + memset(&cvt, 0, sizeof(cvt)); + + if (margins) + cvt.flags |= FB_CVT_FLAG_MARGINS; + + if (rb) + cvt.flags |= FB_CVT_FLAG_REDUCED_BLANK; + + if (mode->vmode & FB_VMODE_INTERLACED) + cvt.flags |= FB_CVT_FLAG_INTERLACED; + + cvt.xres = mode->xres; + cvt.yres = mode->yres; + cvt.refresh = mode->refresh; + cvt.f_refresh = cvt.refresh; + cvt.interlace = 1; + + if (!cvt.xres || !cvt.yres || !cvt.refresh) { + printk(KERN_INFO "fbcvt: Invalid input parameters\n"); + return 1; + } + + if (!(cvt.refresh == 50 || cvt.refresh == 60 || cvt.refresh == 70 || + cvt.refresh == 85)) { + printk(KERN_INFO "fbcvt: Refresh rate not CVT " + "standard\n"); + cvt.status = 1; + } + + cvt.xres &= ~(FB_CVT_CELLSIZE - 1); + + if (cvt.flags & FB_CVT_FLAG_INTERLACED) { + cvt.interlace = 2; + cvt.f_refresh *= 2; + } + + if (cvt.flags & FB_CVT_FLAG_REDUCED_BLANK) { + if (cvt.refresh != 60) { + printk(KERN_INFO "fbcvt: 60Hz refresh rate " + "advised for reduced blanking\n"); + cvt.status = 1; + } + } + + if (cvt.flags & FB_CVT_FLAG_MARGINS) { + cvt.h_margin = (cvt.xres * 18)/1000; + cvt.h_margin &= ~(FB_CVT_CELLSIZE - 1); + cvt.v_margin = ((cvt.yres/cvt.interlace)* 18)/1000; + } + + cvt.aspect_ratio = fb_cvt_aspect_ratio(&cvt); + cvt.active_pixels = cvt.xres + 2 * cvt.h_margin; + cvt.hperiod = fb_cvt_hperiod(&cvt); + cvt.vsync = fb_cvt_vbi_tab[cvt.aspect_ratio]; + cvt.vtotal = fb_cvt_vtotal(&cvt); + cvt.hblank = fb_cvt_hblank(&cvt); + cvt.htotal = cvt.active_pixels + cvt.hblank; + cvt.hsync = fb_cvt_hsync(&cvt); + cvt.pixclock = fb_cvt_pixclock(&cvt); + cvt.hfreq = cvt.pixclock/cvt.htotal; + cvt.h_back_porch = cvt.hblank/2 + cvt.h_margin; + cvt.h_front_porch = cvt.hblank - cvt.hsync - cvt.h_back_porch + + 2 * cvt.h_margin; + cvt.v_back_porch = 3 + cvt.v_margin; + cvt.v_front_porch = cvt.vtotal - cvt.yres/cvt.interlace - + cvt.v_back_porch - cvt.vsync; + fb_cvt_print_name(&cvt); + fb_cvt_convert_to_mode(&cvt, mode); + + return 0; +} diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c new file mode 100644 index 00000000000..b6d5008f361 --- /dev/null +++ b/drivers/video/fbdev/core/fbmem.c @@ -0,0 +1,2002 @@ +/* + * linux/drivers/video/fbmem.c + * + * Copyright (C) 1994 Martin Schaller + * + * 2001 - Documented with DocBook + * - Brad Douglas + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + + /* + * Frame buffer device initialization and setup routines + */ + +#define FBPIXMAPSIZE (1024 * 8) + +static DEFINE_MUTEX(registration_lock); + +struct fb_info *registered_fb[FB_MAX] __read_mostly; +EXPORT_SYMBOL(registered_fb); + +int num_registered_fb __read_mostly; +EXPORT_SYMBOL(num_registered_fb); + +static struct fb_info *get_fb_info(unsigned int idx) +{ + struct fb_info *fb_info; + + if (idx >= FB_MAX) + return ERR_PTR(-ENODEV); + + mutex_lock(®istration_lock); + fb_info = registered_fb[idx]; + if (fb_info) + atomic_inc(&fb_info->count); + mutex_unlock(®istration_lock); + + return fb_info; +} + +static void put_fb_info(struct fb_info *fb_info) +{ + if (!atomic_dec_and_test(&fb_info->count)) + return; + if (fb_info->fbops->fb_destroy) + fb_info->fbops->fb_destroy(fb_info); +} + +int lock_fb_info(struct fb_info *info) +{ + mutex_lock(&info->lock); + if (!info->fbops) { + mutex_unlock(&info->lock); + return 0; + } + return 1; +} +EXPORT_SYMBOL(lock_fb_info); + +/* + * Helpers + */ + +int fb_get_color_depth(struct fb_var_screeninfo *var, + struct fb_fix_screeninfo *fix) +{ + int depth = 0; + + if (fix->visual == FB_VISUAL_MONO01 || + fix->visual == FB_VISUAL_MONO10) + depth = 1; + else { + if (var->green.length == var->blue.length && + var->green.length == var->red.length && + var->green.offset == var->blue.offset && + var->green.offset == var->red.offset) + depth = var->green.length; + else + depth = var->green.length + var->red.length + + var->blue.length; + } + + return depth; +} +EXPORT_SYMBOL(fb_get_color_depth); + +/* + * Data padding functions. + */ +void fb_pad_aligned_buffer(u8 *dst, u32 d_pitch, u8 *src, u32 s_pitch, u32 height) +{ + __fb_pad_aligned_buffer(dst, d_pitch, src, s_pitch, height); +} +EXPORT_SYMBOL(fb_pad_aligned_buffer); + +void fb_pad_unaligned_buffer(u8 *dst, u32 d_pitch, u8 *src, u32 idx, u32 height, + u32 shift_high, u32 shift_low, u32 mod) +{ + u8 mask = (u8) (0xfff << shift_high), tmp; + int i, j; + + for (i = height; i--; ) { + for (j = 0; j < idx; j++) { + tmp = dst[j]; + tmp &= mask; + tmp |= *src >> shift_low; + dst[j] = tmp; + tmp = *src << shift_high; + dst[j+1] = tmp; + src++; + } + tmp = dst[idx]; + tmp &= mask; + tmp |= *src >> shift_low; + dst[idx] = tmp; + if (shift_high < mod) { + tmp = *src << shift_high; + dst[idx+1] = tmp; + } + src++; + dst += d_pitch; + } +} +EXPORT_SYMBOL(fb_pad_unaligned_buffer); + +/* + * we need to lock this section since fb_cursor + * may use fb_imageblit() + */ +char* fb_get_buffer_offset(struct fb_info *info, struct fb_pixmap *buf, u32 size) +{ + u32 align = buf->buf_align - 1, offset; + char *addr = buf->addr; + + /* If IO mapped, we need to sync before access, no sharing of + * the pixmap is done + */ + if (buf->flags & FB_PIXMAP_IO) { + if (info->fbops->fb_sync && (buf->flags & FB_PIXMAP_SYNC)) + info->fbops->fb_sync(info); + return addr; + } + + /* See if we fit in the remaining pixmap space */ + offset = buf->offset + align; + offset &= ~align; + if (offset + size > buf->size) { + /* We do not fit. In order to be able to re-use the buffer, + * we must ensure no asynchronous DMA'ing or whatever operation + * is in progress, we sync for that. + */ + if (info->fbops->fb_sync && (buf->flags & FB_PIXMAP_SYNC)) + info->fbops->fb_sync(info); + offset = 0; + } + buf->offset = offset + size; + addr += offset; + + return addr; +} +EXPORT_SYMBOL(fb_get_buffer_offset); + +#ifdef CONFIG_LOGO + +static inline unsigned safe_shift(unsigned d, int n) +{ + return n < 0 ? d >> -n : d << n; +} + +static void fb_set_logocmap(struct fb_info *info, + const struct linux_logo *logo) +{ + struct fb_cmap palette_cmap; + u16 palette_green[16]; + u16 palette_blue[16]; + u16 palette_red[16]; + int i, j, n; + const unsigned char *clut = logo->clut; + + palette_cmap.start = 0; + palette_cmap.len = 16; + palette_cmap.red = palette_red; + palette_cmap.green = palette_green; + palette_cmap.blue = palette_blue; + palette_cmap.transp = NULL; + + for (i = 0; i < logo->clutsize; i += n) { + n = logo->clutsize - i; + /* palette_cmap provides space for only 16 colors at once */ + if (n > 16) + n = 16; + palette_cmap.start = 32 + i; + palette_cmap.len = n; + for (j = 0; j < n; ++j) { + palette_cmap.red[j] = clut[0] << 8 | clut[0]; + palette_cmap.green[j] = clut[1] << 8 | clut[1]; + palette_cmap.blue[j] = clut[2] << 8 | clut[2]; + clut += 3; + } + fb_set_cmap(&palette_cmap, info); + } +} + +static void fb_set_logo_truepalette(struct fb_info *info, + const struct linux_logo *logo, + u32 *palette) +{ + static const unsigned char mask[] = { 0,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff }; + unsigned char redmask, greenmask, bluemask; + int redshift, greenshift, blueshift; + int i; + const unsigned char *clut = logo->clut; + + /* + * We have to create a temporary palette since console palette is only + * 16 colors long. + */ + /* Bug: Doesn't obey msb_right ... (who needs that?) */ + redmask = mask[info->var.red.length < 8 ? info->var.red.length : 8]; + greenmask = mask[info->var.green.length < 8 ? info->var.green.length : 8]; + bluemask = mask[info->var.blue.length < 8 ? info->var.blue.length : 8]; + redshift = info->var.red.offset - (8 - info->var.red.length); + greenshift = info->var.green.offset - (8 - info->var.green.length); + blueshift = info->var.blue.offset - (8 - info->var.blue.length); + + for ( i = 0; i < logo->clutsize; i++) { + palette[i+32] = (safe_shift((clut[0] & redmask), redshift) | + safe_shift((clut[1] & greenmask), greenshift) | + safe_shift((clut[2] & bluemask), blueshift)); + clut += 3; + } +} + +static void fb_set_logo_directpalette(struct fb_info *info, + const struct linux_logo *logo, + u32 *palette) +{ + int redshift, greenshift, blueshift; + int i; + + redshift = info->var.red.offset; + greenshift = info->var.green.offset; + blueshift = info->var.blue.offset; + + for (i = 32; i < 32 + logo->clutsize; i++) + palette[i] = i << redshift | i << greenshift | i << blueshift; +} + +static void fb_set_logo(struct fb_info *info, + const struct linux_logo *logo, u8 *dst, + int depth) +{ + int i, j, k; + const u8 *src = logo->data; + u8 xor = (info->fix.visual == FB_VISUAL_MONO01) ? 0xff : 0; + u8 fg = 1, d; + + switch (fb_get_color_depth(&info->var, &info->fix)) { + case 1: + fg = 1; + break; + case 2: + fg = 3; + break; + default: + fg = 7; + break; + } + + if (info->fix.visual == FB_VISUAL_MONO01 || + info->fix.visual == FB_VISUAL_MONO10) + fg = ~((u8) (0xfff << info->var.green.length)); + + switch (depth) { + case 4: + for (i = 0; i < logo->height; i++) + for (j = 0; j < logo->width; src++) { + *dst++ = *src >> 4; + j++; + if (j < logo->width) { + *dst++ = *src & 0x0f; + j++; + } + } + break; + case 1: + for (i = 0; i < logo->height; i++) { + for (j = 0; j < logo->width; src++) { + d = *src ^ xor; + for (k = 7; k >= 0; k--) { + *dst++ = ((d >> k) & 1) ? fg : 0; + j++; + } + } + } + break; + } +} + +/* + * Three (3) kinds of logo maps exist. linux_logo_clut224 (>16 colors), + * linux_logo_vga16 (16 colors) and linux_logo_mono (2 colors). Depending on + * the visual format and color depth of the framebuffer, the DAC, the + * pseudo_palette, and the logo data will be adjusted accordingly. + * + * Case 1 - linux_logo_clut224: + * Color exceeds the number of console colors (16), thus we set the hardware DAC + * using fb_set_cmap() appropriately. The "needs_cmapreset" flag will be set. + * + * For visuals that require color info from the pseudo_palette, we also construct + * one for temporary use. The "needs_directpalette" or "needs_truepalette" flags + * will be set. + * + * Case 2 - linux_logo_vga16: + * The number of colors just matches the console colors, thus there is no need + * to set the DAC or the pseudo_palette. However, the bitmap is packed, ie, + * each byte contains color information for two pixels (upper and lower nibble). + * To be consistent with fb_imageblit() usage, we therefore separate the two + * nibbles into separate bytes. The "depth" flag will be set to 4. + * + * Case 3 - linux_logo_mono: + * This is similar with Case 2. Each byte contains information for 8 pixels. + * We isolate each bit and expand each into a byte. The "depth" flag will + * be set to 1. + */ +static struct logo_data { + int depth; + int needs_directpalette; + int needs_truepalette; + int needs_cmapreset; + const struct linux_logo *logo; +} fb_logo __read_mostly; + +static void fb_rotate_logo_ud(const u8 *in, u8 *out, u32 width, u32 height) +{ + u32 size = width * height, i; + + out += size - 1; + + for (i = size; i--; ) + *out-- = *in++; +} + +static void fb_rotate_logo_cw(const u8 *in, u8 *out, u32 width, u32 height) +{ + int i, j, h = height - 1; + + for (i = 0; i < height; i++) + for (j = 0; j < width; j++) + out[height * j + h - i] = *in++; +} + +static void fb_rotate_logo_ccw(const u8 *in, u8 *out, u32 width, u32 height) +{ + int i, j, w = width - 1; + + for (i = 0; i < height; i++) + for (j = 0; j < width; j++) + out[height * (w - j) + i] = *in++; +} + +static void fb_rotate_logo(struct fb_info *info, u8 *dst, + struct fb_image *image, int rotate) +{ + u32 tmp; + + if (rotate == FB_ROTATE_UD) { + fb_rotate_logo_ud(image->data, dst, image->width, + image->height); + image->dx = info->var.xres - image->width - image->dx; + image->dy = info->var.yres - image->height - image->dy; + } else if (rotate == FB_ROTATE_CW) { + fb_rotate_logo_cw(image->data, dst, image->width, + image->height); + tmp = image->width; + image->width = image->height; + image->height = tmp; + tmp = image->dy; + image->dy = image->dx; + image->dx = info->var.xres - image->width - tmp; + } else if (rotate == FB_ROTATE_CCW) { + fb_rotate_logo_ccw(image->data, dst, image->width, + image->height); + tmp = image->width; + image->width = image->height; + image->height = tmp; + tmp = image->dx; + image->dx = image->dy; + image->dy = info->var.yres - image->height - tmp; + } + + image->data = dst; +} + +static void fb_do_show_logo(struct fb_info *info, struct fb_image *image, + int rotate, unsigned int num) +{ + unsigned int x; + + if (rotate == FB_ROTATE_UR) { + for (x = 0; + x < num && image->dx + image->width <= info->var.xres; + x++) { + info->fbops->fb_imageblit(info, image); + image->dx += image->width + 8; + } + } else if (rotate == FB_ROTATE_UD) { + for (x = 0; x < num && image->dx >= 0; x++) { + info->fbops->fb_imageblit(info, image); + image->dx -= image->width + 8; + } + } else if (rotate == FB_ROTATE_CW) { + for (x = 0; + x < num && image->dy + image->height <= info->var.yres; + x++) { + info->fbops->fb_imageblit(info, image); + image->dy += image->height + 8; + } + } else if (rotate == FB_ROTATE_CCW) { + for (x = 0; x < num && image->dy >= 0; x++) { + info->fbops->fb_imageblit(info, image); + image->dy -= image->height + 8; + } + } +} + +static int fb_show_logo_line(struct fb_info *info, int rotate, + const struct linux_logo *logo, int y, + unsigned int n) +{ + u32 *palette = NULL, *saved_pseudo_palette = NULL; + unsigned char *logo_new = NULL, *logo_rotate = NULL; + struct fb_image image; + + /* Return if the frame buffer is not mapped or suspended */ + if (logo == NULL || info->state != FBINFO_STATE_RUNNING || + info->flags & FBINFO_MODULE) + return 0; + + image.depth = 8; + image.data = logo->data; + + if (fb_logo.needs_cmapreset) + fb_set_logocmap(info, logo); + + if (fb_logo.needs_truepalette || + fb_logo.needs_directpalette) { + palette = kmalloc(256 * 4, GFP_KERNEL); + if (palette == NULL) + return 0; + + if (fb_logo.needs_truepalette) + fb_set_logo_truepalette(info, logo, palette); + else + fb_set_logo_directpalette(info, logo, palette); + + saved_pseudo_palette = info->pseudo_palette; + info->pseudo_palette = palette; + } + + if (fb_logo.depth <= 4) { + logo_new = kmalloc(logo->width * logo->height, GFP_KERNEL); + if (logo_new == NULL) { + kfree(palette); + if (saved_pseudo_palette) + info->pseudo_palette = saved_pseudo_palette; + return 0; + } + image.data = logo_new; + fb_set_logo(info, logo, logo_new, fb_logo.depth); + } + + image.dx = 0; + image.dy = y; + image.width = logo->width; + image.height = logo->height; + + if (rotate) { + logo_rotate = kmalloc(logo->width * + logo->height, GFP_KERNEL); + if (logo_rotate) + fb_rotate_logo(info, logo_rotate, &image, rotate); + } + + fb_do_show_logo(info, &image, rotate, n); + + kfree(palette); + if (saved_pseudo_palette != NULL) + info->pseudo_palette = saved_pseudo_palette; + kfree(logo_new); + kfree(logo_rotate); + return logo->height; +} + + +#ifdef CONFIG_FB_LOGO_EXTRA + +#define FB_LOGO_EX_NUM_MAX 10 +static struct logo_data_extra { + const struct linux_logo *logo; + unsigned int n; +} fb_logo_ex[FB_LOGO_EX_NUM_MAX]; +static unsigned int fb_logo_ex_num; + +void fb_append_extra_logo(const struct linux_logo *logo, unsigned int n) +{ + if (!n || fb_logo_ex_num == FB_LOGO_EX_NUM_MAX) + return; + + fb_logo_ex[fb_logo_ex_num].logo = logo; + fb_logo_ex[fb_logo_ex_num].n = n; + fb_logo_ex_num++; +} + +static int fb_prepare_extra_logos(struct fb_info *info, unsigned int height, + unsigned int yres) +{ + unsigned int i; + + /* FIXME: logo_ex supports only truecolor fb. */ + if (info->fix.visual != FB_VISUAL_TRUECOLOR) + fb_logo_ex_num = 0; + + for (i = 0; i < fb_logo_ex_num; i++) { + if (fb_logo_ex[i].logo->type != fb_logo.logo->type) { + fb_logo_ex[i].logo = NULL; + continue; + } + height += fb_logo_ex[i].logo->height; + if (height > yres) { + height -= fb_logo_ex[i].logo->height; + fb_logo_ex_num = i; + break; + } + } + return height; +} + +static int fb_show_extra_logos(struct fb_info *info, int y, int rotate) +{ + unsigned int i; + + for (i = 0; i < fb_logo_ex_num; i++) + y += fb_show_logo_line(info, rotate, + fb_logo_ex[i].logo, y, fb_logo_ex[i].n); + + return y; +} + +#else /* !CONFIG_FB_LOGO_EXTRA */ + +static inline int fb_prepare_extra_logos(struct fb_info *info, + unsigned int height, + unsigned int yres) +{ + return height; +} + +static inline int fb_show_extra_logos(struct fb_info *info, int y, int rotate) +{ + return y; +} + +#endif /* CONFIG_FB_LOGO_EXTRA */ + + +int fb_prepare_logo(struct fb_info *info, int rotate) +{ + int depth = fb_get_color_depth(&info->var, &info->fix); + unsigned int yres; + + memset(&fb_logo, 0, sizeof(struct logo_data)); + + if (info->flags & FBINFO_MISC_TILEBLITTING || + info->flags & FBINFO_MODULE) + return 0; + + if (info->fix.visual == FB_VISUAL_DIRECTCOLOR) { + depth = info->var.blue.length; + if (info->var.red.length < depth) + depth = info->var.red.length; + if (info->var.green.length < depth) + depth = info->var.green.length; + } + + if (info->fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR && depth > 4) { + /* assume console colormap */ + depth = 4; + } + + /* Return if no suitable logo was found */ + fb_logo.logo = fb_find_logo(depth); + + if (!fb_logo.logo) { + return 0; + } + + if (rotate == FB_ROTATE_UR || rotate == FB_ROTATE_UD) + yres = info->var.yres; + else + yres = info->var.xres; + + if (fb_logo.logo->height > yres) { + fb_logo.logo = NULL; + return 0; + } + + /* What depth we asked for might be different from what we get */ + if (fb_logo.logo->type == LINUX_LOGO_CLUT224) + fb_logo.depth = 8; + else if (fb_logo.logo->type == LINUX_LOGO_VGA16) + fb_logo.depth = 4; + else + fb_logo.depth = 1; + + + if (fb_logo.depth > 4 && depth > 4) { + switch (info->fix.visual) { + case FB_VISUAL_TRUECOLOR: + fb_logo.needs_truepalette = 1; + break; + case FB_VISUAL_DIRECTCOLOR: + fb_logo.needs_directpalette = 1; + fb_logo.needs_cmapreset = 1; + break; + case FB_VISUAL_PSEUDOCOLOR: + fb_logo.needs_cmapreset = 1; + break; + } + } + + return fb_prepare_extra_logos(info, fb_logo.logo->height, yres); +} + +int fb_show_logo(struct fb_info *info, int rotate) +{ + int y; + + y = fb_show_logo_line(info, rotate, fb_logo.logo, 0, + num_online_cpus()); + y = fb_show_extra_logos(info, y, rotate); + + return y; +} +#else +int fb_prepare_logo(struct fb_info *info, int rotate) { return 0; } +int fb_show_logo(struct fb_info *info, int rotate) { return 0; } +#endif /* CONFIG_LOGO */ +EXPORT_SYMBOL(fb_show_logo); + +static void *fb_seq_start(struct seq_file *m, loff_t *pos) +{ + mutex_lock(®istration_lock); + return (*pos < FB_MAX) ? pos : NULL; +} + +static void *fb_seq_next(struct seq_file *m, void *v, loff_t *pos) +{ + (*pos)++; + return (*pos < FB_MAX) ? pos : NULL; +} + +static void fb_seq_stop(struct seq_file *m, void *v) +{ + mutex_unlock(®istration_lock); +} + +static int fb_seq_show(struct seq_file *m, void *v) +{ + int i = *(loff_t *)v; + struct fb_info *fi = registered_fb[i]; + + if (fi) + seq_printf(m, "%d %s\n", fi->node, fi->fix.id); + return 0; +} + +static const struct seq_operations proc_fb_seq_ops = { + .start = fb_seq_start, + .next = fb_seq_next, + .stop = fb_seq_stop, + .show = fb_seq_show, +}; + +static int proc_fb_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &proc_fb_seq_ops); +} + +static const struct file_operations fb_proc_fops = { + .owner = THIS_MODULE, + .open = proc_fb_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +/* + * We hold a reference to the fb_info in file->private_data, + * but if the current registered fb has changed, we don't + * actually want to use it. + * + * So look up the fb_info using the inode minor number, + * and just verify it against the reference we have. + */ +static struct fb_info *file_fb_info(struct file *file) +{ + struct inode *inode = file_inode(file); + int fbidx = iminor(inode); + struct fb_info *info = registered_fb[fbidx]; + + if (info != file->private_data) + info = NULL; + return info; +} + +static ssize_t +fb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) +{ + unsigned long p = *ppos; + struct fb_info *info = file_fb_info(file); + u8 *buffer, *dst; + u8 __iomem *src; + int c, cnt = 0, err = 0; + unsigned long total_size; + + if (!info || ! info->screen_base) + return -ENODEV; + + if (info->state != FBINFO_STATE_RUNNING) + return -EPERM; + + if (info->fbops->fb_read) + return info->fbops->fb_read(info, buf, count, ppos); + + total_size = info->screen_size; + + if (total_size == 0) + total_size = info->fix.smem_len; + + if (p >= total_size) + return 0; + + if (count >= total_size) + count = total_size; + + if (count + p > total_size) + count = total_size - p; + + buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, + GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + src = (u8 __iomem *) (info->screen_base + p); + + if (info->fbops->fb_sync) + info->fbops->fb_sync(info); + + while (count) { + c = (count > PAGE_SIZE) ? PAGE_SIZE : count; + dst = buffer; + fb_memcpy_fromfb(dst, src, c); + dst += c; + src += c; + + if (copy_to_user(buf, buffer, c)) { + err = -EFAULT; + break; + } + *ppos += c; + buf += c; + cnt += c; + count -= c; + } + + kfree(buffer); + + return (err) ? err : cnt; +} + +static ssize_t +fb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) +{ + unsigned long p = *ppos; + struct fb_info *info = file_fb_info(file); + u8 *buffer, *src; + u8 __iomem *dst; + int c, cnt = 0, err = 0; + unsigned long total_size; + + if (!info || !info->screen_base) + return -ENODEV; + + if (info->state != FBINFO_STATE_RUNNING) + return -EPERM; + + if (info->fbops->fb_write) + return info->fbops->fb_write(info, buf, count, ppos); + + total_size = info->screen_size; + + if (total_size == 0) + total_size = info->fix.smem_len; + + if (p > total_size) + return -EFBIG; + + if (count > total_size) { + err = -EFBIG; + count = total_size; + } + + if (count + p > total_size) { + if (!err) + err = -ENOSPC; + + count = total_size - p; + } + + buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, + GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + dst = (u8 __iomem *) (info->screen_base + p); + + if (info->fbops->fb_sync) + info->fbops->fb_sync(info); + + while (count) { + c = (count > PAGE_SIZE) ? PAGE_SIZE : count; + src = buffer; + + if (copy_from_user(src, buf, c)) { + err = -EFAULT; + break; + } + + fb_memcpy_tofb(dst, src, c); + dst += c; + src += c; + *ppos += c; + buf += c; + cnt += c; + count -= c; + } + + kfree(buffer); + + return (cnt) ? cnt : err; +} + +int +fb_pan_display(struct fb_info *info, struct fb_var_screeninfo *var) +{ + struct fb_fix_screeninfo *fix = &info->fix; + unsigned int yres = info->var.yres; + int err = 0; + + if (var->yoffset > 0) { + if (var->vmode & FB_VMODE_YWRAP) { + if (!fix->ywrapstep || (var->yoffset % fix->ywrapstep)) + err = -EINVAL; + else + yres = 0; + } else if (!fix->ypanstep || (var->yoffset % fix->ypanstep)) + err = -EINVAL; + } + + if (var->xoffset > 0 && (!fix->xpanstep || + (var->xoffset % fix->xpanstep))) + err = -EINVAL; + + if (err || !info->fbops->fb_pan_display || + var->yoffset > info->var.yres_virtual - yres || + var->xoffset > info->var.xres_virtual - info->var.xres) + return -EINVAL; + + if ((err = info->fbops->fb_pan_display(var, info))) + return err; + info->var.xoffset = var->xoffset; + info->var.yoffset = var->yoffset; + if (var->vmode & FB_VMODE_YWRAP) + info->var.vmode |= FB_VMODE_YWRAP; + else + info->var.vmode &= ~FB_VMODE_YWRAP; + return 0; +} +EXPORT_SYMBOL(fb_pan_display); + +static int fb_check_caps(struct fb_info *info, struct fb_var_screeninfo *var, + u32 activate) +{ + struct fb_event event; + struct fb_blit_caps caps, fbcaps; + int err = 0; + + memset(&caps, 0, sizeof(caps)); + memset(&fbcaps, 0, sizeof(fbcaps)); + caps.flags = (activate & FB_ACTIVATE_ALL) ? 1 : 0; + event.info = info; + event.data = ∩︀ + fb_notifier_call_chain(FB_EVENT_GET_REQ, &event); + info->fbops->fb_get_caps(info, &fbcaps, var); + + if (((fbcaps.x ^ caps.x) & caps.x) || + ((fbcaps.y ^ caps.y) & caps.y) || + (fbcaps.len < caps.len)) + err = -EINVAL; + + return err; +} + +int +fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var) +{ + int flags = info->flags; + int ret = 0; + + if (var->activate & FB_ACTIVATE_INV_MODE) { + struct fb_videomode mode1, mode2; + + fb_var_to_videomode(&mode1, var); + fb_var_to_videomode(&mode2, &info->var); + /* make sure we don't delete the videomode of current var */ + ret = fb_mode_is_equal(&mode1, &mode2); + + if (!ret) { + struct fb_event event; + + event.info = info; + event.data = &mode1; + ret = fb_notifier_call_chain(FB_EVENT_MODE_DELETE, &event); + } + + if (!ret) + fb_delete_videomode(&mode1, &info->modelist); + + + ret = (ret) ? -EINVAL : 0; + goto done; + } + + if ((var->activate & FB_ACTIVATE_FORCE) || + memcmp(&info->var, var, sizeof(struct fb_var_screeninfo))) { + u32 activate = var->activate; + + /* When using FOURCC mode, make sure the red, green, blue and + * transp fields are set to 0. + */ + if ((info->fix.capabilities & FB_CAP_FOURCC) && + var->grayscale > 1) { + if (var->red.offset || var->green.offset || + var->blue.offset || var->transp.offset || + var->red.length || var->green.length || + var->blue.length || var->transp.length || + var->red.msb_right || var->green.msb_right || + var->blue.msb_right || var->transp.msb_right) + return -EINVAL; + } + + if (!info->fbops->fb_check_var) { + *var = info->var; + goto done; + } + + ret = info->fbops->fb_check_var(var, info); + + if (ret) + goto done; + + if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) { + struct fb_var_screeninfo old_var; + struct fb_videomode mode; + + if (info->fbops->fb_get_caps) { + ret = fb_check_caps(info, var, activate); + + if (ret) + goto done; + } + + old_var = info->var; + info->var = *var; + + if (info->fbops->fb_set_par) { + ret = info->fbops->fb_set_par(info); + + if (ret) { + info->var = old_var; + printk(KERN_WARNING "detected " + "fb_set_par error, " + "error code: %d\n", ret); + goto done; + } + } + + fb_pan_display(info, &info->var); + fb_set_cmap(&info->cmap, info); + fb_var_to_videomode(&mode, &info->var); + + if (info->modelist.prev && info->modelist.next && + !list_empty(&info->modelist)) + ret = fb_add_videomode(&mode, &info->modelist); + + if (!ret && (flags & FBINFO_MISC_USEREVENT)) { + struct fb_event event; + int evnt = (activate & FB_ACTIVATE_ALL) ? + FB_EVENT_MODE_CHANGE_ALL : + FB_EVENT_MODE_CHANGE; + + info->flags &= ~FBINFO_MISC_USEREVENT; + event.info = info; + event.data = &mode; + fb_notifier_call_chain(evnt, &event); + } + } + } + + done: + return ret; +} +EXPORT_SYMBOL(fb_set_var); + +int +fb_blank(struct fb_info *info, int blank) +{ + struct fb_event event; + int ret = -EINVAL, early_ret; + + if (blank > FB_BLANK_POWERDOWN) + blank = FB_BLANK_POWERDOWN; + + event.info = info; + event.data = ␣ + + early_ret = fb_notifier_call_chain(FB_EARLY_EVENT_BLANK, &event); + + if (info->fbops->fb_blank) + ret = info->fbops->fb_blank(blank, info); + + if (!ret) + fb_notifier_call_chain(FB_EVENT_BLANK, &event); + else { + /* + * if fb_blank is failed then revert effects of + * the early blank event. + */ + if (!early_ret) + fb_notifier_call_chain(FB_R_EARLY_EVENT_BLANK, &event); + } + + return ret; +} +EXPORT_SYMBOL(fb_blank); + +static long do_fb_ioctl(struct fb_info *info, unsigned int cmd, + unsigned long arg) +{ + struct fb_ops *fb; + struct fb_var_screeninfo var; + struct fb_fix_screeninfo fix; + struct fb_con2fbmap con2fb; + struct fb_cmap cmap_from; + struct fb_cmap_user cmap; + struct fb_event event; + void __user *argp = (void __user *)arg; + long ret = 0; + + switch (cmd) { + case FBIOGET_VSCREENINFO: + if (!lock_fb_info(info)) + return -ENODEV; + var = info->var; + unlock_fb_info(info); + + ret = copy_to_user(argp, &var, sizeof(var)) ? -EFAULT : 0; + break; + case FBIOPUT_VSCREENINFO: + if (copy_from_user(&var, argp, sizeof(var))) + return -EFAULT; + console_lock(); + if (!lock_fb_info(info)) { + console_unlock(); + return -ENODEV; + } + info->flags |= FBINFO_MISC_USEREVENT; + ret = fb_set_var(info, &var); + info->flags &= ~FBINFO_MISC_USEREVENT; + unlock_fb_info(info); + console_unlock(); + if (!ret && copy_to_user(argp, &var, sizeof(var))) + ret = -EFAULT; + break; + case FBIOGET_FSCREENINFO: + if (!lock_fb_info(info)) + return -ENODEV; + fix = info->fix; + unlock_fb_info(info); + + ret = copy_to_user(argp, &fix, sizeof(fix)) ? -EFAULT : 0; + break; + case FBIOPUTCMAP: + if (copy_from_user(&cmap, argp, sizeof(cmap))) + return -EFAULT; + ret = fb_set_user_cmap(&cmap, info); + break; + case FBIOGETCMAP: + if (copy_from_user(&cmap, argp, sizeof(cmap))) + return -EFAULT; + if (!lock_fb_info(info)) + return -ENODEV; + cmap_from = info->cmap; + unlock_fb_info(info); + ret = fb_cmap_to_user(&cmap_from, &cmap); + break; + case FBIOPAN_DISPLAY: + if (copy_from_user(&var, argp, sizeof(var))) + return -EFAULT; + console_lock(); + if (!lock_fb_info(info)) { + console_unlock(); + return -ENODEV; + } + ret = fb_pan_display(info, &var); + unlock_fb_info(info); + console_unlock(); + if (ret == 0 && copy_to_user(argp, &var, sizeof(var))) + return -EFAULT; + break; + case FBIO_CURSOR: + ret = -EINVAL; + break; + case FBIOGET_CON2FBMAP: + if (copy_from_user(&con2fb, argp, sizeof(con2fb))) + return -EFAULT; + if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES) + return -EINVAL; + con2fb.framebuffer = -1; + event.data = &con2fb; + if (!lock_fb_info(info)) + return -ENODEV; + event.info = info; + fb_notifier_call_chain(FB_EVENT_GET_CONSOLE_MAP, &event); + unlock_fb_info(info); + ret = copy_to_user(argp, &con2fb, sizeof(con2fb)) ? -EFAULT : 0; + break; + case FBIOPUT_CON2FBMAP: + if (copy_from_user(&con2fb, argp, sizeof(con2fb))) + return -EFAULT; + if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES) + return -EINVAL; + if (con2fb.framebuffer < 0 || con2fb.framebuffer >= FB_MAX) + return -EINVAL; + if (!registered_fb[con2fb.framebuffer]) + request_module("fb%d", con2fb.framebuffer); + if (!registered_fb[con2fb.framebuffer]) { + ret = -EINVAL; + break; + } + event.data = &con2fb; + console_lock(); + if (!lock_fb_info(info)) { + console_unlock(); + return -ENODEV; + } + event.info = info; + ret = fb_notifier_call_chain(FB_EVENT_SET_CONSOLE_MAP, &event); + unlock_fb_info(info); + console_unlock(); + break; + case FBIOBLANK: + console_lock(); + if (!lock_fb_info(info)) { + console_unlock(); + return -ENODEV; + } + info->flags |= FBINFO_MISC_USEREVENT; + ret = fb_blank(info, arg); + info->flags &= ~FBINFO_MISC_USEREVENT; + unlock_fb_info(info); + console_unlock(); + break; + default: + if (!lock_fb_info(info)) + return -ENODEV; + fb = info->fbops; + if (fb->fb_ioctl) + ret = fb->fb_ioctl(info, cmd, arg); + else + ret = -ENOTTY; + unlock_fb_info(info); + } + return ret; +} + +static long fb_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct fb_info *info = file_fb_info(file); + + if (!info) + return -ENODEV; + return do_fb_ioctl(info, cmd, arg); +} + +#ifdef CONFIG_COMPAT +struct fb_fix_screeninfo32 { + char id[16]; + compat_caddr_t smem_start; + u32 smem_len; + u32 type; + u32 type_aux; + u32 visual; + u16 xpanstep; + u16 ypanstep; + u16 ywrapstep; + u32 line_length; + compat_caddr_t mmio_start; + u32 mmio_len; + u32 accel; + u16 reserved[3]; +}; + +struct fb_cmap32 { + u32 start; + u32 len; + compat_caddr_t red; + compat_caddr_t green; + compat_caddr_t blue; + compat_caddr_t transp; +}; + +static int fb_getput_cmap(struct fb_info *info, unsigned int cmd, + unsigned long arg) +{ + struct fb_cmap_user __user *cmap; + struct fb_cmap32 __user *cmap32; + __u32 data; + int err; + + cmap = compat_alloc_user_space(sizeof(*cmap)); + cmap32 = compat_ptr(arg); + + if (copy_in_user(&cmap->start, &cmap32->start, 2 * sizeof(__u32))) + return -EFAULT; + + if (get_user(data, &cmap32->red) || + put_user(compat_ptr(data), &cmap->red) || + get_user(data, &cmap32->green) || + put_user(compat_ptr(data), &cmap->green) || + get_user(data, &cmap32->blue) || + put_user(compat_ptr(data), &cmap->blue) || + get_user(data, &cmap32->transp) || + put_user(compat_ptr(data), &cmap->transp)) + return -EFAULT; + + err = do_fb_ioctl(info, cmd, (unsigned long) cmap); + + if (!err) { + if (copy_in_user(&cmap32->start, + &cmap->start, + 2 * sizeof(__u32))) + err = -EFAULT; + } + return err; +} + +static int do_fscreeninfo_to_user(struct fb_fix_screeninfo *fix, + struct fb_fix_screeninfo32 __user *fix32) +{ + __u32 data; + int err; + + err = copy_to_user(&fix32->id, &fix->id, sizeof(fix32->id)); + + data = (__u32) (unsigned long) fix->smem_start; + err |= put_user(data, &fix32->smem_start); + + err |= put_user(fix->smem_len, &fix32->smem_len); + err |= put_user(fix->type, &fix32->type); + err |= put_user(fix->type_aux, &fix32->type_aux); + err |= put_user(fix->visual, &fix32->visual); + err |= put_user(fix->xpanstep, &fix32->xpanstep); + err |= put_user(fix->ypanstep, &fix32->ypanstep); + err |= put_user(fix->ywrapstep, &fix32->ywrapstep); + err |= put_user(fix->line_length, &fix32->line_length); + + data = (__u32) (unsigned long) fix->mmio_start; + err |= put_user(data, &fix32->mmio_start); + + err |= put_user(fix->mmio_len, &fix32->mmio_len); + err |= put_user(fix->accel, &fix32->accel); + err |= copy_to_user(fix32->reserved, fix->reserved, + sizeof(fix->reserved)); + + if (err) + return -EFAULT; + return 0; +} + +static int fb_get_fscreeninfo(struct fb_info *info, unsigned int cmd, + unsigned long arg) +{ + mm_segment_t old_fs; + struct fb_fix_screeninfo fix; + struct fb_fix_screeninfo32 __user *fix32; + int err; + + fix32 = compat_ptr(arg); + + old_fs = get_fs(); + set_fs(KERNEL_DS); + err = do_fb_ioctl(info, cmd, (unsigned long) &fix); + set_fs(old_fs); + + if (!err) + err = do_fscreeninfo_to_user(&fix, fix32); + + return err; +} + +static long fb_compat_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct fb_info *info = file_fb_info(file); + struct fb_ops *fb; + long ret = -ENOIOCTLCMD; + + if (!info) + return -ENODEV; + fb = info->fbops; + switch(cmd) { + case FBIOGET_VSCREENINFO: + case FBIOPUT_VSCREENINFO: + case FBIOPAN_DISPLAY: + case FBIOGET_CON2FBMAP: + case FBIOPUT_CON2FBMAP: + arg = (unsigned long) compat_ptr(arg); + case FBIOBLANK: + ret = do_fb_ioctl(info, cmd, arg); + break; + + case FBIOGET_FSCREENINFO: + ret = fb_get_fscreeninfo(info, cmd, arg); + break; + + case FBIOGETCMAP: + case FBIOPUTCMAP: + ret = fb_getput_cmap(info, cmd, arg); + break; + + default: + if (fb->fb_compat_ioctl) + ret = fb->fb_compat_ioctl(info, cmd, arg); + break; + } + return ret; +} +#endif + +static int +fb_mmap(struct file *file, struct vm_area_struct * vma) +{ + struct fb_info *info = file_fb_info(file); + struct fb_ops *fb; + unsigned long mmio_pgoff; + unsigned long start; + u32 len; + + if (!info) + return -ENODEV; + fb = info->fbops; + if (!fb) + return -ENODEV; + mutex_lock(&info->mm_lock); + if (fb->fb_mmap) { + int res; + res = fb->fb_mmap(info, vma); + mutex_unlock(&info->mm_lock); + return res; + } + + /* + * Ugh. This can be either the frame buffer mapping, or + * if pgoff points past it, the mmio mapping. + */ + start = info->fix.smem_start; + len = info->fix.smem_len; + mmio_pgoff = PAGE_ALIGN((start & ~PAGE_MASK) + len) >> PAGE_SHIFT; + if (vma->vm_pgoff >= mmio_pgoff) { + if (info->var.accel_flags) { + mutex_unlock(&info->mm_lock); + return -EINVAL; + } + + vma->vm_pgoff -= mmio_pgoff; + start = info->fix.mmio_start; + len = info->fix.mmio_len; + } + mutex_unlock(&info->mm_lock); + + vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); + fb_pgprotect(file, vma, start); + + return vm_iomap_memory(vma, start, len); +} + +static int +fb_open(struct inode *inode, struct file *file) +__acquires(&info->lock) +__releases(&info->lock) +{ + int fbidx = iminor(inode); + struct fb_info *info; + int res = 0; + + info = get_fb_info(fbidx); + if (!info) { + request_module("fb%d", fbidx); + info = get_fb_info(fbidx); + if (!info) + return -ENODEV; + } + if (IS_ERR(info)) + return PTR_ERR(info); + + mutex_lock(&info->lock); + if (!try_module_get(info->fbops->owner)) { + res = -ENODEV; + goto out; + } + file->private_data = info; + if (info->fbops->fb_open) { + res = info->fbops->fb_open(info,1); + if (res) + module_put(info->fbops->owner); + } +#ifdef CONFIG_FB_DEFERRED_IO + if (info->fbdefio) + fb_deferred_io_open(info, inode, file); +#endif +out: + mutex_unlock(&info->lock); + if (res) + put_fb_info(info); + return res; +} + +static int +fb_release(struct inode *inode, struct file *file) +__acquires(&info->lock) +__releases(&info->lock) +{ + struct fb_info * const info = file->private_data; + + mutex_lock(&info->lock); + if (info->fbops->fb_release) + info->fbops->fb_release(info,1); + module_put(info->fbops->owner); + mutex_unlock(&info->lock); + put_fb_info(info); + return 0; +} + +static const struct file_operations fb_fops = { + .owner = THIS_MODULE, + .read = fb_read, + .write = fb_write, + .unlocked_ioctl = fb_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = fb_compat_ioctl, +#endif + .mmap = fb_mmap, + .open = fb_open, + .release = fb_release, +#ifdef HAVE_ARCH_FB_UNMAPPED_AREA + .get_unmapped_area = get_fb_unmapped_area, +#endif +#ifdef CONFIG_FB_DEFERRED_IO + .fsync = fb_deferred_io_fsync, +#endif + .llseek = default_llseek, +}; + +struct class *fb_class; +EXPORT_SYMBOL(fb_class); + +static int fb_check_foreignness(struct fb_info *fi) +{ + const bool foreign_endian = fi->flags & FBINFO_FOREIGN_ENDIAN; + + fi->flags &= ~FBINFO_FOREIGN_ENDIAN; + +#ifdef __BIG_ENDIAN + fi->flags |= foreign_endian ? 0 : FBINFO_BE_MATH; +#else + fi->flags |= foreign_endian ? FBINFO_BE_MATH : 0; +#endif /* __BIG_ENDIAN */ + + if (fi->flags & FBINFO_BE_MATH && !fb_be_math(fi)) { + pr_err("%s: enable CONFIG_FB_BIG_ENDIAN to " + "support this framebuffer\n", fi->fix.id); + return -ENOSYS; + } else if (!(fi->flags & FBINFO_BE_MATH) && fb_be_math(fi)) { + pr_err("%s: enable CONFIG_FB_LITTLE_ENDIAN to " + "support this framebuffer\n", fi->fix.id); + return -ENOSYS; + } + + return 0; +} + +static bool apertures_overlap(struct aperture *gen, struct aperture *hw) +{ + /* is the generic aperture base the same as the HW one */ + if (gen->base == hw->base) + return true; + /* is the generic aperture base inside the hw base->hw base+size */ + if (gen->base > hw->base && gen->base < hw->base + hw->size) + return true; + return false; +} + +static bool fb_do_apertures_overlap(struct apertures_struct *gena, + struct apertures_struct *hwa) +{ + int i, j; + if (!hwa || !gena) + return false; + + for (i = 0; i < hwa->count; ++i) { + struct aperture *h = &hwa->ranges[i]; + for (j = 0; j < gena->count; ++j) { + struct aperture *g = &gena->ranges[j]; + printk(KERN_DEBUG "checking generic (%llx %llx) vs hw (%llx %llx)\n", + (unsigned long long)g->base, + (unsigned long long)g->size, + (unsigned long long)h->base, + (unsigned long long)h->size); + if (apertures_overlap(g, h)) + return true; + } + } + + return false; +} + +static int do_unregister_framebuffer(struct fb_info *fb_info); + +#define VGA_FB_PHYS 0xA0000 +static int do_remove_conflicting_framebuffers(struct apertures_struct *a, + const char *name, bool primary) +{ + int i, ret; + + /* check all firmware fbs and kick off if the base addr overlaps */ + for (i = 0 ; i < FB_MAX; i++) { + struct apertures_struct *gen_aper; + if (!registered_fb[i]) + continue; + + if (!(registered_fb[i]->flags & FBINFO_MISC_FIRMWARE)) + continue; + + gen_aper = registered_fb[i]->apertures; + if (fb_do_apertures_overlap(gen_aper, a) || + (primary && gen_aper && gen_aper->count && + gen_aper->ranges[0].base == VGA_FB_PHYS)) { + + printk(KERN_INFO "fb: switching to %s from %s\n", + name, registered_fb[i]->fix.id); + ret = do_unregister_framebuffer(registered_fb[i]); + if (ret) + return ret; + } + } + + return 0; +} + +static int do_register_framebuffer(struct fb_info *fb_info) +{ + int i, ret; + struct fb_event event; + struct fb_videomode mode; + + if (fb_check_foreignness(fb_info)) + return -ENOSYS; + + ret = do_remove_conflicting_framebuffers(fb_info->apertures, + fb_info->fix.id, + fb_is_primary_device(fb_info)); + if (ret) + return ret; + + if (num_registered_fb == FB_MAX) + return -ENXIO; + + num_registered_fb++; + for (i = 0 ; i < FB_MAX; i++) + if (!registered_fb[i]) + break; + fb_info->node = i; + atomic_set(&fb_info->count, 1); + mutex_init(&fb_info->lock); + mutex_init(&fb_info->mm_lock); + + fb_info->dev = device_create(fb_class, fb_info->device, + MKDEV(FB_MAJOR, i), NULL, "fb%d", i); + if (IS_ERR(fb_info->dev)) { + /* Not fatal */ + printk(KERN_WARNING "Unable to create device for framebuffer %d; errno = %ld\n", i, PTR_ERR(fb_info->dev)); + fb_info->dev = NULL; + } else + fb_init_device(fb_info); + + if (fb_info->pixmap.addr == NULL) { + fb_info->pixmap.addr = kmalloc(FBPIXMAPSIZE, GFP_KERNEL); + if (fb_info->pixmap.addr) { + fb_info->pixmap.size = FBPIXMAPSIZE; + fb_info->pixmap.buf_align = 1; + fb_info->pixmap.scan_align = 1; + fb_info->pixmap.access_align = 32; + fb_info->pixmap.flags = FB_PIXMAP_DEFAULT; + } + } + fb_info->pixmap.offset = 0; + + if (!fb_info->pixmap.blit_x) + fb_info->pixmap.blit_x = ~(u32)0; + + if (!fb_info->pixmap.blit_y) + fb_info->pixmap.blit_y = ~(u32)0; + + if (!fb_info->modelist.prev || !fb_info->modelist.next) + INIT_LIST_HEAD(&fb_info->modelist); + + if (fb_info->skip_vt_switch) + pm_vt_switch_required(fb_info->dev, false); + else + pm_vt_switch_required(fb_info->dev, true); + + fb_var_to_videomode(&mode, &fb_info->var); + fb_add_videomode(&mode, &fb_info->modelist); + registered_fb[i] = fb_info; + + event.info = fb_info; + console_lock(); + if (!lock_fb_info(fb_info)) { + console_unlock(); + return -ENODEV; + } + + fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event); + unlock_fb_info(fb_info); + console_unlock(); + return 0; +} + +static int do_unregister_framebuffer(struct fb_info *fb_info) +{ + struct fb_event event; + int i, ret = 0; + + i = fb_info->node; + if (i < 0 || i >= FB_MAX || registered_fb[i] != fb_info) + return -EINVAL; + + console_lock(); + if (!lock_fb_info(fb_info)) { + console_unlock(); + return -ENODEV; + } + + event.info = fb_info; + ret = fb_notifier_call_chain(FB_EVENT_FB_UNBIND, &event); + unlock_fb_info(fb_info); + console_unlock(); + + if (ret) + return -EINVAL; + + pm_vt_switch_unregister(fb_info->dev); + + unlink_framebuffer(fb_info); + if (fb_info->pixmap.addr && + (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT)) + kfree(fb_info->pixmap.addr); + fb_destroy_modelist(&fb_info->modelist); + registered_fb[i] = NULL; + num_registered_fb--; + fb_cleanup_device(fb_info); + event.info = fb_info; + console_lock(); + fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event); + console_unlock(); + + /* this may free fb info */ + put_fb_info(fb_info); + return 0; +} + +int unlink_framebuffer(struct fb_info *fb_info) +{ + int i; + + i = fb_info->node; + if (i < 0 || i >= FB_MAX || registered_fb[i] != fb_info) + return -EINVAL; + + if (fb_info->dev) { + device_destroy(fb_class, MKDEV(FB_MAJOR, i)); + fb_info->dev = NULL; + } + return 0; +} +EXPORT_SYMBOL(unlink_framebuffer); + +int remove_conflicting_framebuffers(struct apertures_struct *a, + const char *name, bool primary) +{ + int ret; + + mutex_lock(®istration_lock); + ret = do_remove_conflicting_framebuffers(a, name, primary); + mutex_unlock(®istration_lock); + + return ret; +} +EXPORT_SYMBOL(remove_conflicting_framebuffers); + +/** + * register_framebuffer - registers a frame buffer device + * @fb_info: frame buffer info structure + * + * Registers a frame buffer device @fb_info. + * + * Returns negative errno on error, or zero for success. + * + */ +int +register_framebuffer(struct fb_info *fb_info) +{ + int ret; + + mutex_lock(®istration_lock); + ret = do_register_framebuffer(fb_info); + mutex_unlock(®istration_lock); + + return ret; +} +EXPORT_SYMBOL(register_framebuffer); + +/** + * unregister_framebuffer - releases a frame buffer device + * @fb_info: frame buffer info structure + * + * Unregisters a frame buffer device @fb_info. + * + * Returns negative errno on error, or zero for success. + * + * This function will also notify the framebuffer console + * to release the driver. + * + * This is meant to be called within a driver's module_exit() + * function. If this is called outside module_exit(), ensure + * that the driver implements fb_open() and fb_release() to + * check that no processes are using the device. + */ +int +unregister_framebuffer(struct fb_info *fb_info) +{ + int ret; + + mutex_lock(®istration_lock); + ret = do_unregister_framebuffer(fb_info); + mutex_unlock(®istration_lock); + + return ret; +} +EXPORT_SYMBOL(unregister_framebuffer); + +/** + * fb_set_suspend - low level driver signals suspend + * @info: framebuffer affected + * @state: 0 = resuming, !=0 = suspending + * + * This is meant to be used by low level drivers to + * signal suspend/resume to the core & clients. + * It must be called with the console semaphore held + */ +void fb_set_suspend(struct fb_info *info, int state) +{ + struct fb_event event; + + event.info = info; + if (state) { + fb_notifier_call_chain(FB_EVENT_SUSPEND, &event); + info->state = FBINFO_STATE_SUSPENDED; + } else { + info->state = FBINFO_STATE_RUNNING; + fb_notifier_call_chain(FB_EVENT_RESUME, &event); + } +} +EXPORT_SYMBOL(fb_set_suspend); + +/** + * fbmem_init - init frame buffer subsystem + * + * Initialize the frame buffer subsystem. + * + * NOTE: This function is _only_ to be called by drivers/char/mem.c. + * + */ + +static int __init +fbmem_init(void) +{ + proc_create("fb", 0, NULL, &fb_proc_fops); + + if (register_chrdev(FB_MAJOR,"fb",&fb_fops)) + printk("unable to get major %d for fb devs\n", FB_MAJOR); + + fb_class = class_create(THIS_MODULE, "graphics"); + if (IS_ERR(fb_class)) { + printk(KERN_WARNING "Unable to create fb class; errno = %ld\n", PTR_ERR(fb_class)); + fb_class = NULL; + } + return 0; +} + +#ifdef MODULE +module_init(fbmem_init); +static void __exit +fbmem_exit(void) +{ + remove_proc_entry("fb", NULL); + class_destroy(fb_class); + unregister_chrdev(FB_MAJOR, "fb"); +} + +module_exit(fbmem_exit); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Framebuffer base"); +#else +subsys_initcall(fbmem_init); +#endif + +int fb_new_modelist(struct fb_info *info) +{ + struct fb_event event; + struct fb_var_screeninfo var = info->var; + struct list_head *pos, *n; + struct fb_modelist *modelist; + struct fb_videomode *m, mode; + int err = 1; + + list_for_each_safe(pos, n, &info->modelist) { + modelist = list_entry(pos, struct fb_modelist, list); + m = &modelist->mode; + fb_videomode_to_var(&var, m); + var.activate = FB_ACTIVATE_TEST; + err = fb_set_var(info, &var); + fb_var_to_videomode(&mode, &var); + if (err || !fb_mode_is_equal(m, &mode)) { + list_del(pos); + kfree(pos); + } + } + + err = 1; + + if (!list_empty(&info->modelist)) { + event.info = info; + err = fb_notifier_call_chain(FB_EVENT_NEW_MODELIST, &event); + } + + return err; +} + +static char *video_options[FB_MAX] __read_mostly; +static int ofonly __read_mostly; + +/** + * fb_get_options - get kernel boot parameters + * @name: framebuffer name as it would appear in + * the boot parameter line + * (video=:) + * @option: the option will be stored here + * + * NOTE: Needed to maintain backwards compatibility + */ +int fb_get_options(const char *name, char **option) +{ + char *opt, *options = NULL; + int retval = 0; + int name_len = strlen(name), i; + + if (name_len && ofonly && strncmp(name, "offb", 4)) + retval = 1; + + if (name_len && !retval) { + for (i = 0; i < FB_MAX; i++) { + if (video_options[i] == NULL) + continue; + if (!video_options[i][0]) + continue; + opt = video_options[i]; + if (!strncmp(name, opt, name_len) && + opt[name_len] == ':') + options = opt + name_len + 1; + } + } + /* No match, pass global option */ + if (!options && option && fb_mode_option) + options = kstrdup(fb_mode_option, GFP_KERNEL); + if (options && !strncmp(options, "off", 3)) + retval = 1; + + if (option) + *option = options; + + return retval; +} +EXPORT_SYMBOL(fb_get_options); + +#ifndef MODULE +/** + * video_setup - process command line options + * @options: string of options + * + * Process command line options for frame buffer subsystem. + * + * NOTE: This function is a __setup and __init function. + * It only stores the options. Drivers have to call + * fb_get_options() as necessary. + * + * Returns zero. + * + */ +static int __init video_setup(char *options) +{ + int i, global = 0; + + if (!options || !*options) + global = 1; + + if (!global && !strncmp(options, "ofonly", 6)) { + ofonly = 1; + global = 1; + } + + if (!global && !strchr(options, ':')) { + fb_mode_option = options; + global = 1; + } + + if (!global) { + for (i = 0; i < FB_MAX; i++) { + if (video_options[i] == NULL) { + video_options[i] = options; + break; + } + + } + } + + return 1; +} +__setup("video=", video_setup); +#endif + +MODULE_LICENSE("GPL"); diff --git a/drivers/video/fbdev/core/fbmon.c b/drivers/video/fbdev/core/fbmon.c new file mode 100644 index 00000000000..c204ebe6187 --- /dev/null +++ b/drivers/video/fbdev/core/fbmon.c @@ -0,0 +1,1592 @@ +/* + * linux/drivers/video/fbmon.c + * + * Copyright (C) 2002 James Simmons + * + * Credits: + * + * The EDID Parser is a conglomeration from the following sources: + * + * 1. SciTech SNAP Graphics Architecture + * Copyright (C) 1991-2002 SciTech Software, Inc. All rights reserved. + * + * 2. XFree86 4.3.0, interpret_edid.c + * Copyright 1998 by Egbert Eich + * + * 3. John Fremlin and + * Ani Joshi + * + * Generalized Timing Formula is derived from: + * + * GTF Spreadsheet by Andy Morrish (1/5/97) + * available at http://www.vesa.org + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + * + */ +#include +#include +#include +#include +#include