summaryrefslogtreecommitdiffstats
path: root/kernel/auditfilter.c
AgeCommit message (Expand)Author
2012-10-12audit: optimize audit_compare_dname_pathJeff Layton
2012-10-12audit: make audit_compare_dname_path use parent_len helperEric Paris
2012-10-12audit: remove dirlen argument to audit_compare_dname_pathJeff Layton
2012-10-12audit: set the name_len in audit_inode for parent lookupsJeff Layton
2012-09-17userns: Convert the audit loginuid to be a kuidEric W. Biederman
2012-09-17audit: Add typespecific uid and gid comparatorsEric W. Biederman
2012-09-17audit: Remove the unused uid parameter from audit_receive_filterEric W. Biederman
2012-09-17audit: Use current instead of NETLINK_CREDS() in audit_filterEric W. Biederman
2012-01-17audit: allow interfield comparison in audit rulesEric Paris
2012-01-17audit: allow audit matching on inode gidEric Paris
2012-01-17audit: allow matching on obj_uidEric Paris
2012-01-17audit: reject entry,always rulesEric Paris
2012-01-17audit: make filetype matching consistent with other filtersEric Paris
2011-03-03netlink: kill loginuid/sessionid/sid members from struct netlink_skb_parmsPatrick McHardy
2010-10-30Audit: add support to match lsm labels on user audit messagesMiloslav Trmac
2010-07-28audit: do not get and put just to free a watchEric Paris
2010-07-28Audit: clean up the audit_watch splitEric Paris
2010-03-30include cleanup: Update gfp.h and slab.h includes to prepare for breaking imp...Tejun Heo
2009-06-24Audit: clean up all op= output to include string quotingEric Paris
2009-06-23Audit: move audit_get_nd completely into audit_watchEric Paris
2009-06-23audit: seperate audit inode watches into a subfileEric Paris
2009-06-23Audit: dereferencing krule as if it were an audit_watchEric Paris
2009-06-23Audit: fix audit watch use after freeEric Paris
2009-05-06inotify: use GFP_NOFS in kernel_event() to work around a lockdep false-positiveWu Fengguang
2009-04-05make the e->rule.xxx shorter in kernel auditfilter.cZhenwen Xu
2009-01-04audit: validate comparison operations, store them in sane formAl Viro
2009-01-04clean up audit_rule_{add,del} a bitAl Viro
2009-01-04audit rules ordering, part 2Al Viro
2009-01-04fixing audit rule ordering mess, part 1Al Viro
2009-01-04audit_update_lsm_rules() misses the audit_inode_hash[] onesAl Viro
2008-11-15Fix inotify watch removal/umount racesAl Viro
2008-08-01Re: [PATCH] the loginuid field should be output in all AUDIT_CONFIG_CHANGE au...zhangxiliang
2008-06-24[PATCH] remove useless argument type in audit_filter_user()Peng Haitao
2008-06-24[PATCH] audit: fix kernel-doc parameter notationRandy Dunlap
2008-04-29Merge branch 'audit.b50' of git://git.kernel.org/pub/scm/linux/kernel/git/vir...Linus Torvalds
2008-04-29Remove duplicated unlikely() in IS_ERR()Hirofumi Nakagawa
2008-04-28[PATCH] new predicate - AUDIT_FILETYPEAl Viro
2008-04-28[PATCH 2/2] audit: fix sparse shadowed variable warningsHarvey Harrison
2008-04-28[PATCH 1/2] audit: move extern declarations to audit.hHarvey Harrison
2008-04-28Audit: collect sessionid in netlink messagesEric Paris
2008-04-19Audit: Final renamings and cleanupAhmed S. Darwish
2008-04-19Audit: internally use the new LSM audit hooksAhmed S. Darwish
2008-04-19Audit: use new LSM hooks instead of SELinux exportsAhmed S. Darwish
2008-02-14Introduce path_put()Jan Blunck
2008-02-14Embed a struct path into struct nameidata instead of nd->{dentry,mnt}Jan Blunck
2008-02-01[AUDIT] make audit=0 really stop audit messagesEric Paris
2007-10-21[PATCH] audit: watching subtreesAl Viro
2007-10-18whitespace fixes: audit filteringDaniel Walker
2007-07-22[PATCH] allow audit filtering on bit & operationsEric Paris
2007-07-22[PATCH] audit: fix broken class-based syscall auditKlaus Weidner
a id='n383' href='#n383'>383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460
/*
 * Copyright (C) Overkiz SAS 2012
 *
 * Author: Boris BREZILLON <b.brezillon@overkiz.com>
 * License terms: GNU General Public License (GPL) version 2
 */

