summaryrefslogtreecommitdiffstats
path: root/net/mac80211/tkip.c
AgeCommit message (Expand)Author
2020-01-15mac80211: Fix TKIP replay protection immediately after key setupJouni Malinen
2019-07-08Merge branch 'linus' of git://git.kernel.org/pub/scm/linux/kernel/git/herbert...Linus Torvalds
2019-06-20net/mac80211: move WEP handling to ARC4 library interfaceArd Biesheuvel
2019-06-19treewide: Replace GPLv2 boilerplate/reference with SPDX - rule 500Thomas Gleixner
2016-02-24mac80211: move TKIP TX IVs to public part of key structEliad Peller
2013-12-18mac80211: fix checkpatch errorsWeilong Chen
2013-05-16mac80211: use just spin_lock() in ieee80211_get_tkip_p2k()Johannes Berg
2013-02-15mac80211: use spin_lock_bh() for TKIP lockJohannes Berg
2012-06-22mac80211: remove TKIP debugJohannes Berg
2012-06-05net: mac80211: Convert printk(KERN_DEBUG to pr_debugJoe Perches
2011-10-31net: Add export.h for EXPORT_SYMBOL/THIS_MODULE to non-modulesPaul Gortmaker
2011-07-15mac80211: allow driver access to TKIP RX P1KJohannes Berg
2011-07-08mac80211: allow driver to generate P1K for IV32Johannes Berg
2011-07-08mac80211: fix TKIP races, make API easier to useJohannes Berg
2011-04-04mac80211: remove the dependency on crypto_blkcipherFelix Fietkau
2010-07-08mac80211: remove wep dependencyJohn W. Linville
2010-01-22mac80211: pass vif and station to update_tkip_keyJohannes Berg
2010-01-19mac80211: move control.hw_key assignmentJohannes Berg
2009-12-22mac80211 : fix a race with update_tkip_keygregor kowski
2009-11-18mac80211: use fixed broadcast addressJohannes Berg
2009-05-06mac80211: add driver ops wrappersJohannes Berg
2008-10-27mac80211: convert to %pM away from print_macJohannes Berg
2008-09-15mac80211: share STA information with driverJohannes Berg
2008-06-27mac80211: Let drivers have access to TKIP key offets for TX and RX MICLuis R. Rodriguez
2008-06-27mac80211: rename TKIP debugging Kconfig symbolJohannes Berg
2008-06-14mac80211: tkip.c use a local struct tkip_ctx in ieee80211_get_tkip_keyHarvey Harrison
2008-06-14mac80211: tkip.c fold ieee80211_gen_rc4key into its one callerHarvey Harrison
2008-06-14mac80211: tkip.c consolidate tkip IV writing in helperHarvey Harrison
2008-05-21mac80211: tkip.c use struct tkip_ctx in phase 2 key mixingHarvey Harrison
2008-05-21mac80211: tkip.c use struct tkip_ctx in phase 1 key mixingHarvey Harrison
2008-05-21mac80211: add a struct to hold tkip contextHarvey Harrison
2008-05-21mac80211: add const, remove unused function, make one function staticHarvey Harrison
2008-05-14mac80211: tkip.c use kernel-provided infrastructureHarvey Harrison
2008-04-30mac80211: incorrect shift directionHarvey Harrison
2008-04-08mac80211: rename filesJohannes Berg
2008-03-25mac80211: allows driver to request a Phase 1 RX keyEmmanuel Grumbach
2008-03-25mac80211: get a TKIP phase key from skbEmmanuel Grumbach
2007-10-10[PATCH] mac80211: fix TKIP IV updateJohannes Berg
2007-10-10[NET]: Introduce and use print_mac() and DECLARE_MAC_BUF()Joe Perches
2007-10-10[MAC80211]: embed key conf in key, fix driver interfaceJohannes Berg
2007-05-05[MAC80211]: Add mac80211 wireless stack.Jiri Benc
='#n326'>326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360
/*
 * LoCoMo keyboard driver for Linux-based ARM PDAs:
 * 	- SHARP Zaurus Collie (SL-5500)
 * 	- SHARP Zaurus Poodle (SL-5600)
 *
 * Copyright (c) 2005 John Lenz
 * Based on from xtkbd.c
 *
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 *
 */

#include <linux/slab.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/input.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>

#include <asm/hardware/locomo.h>
#include <asm/irq.h>

MODULE_AUTHOR("John Lenz <lenz@cs.wisc.edu>");
MODULE_DESCRIPTION("LoCoMo keyboard driver");
MODULE_LICENSE("GPL");

#define LOCOMOKBD_NUMKEYS	128

#define KEY_ACTIVITY		KEY_F16
#define KEY_CONTACT		KEY_F18
#define KEY_CENTER		KEY_F15

static const unsigned char
locomokbd_keycode[LOCOMOKBD_NUMKEYS] = {
	0, KEY_ESC, KEY_ACTIVITY, 0, 0, 0, 0, 0, 0, 0,				/* 0 - 9 */
	0, 0, 0, 0, 0, 0, 0, KEY_MENU, KEY_HOME, KEY_CONTACT,			/* 10 - 19 */
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,						/* 20 - 29 */
	0, 0, 0, KEY_CENTER, 0, KEY_MAIL, 0, 0, 0, 0,				/* 30 - 39 */
	0, 0, 0, 0, 0, 0, 0, 0, 0, KEY_RIGHT,					/* 40 - 49 */
	KEY_UP, KEY_LEFT, 0, 0, KEY_P, 0, KEY_O, KEY_I, KEY_Y, KEY_T,		/* 50 - 59 */
	KEY_E, KEY_W, 0, 0, 0, 0, KEY_DOWN, KEY_ENTER, 0, 0,			/* 60 - 69 */
	KEY_BACKSPACE, 0, KEY_L, KEY_U, KEY_H, KEY_R, KEY_D, KEY_Q, 0, 0,	/* 70 - 79 */
	0, 0, 0, 0, 0, 0, KEY_ENTER, KEY_RIGHTSHIFT, KEY_K, KEY_J,		/* 80 - 89 */
	KEY_G, KEY_F, KEY_X, KEY_S, 0, 0, 0, 0, 0, 0,				/* 90 - 99 */
	0, 0, KEY_DOT, 0, KEY_COMMA, KEY_N, KEY_B, KEY_C, KEY_Z, KEY_A,		/* 100 - 109 */
	KEY_LEFTSHIFT, KEY_TAB, KEY_LEFTCTRL, 0, 0, 0, 0, 0, 0, 0,		/* 110 - 119 */
	KEY_M, KEY_SPACE, KEY_V, KEY_APOSTROPHE, KEY_SLASH, 0, 0, 0		/* 120 - 128 */
};

#define KB_ROWS			16
#define KB_COLS			8
#define KB_ROWMASK(r)		(1 << (r))
#define SCANCODE(c,r)		( ((c)<<4) + (r) + 1 )

#define KB_DELAY		8
#define SCAN_INTERVAL		(HZ/10)

struct locomokbd {
	unsigned char keycode[LOCOMOKBD_NUMKEYS];
	struct input_dev *input;
	char phys[32];

	unsigned long base;
	spinlock_t lock;

	struct timer_list timer;
	unsigned long suspend_jiffies;
	unsigned int count_cancel;
};

/* helper functions for reading the keyboard matrix */
static inline void locomokbd_charge_all(unsigned long membase)
{
	locomo_writel(0x00FF, membase + LOCOMO_KSC);
}

static inline void locomokbd_activate_all(unsigned long membase)
{
	unsigned long r;

	locomo_writel(0, membase + LOCOMO_KSC);
	r = locomo_readl(membase + LOCOMO_KIC);
	r &= 0xFEFF;
	locomo_writel(r, membase + LOCOMO_KIC);
}

static inline void locomokbd_activate_col(unsigned long membase, int col)
{
	unsigned short nset;
	unsigned short nbset;

	nset = 0xFF & ~(1 << col);
	nbset = (nset << 8) + nset;
	locomo_writel(nbset, membase + LOCOMO_KSC);
}

static inline void locomokbd_reset_col(unsigned long membase, int col)
{
	unsigned short nbset;

	nbset = ((0xFF & ~(1 << col)) << 8) + 0xFF;
	locomo_writel(nbset, membase + LOCOMO_KSC);
}

/*
 * The LoCoMo keyboard only generates interrupts when a key is pressed.
 * So when a key is pressed, we enable a timer.  This timer scans the
 * keyboard, and this is how we detect when the key is released.
 */

/* Scan the hardware keyboard and push any changes up through the input layer */
static void locomokbd_scankeyboard(struct locomokbd *locomokbd)
{
	unsigned int row, col, rowd;
	unsigned long flags;
	unsigned int num_pressed;
	unsigned long membase = locomokbd->base;

	spin_lock_irqsave(&locomokbd->lock, flags);

	locomokbd_charge_all(membase);

	num_pressed = 0;
	for (col = 0; col < KB_COLS; col++) {

		locomokbd_activate_col(membase, col);
		udelay(KB_DELAY);

		rowd = ~locomo_readl(membase + LOCOMO_KIB);
		for (row = 0; row < KB_ROWS; row++) {
			unsigned int scancode, pressed, key;

			scancode = SCANCODE(col, row);
			pressed = rowd & KB_ROWMASK(row);
			key = locomokbd->keycode[scancode];

			input_report_key(locomokbd->input, key, pressed);
			if (likely(!pressed))
				continue;

			num_pressed++;

			/* The "Cancel/ESC" key is labeled "On/Off" on
			 * Collie and Poodle and should suspend the device
			 * if it was pressed for more than a second. */
			if (unlikely(key == KEY_ESC)) {
				if (!time_after(jiffies,
					locomokbd->suspend_jiffies + HZ))
					continue;
				if (locomokbd->count_cancel++
					!= (HZ/SCAN_INTERVAL + 1))
					continue;
				input_event(locomokbd->input, EV_PWR,
					KEY_SUSPEND, 1);
				locomokbd->suspend_jiffies = jiffies;
			} else
				locomokbd->count_cancel = 0;
		}
		locomokbd_reset_col(membase, col);
	}
	locomokbd_activate_all(membase);

	input_sync(locomokbd->input);

	/* if any keys are pressed, enable the timer */
	if (num_pressed)
		mod_timer(&locomokbd->timer, jiffies + SCAN_INTERVAL);
	else
		locomokbd->count_cancel = 0;

	spin_unlock_irqrestore(&locomokbd->lock, flags);
}

/*
 * LoCoMo keyboard interrupt handler.
 */
static irqreturn_t locomokbd_interrupt(int irq, void *dev_id)
{
	struct locomokbd *locomokbd = dev_id;
	u16 r;

	r = locomo_readl(locomokbd->base + LOCOMO_KIC);
	if ((r & 0x0001) == 0)
		return IRQ_HANDLED;

	locomo_writel(r & ~0x0100, locomokbd->base + LOCOMO_KIC); /* Ack */

	/** wait chattering delay **/
	udelay(100);

	locomokbd_scankeyboard(locomokbd);
	return IRQ_HANDLED;
}

/*
 * LoCoMo timer checking for released keys
 */
static void locomokbd_timer_callback(struct timer_list *t)
{
	struct locomokbd *locomokbd = from_timer(locomokbd, t, timer);

	locomokbd_scankeyboard(locomokbd);
}

static int locomokbd_open(struct input_dev *dev)
{
	struct locomokbd *locomokbd = input_get_drvdata(dev);
	u16 r;
	
	r = locomo_readl(locomokbd->base + LOCOMO_KIC) | 0x0010;
	locomo_writel(r, locomokbd->base + LOCOMO_KIC);
	return 0;
}

static void locomokbd_close(struct input_dev *dev)
{
	struct locomokbd *locomokbd = input_get_drvdata(dev);
	u16 r;
	
	r = locomo_readl(locomokbd->base + LOCOMO_KIC) & ~0x0010;
	locomo_writel(r, locomokbd->base + LOCOMO_KIC);
}

static int locomokbd_probe(struct locomo_dev *dev)
{
	struct locomokbd *locomokbd;
	struct input_dev *input_dev;
	int i, err;

	locomokbd = kzalloc(sizeof(struct locomokbd), GFP_KERNEL);
	input_dev = input_allocate_device();
	if (!locomokbd || !input_dev) {
		err = -ENOMEM;
		goto err_free_mem;
	}

	/* try and claim memory region */
	if (!request_mem_region((unsigned long