#include <linux/module.h>
#include <linux/init.h>
#include <linux/clocksource.h>
#include <linux/clockchips.h>
#include <linux/interrupt.h>
#include <linux/irq.h>

#include <linux/clk.h>
#include <linux/err.h>
#include <linux/ioport.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/atmel_tc.h>
#include <linux/pwm.h>
#include <linux/of_device.h>
#include <linux/slab.h>

#define NPWM	6

#define ATMEL_TC_ACMR_MASK	(ATMEL_TC_ACPA | ATMEL_TC_ACPC |	\
				 ATMEL_TC_AEEVT | ATMEL_TC_ASWTRG)

#define ATMEL_TC_BCMR_MASK	(ATMEL_TC_BCPB | ATMEL_TC_BCPC |	\
				 ATMEL_TC_BEEVT | ATMEL_TC_BSWTRG)

struct atmel_tcb_pwm_device {
	enum pwm_polarity polarity;	/* PWM polarity */
	unsigned div;			/* PWM clock divider */
	unsigned duty;			/* PWM duty expressed in clk cycles */
	unsigned period;		/* PWM period expressed in clk cycles */
};

struct atmel_tcb_pwm_chip {
	struct pwm_chip chip;
	spinlock_t lock;
	struct atmel_tc *tc;
	struct atmel_tcb_pwm_device *pwms[NPWM];
};

static inline struct atmel_tcb_pwm_chip *to_tcb_chip(struct pwm_chip *chip)
{
	return container_of(chip, struct atmel_tcb_pwm_chip, chip);
}

static int atmel_tcb_pwm_set_polarity(struct pwm_chip *chip,
				      struct pwm_device *pwm,
				      enum pwm_polarity polarity)
{
	struct atmel_tcb_pwm_device *tcbpwm = pwm_get_chip_data(pwm);

	tcbpwm->polarity = polarity;

	return 0;
}

static int atmel_tcb_pwm_request(struct pwm_chip *chip,
				 struct pwm_device *pwm)
{
	struct atmel_tcb_pwm_chip *tcbpwmc = to_tcb_chip(chip);
	struct atmel_tcb_pwm_device *tcbpwm;
	struct atmel_tc *tc = tcbpwmc->tc;
	void __iomem *regs = tc->regs;
	unsigned group = pwm->hwpwm / 2;
	unsigned index = pwm->hwpwm % 2;
	unsigned cmr;
	int ret;

	tcbpwm = devm_kzalloc(chip->dev, sizeof(*tcbpwm), GFP_KERNEL);
	if (!tcbpwm)
		return -ENOMEM;

	ret = clk_prepare_enable(tc->clk[group]);
	if (ret) {
		devm_kfree(chip->dev, tcbpwm);
		return ret;
	}

	pwm_set_chip_data(pwm, tcbpwm);
	tcbpwm->polarity = PWM_POLARITY_NORMAL;
	tcbpwm->duty = 0;
	tcbpwm->period = 0;
	tcbpwm->div = 0;

	spin_lock(&tcbpwmc->lock);
	cmr = __raw_readl(regs + ATMEL_TC_REG(group, CMR));
	/*
	 * Get init config from Timer Counter registers if
	 * Timer Counter is already configured as a PWM generator.
	 */
	if (cmr & ATMEL_TC_WAVE) {
		if (index == 0)
			tcbpwm->duty =
				__raw_readl(regs + ATMEL_TC_REG(group, RA));
		else
			tcbpwm->duty =
				__raw_readl(regs + ATMEL_TC_REG(group, RB));

		tcbpwm->div = cmr & ATMEL_TC_TCCLKS;
		tcbpwm->period = __raw_readl(regs + ATMEL_TC_REG(group, RC));
		cmr &= (ATMEL_TC_TCCLKS | ATMEL_TC_ACMR_MASK |
			ATMEL_TC_BCMR_MASK);
	} else
		cmr = 0;

	cmr |= ATMEL_TC_WAVE | ATMEL_TC_WAVESEL_UP_AUTO | ATMEL_TC_EEVT_XC0;
	__raw_writel(cmr, regs + ATMEL_TC_REG(group, CMR));
	spin_unlock(&tcbpwmc->lock);

	tcbpwmc->pwms[pwm->hwpwm] = tcbpwm;

	return 0;
}

static void atmel_tcb_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
{
	struct atmel_tcb_pwm_chip *tcbpwmc = to_tcb_chip(chip);
	struct atmel_tcb_pwm_device *tcbpwm = pwm_get_chip_data(pwm);
	struct atmel_tc *tc = tcbpwmc->tc;

	clk_disable_unprepare(tc->clk[pwm->hwpwm / 2]);
	tcbpwmc->pwms[pwm->hwpwm] = NULL;
	devm_kfree(chip->dev, tcbpwm);
}

static void atmel_tcb_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
{
	struct atmel_tcb_pwm_chip *tcbpwmc = to_tcb_chip(chip);
	struct atmel_tcb_pwm_device *tcbpwm = pwm_get_chip_data(pwm);
	struct atmel_tc *tc = tcbpwmc->tc;
	void __iomem *regs = tc->regs;
	unsigned group = pwm->hwpwm / 2;
	unsigned index = pwm->hwpwm % 2;
	unsigned cmr;
	enum pwm_polarity polarity = tcbpwm->polarity;

	/*
	 * If duty is 0 the timer will be stopped and we have to
	 * configure the output correctly on software trigger:
	 *  - set output to high if PWM_POLARITY_INVERSED
	 *  - set output to low if PWM_POLARITY_NORMAL
	 *
	 * This is why we're reverting polarity in this case.
	 */
	if (tcbpwm->duty == 0)
		polarity = !polarity;

	spin_lock(&tcbpwmc->lock);
	cmr = __raw_readl(regs + ATMEL_TC_REG(group, CMR));

	/* flush old setting and set the new one */
	if (index == 0) {
		cmr &= ~ATMEL_TC_ACMR_MASK;
		if (polarity == PWM_POLARITY_INVERSED)
			cmr |= ATMEL_TC_ASWTRG_CLEAR;
		else
			cmr |= ATMEL_TC_ASWTRG_SET;
	} else {
		cmr &= ~ATMEL_TC_BCMR_MASK;
		if (polarity == PWM_POLARITY_INVERSED)
			cmr |= ATMEL_TC_BSWTRG_CLEAR;
		else
			cmr |= ATMEL_TC_BSWTRG_SET;
	}

	__raw_writel(cmr, regs + ATMEL_TC_REG(group, CMR));

	/*
	 * Use software trigger to apply the new setting.
	 * If both PWM devices in this group are disabled we stop the clock.
	 */
	if (!(cmr & (ATMEL_TC_ACPC | ATMEL_TC_BCPC)))
		__raw_writel(ATMEL_TC_SWTRG | ATMEL_TC_CLKDIS,
			     regs + ATMEL_TC_REG(group, CCR));
	else
		__raw_writel(ATMEL_TC_SWTRG, regs +
			     ATMEL_TC_REG(group, CCR));

	spin_unlock(&tcbpwmc->lock);
}

static int atmel_tcb_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
{
	struct atmel_tcb_pwm_chip *tcbpwmc = to_tcb_chip(chip);
	struct atmel_tcb_pwm_device *tcbpwm = pwm_get_chip_data(pwm);
	struct atmel_tc *tc = tcbpwmc->tc;
	void __iomem *regs = tc->regs;
	unsigned group = pwm->hwpwm / 2;
	unsigned index = pwm->hwpwm % 2;
	u32 cmr;
	enum pwm_polarity polarity = tcbpwm->polarity;

	/*
	 * If duty is 0 the timer will be stopped and we have to
	 * configure the output correctly on software trigger:
	 *  - set output to high if PWM_POLARITY_INVERSED
	 *  - set output to low if PWM_POLARITY_NORMAL
	 *
	 * This is why we're reverting polarity in this case.
	 */
	if (tcbpwm->duty == 0)
		polarity = !polarity;

	spin_lock(&tcbpwmc->lock);
	cmr = __raw_readl(regs + ATMEL_TC_REG(group, CMR));

	/* flush old setting and set the new one */
	cmr &= ~ATMEL_TC_TCCLKS;

	if (index == 0) {
		cmr &= ~ATMEL_TC_ACMR_MASK;

		/* Set CMR flags according to given polarity */
		if (polarity == PWM_POLARITY_INVERSED)
			cmr |= ATMEL_TC_ASWTRG_CLEAR;
		else
			cmr |= ATMEL_TC_ASWTRG_SET;
	} else {
		cmr &= ~ATMEL_TC_BCMR_MASK;
		if (polarity == PWM_POLARITY_INVERSED)
			cmr |= ATMEL_TC_BSWTRG_CLEAR;
		else
			cmr |= ATMEL_TC_BSWTRG_SET;
	}

	/*
	 * If duty is 0 or equal to period there's no need to register
	 * a specific action on RA/RB and RC compare.
	 * The output will be configured on software trigger and keep
	 * this config till next config call.
	 */
	if (tcbpwm->duty != tcbpwm->period && tcbpwm->duty > 0) {
		if (index == 0) {
			if (polarity == PWM_POLARITY_INVERSED)
				cmr |= ATMEL_TC_ACPA_SET | ATMEL_TC_ACPC_CLEAR;
			else
				cmr |= ATMEL_TC_ACPA_CLEAR | ATMEL_TC_ACPC_SET;
		}