Fixed MTP to work with TWRP

This commit is contained in:
awab228 2018-06-19 23:16:04 +02:00
commit f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions

View file

@ -0,0 +1,41 @@
#
# PPS clients configuration
#
if PPS
comment "PPS clients support"
config PPS_CLIENT_KTIMER
tristate "Kernel timer client (Testing client, use for debug)"
help
If you say yes here you get support for a PPS debugging client
which uses a kernel timer to generate the PPS signal.
This driver can also be built as a module. If so, the module
will be called pps-ktimer.
config PPS_CLIENT_LDISC
tristate "PPS line discipline"
depends on PPS && TTY
help
If you say yes here you get support for a PPS source connected
with the CD (Carrier Detect) pin of your serial port.
config PPS_CLIENT_PARPORT
tristate "Parallel port PPS client"
depends on PPS && PARPORT
help
If you say yes here you get support for a PPS source connected
with the interrupt pin of your parallel port.
config PPS_CLIENT_GPIO
tristate "PPS client using GPIO"
depends on PPS
help
If you say yes here you get support for a PPS source using
GPIO. To be useful you must also register a platform device
specifying the GPIO pin and other options, usually in your board
setup.
endif

View file

@ -0,0 +1,10 @@
#
# Makefile for PPS clients.
#
obj-$(CONFIG_PPS_CLIENT_KTIMER) += pps-ktimer.o
obj-$(CONFIG_PPS_CLIENT_LDISC) += pps-ldisc.o
obj-$(CONFIG_PPS_CLIENT_PARPORT) += pps_parport.o
obj-$(CONFIG_PPS_CLIENT_GPIO) += pps-gpio.o
ccflags-$(CONFIG_PPS_DEBUG) := -DDEBUG

View file

@ -0,0 +1,213 @@
/*
* pps-gpio.c -- PPS client driver using GPIO
*
*
* Copyright (C) 2010 Ricardo Martins <rasm@fe.up.pt>
* Copyright (C) 2011 James Nuss <jamesnuss@nanometrics.ca>
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#define PPS_GPIO_NAME "pps-gpio"
#define pr_fmt(fmt) PPS_GPIO_NAME ": " fmt
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/pps_kernel.h>
#include <linux/pps-gpio.h>
#include <linux/gpio.h>
#include <linux/list.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
/* Info for each registered platform device */
struct pps_gpio_device_data {
int irq; /* IRQ used as PPS source */
struct pps_device *pps; /* PPS source device */
struct pps_source_info info; /* PPS source information */
bool assert_falling_edge;
bool capture_clear;
unsigned int gpio_pin;
};
/*
* Report the PPS event
*/
static irqreturn_t pps_gpio_irq_handler(int irq, void *data)
{
const struct pps_gpio_device_data *info;
struct pps_event_time ts;
int rising_edge;
/* Get the time stamp first */
pps_get_ts(&ts);
info = data;
rising_edge = gpio_get_value(info->gpio_pin);
if ((rising_edge && !info->assert_falling_edge) ||
(!rising_edge && info->assert_falling_edge))
pps_event(info->pps, &ts, PPS_CAPTUREASSERT, NULL);
else if (info->capture_clear &&
((rising_edge && info->assert_falling_edge) ||
(!rising_edge && !info->assert_falling_edge)))
pps_event(info->pps, &ts, PPS_CAPTURECLEAR, NULL);
return IRQ_HANDLED;
}
static unsigned long
get_irqf_trigger_flags(const struct pps_gpio_device_data *data)
{
unsigned long flags = data->assert_falling_edge ?
IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING;
if (data->capture_clear) {
flags |= ((flags & IRQF_TRIGGER_RISING) ?
IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING);
}
return flags;
}
static int pps_gpio_probe(struct platform_device *pdev)
{
struct pps_gpio_device_data *data;
const char *gpio_label;
int ret;
int pps_default_params;
const struct pps_gpio_platform_data *pdata = pdev->dev.platform_data;
struct device_node *np = pdev->dev.of_node;
/* allocate space for device info */
data = devm_kzalloc(&pdev->dev, sizeof(struct pps_gpio_device_data),
GFP_KERNEL);
if (!data)
return -ENOMEM;
if (pdata) {
data->gpio_pin = pdata->gpio_pin;
gpio_label = pdata->gpio_label;
data->assert_falling_edge = pdata->assert_falling_edge;
data->capture_clear = pdata->capture_clear;
} else {
ret = of_get_gpio(np, 0);
if (ret < 0) {
dev_err(&pdev->dev, "failed to get GPIO from device tree\n");
return ret;
}
data->gpio_pin = ret;
gpio_label = PPS_GPIO_NAME;
if (of_get_property(np, "assert-falling-edge", NULL))
data->assert_falling_edge = true;
}
/* GPIO setup */
ret = devm_gpio_request(&pdev->dev, data->gpio_pin, gpio_label);
if (ret) {
dev_err(&pdev->dev, "failed to request GPIO %u\n",
data->gpio_pin);
return ret;
}
ret = gpio_direction_input(data->gpio_pin);
if (ret) {
dev_err(&pdev->dev, "failed to set pin direction\n");
return -EINVAL;
}
/* IRQ setup */
ret = gpio_to_irq(data->gpio_pin);
if (ret < 0) {
dev_err(&pdev->dev, "failed to map GPIO to IRQ: %d\n", ret);
return -EINVAL;
}
data->irq = ret;
/* initialize PPS specific parts of the bookkeeping data structure. */
data->info.mode = PPS_CAPTUREASSERT | PPS_OFFSETASSERT |
PPS_ECHOASSERT | PPS_CANWAIT | PPS_TSFMT_TSPEC;
if (data->capture_clear)
data->info.mode |= PPS_CAPTURECLEAR | PPS_OFFSETCLEAR |
PPS_ECHOCLEAR;
data->info.owner = THIS_MODULE;
snprintf(data->info.name, PPS_MAX_NAME_LEN - 1, "%s.%d",
pdev->name, pdev->id);
/* register PPS source */
pps_default_params = PPS_CAPTUREASSERT | PPS_OFFSETASSERT;
if (data->capture_clear)
pps_default_params |= PPS_CAPTURECLEAR | PPS_OFFSETCLEAR;
data->pps = pps_register_source(&data->info, pps_default_params);
if (data->pps == NULL) {
dev_err(&pdev->dev, "failed to register IRQ %d as PPS source\n",
data->irq);
return -EINVAL;
}
/* register IRQ interrupt handler */
ret = devm_request_irq(&pdev->dev, data->irq, pps_gpio_irq_handler,
get_irqf_trigger_flags(data), data->info.name, data);
if (ret) {
pps_unregister_source(data->pps);
dev_err(&pdev->dev, "failed to acquire IRQ %d\n", data->irq);
return -EINVAL;
}
platform_set_drvdata(pdev, data);
dev_info(data->pps->dev, "Registered IRQ %d as PPS source\n",
data->irq);
return 0;
}
static int pps_gpio_remove(struct platform_device *pdev)
{
struct pps_gpio_device_data *data = platform_get_drvdata(pdev);
pps_unregister_source(data->pps);
dev_info(&pdev->dev, "removed IRQ %d as PPS source\n", data->irq);
return 0;
}
static const struct of_device_id pps_gpio_dt_ids[] = {
{ .compatible = "pps-gpio", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, pps_gpio_dt_ids);
static struct platform_driver pps_gpio_driver = {
.probe = pps_gpio_probe,
.remove = pps_gpio_remove,
.driver = {
.name = PPS_GPIO_NAME,
.owner = THIS_MODULE,
.of_match_table = pps_gpio_dt_ids,
},
};
module_platform_driver(pps_gpio_driver);
MODULE_AUTHOR("Ricardo Martins <rasm@fe.up.pt>");
MODULE_AUTHOR("James Nuss <jamesnuss@nanometrics.ca>");
MODULE_DESCRIPTION("Use GPIO pin as PPS source");
MODULE_LICENSE("GPL");
MODULE_VERSION("1.0.0");

View file

@ -0,0 +1,101 @@
/*
* pps-ktimer.c -- kernel timer test client
*
*
* Copyright (C) 2005-2006 Rodolfo Giometti <giometti@linux.it>
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/time.h>
#include <linux/timer.h>
#include <linux/pps_kernel.h>
/*
* Global variables
*/
static struct pps_device *pps;
static struct timer_list ktimer;
/*
* The kernel timer
*/
static void pps_ktimer_event(unsigned long ptr)
{
struct pps_event_time ts;
/* First of all we get the time stamp... */
pps_get_ts(&ts);
pps_event(pps, &ts, PPS_CAPTUREASSERT, NULL);
mod_timer(&ktimer, jiffies + HZ);
}
/*
* The PPS info struct
*/
static struct pps_source_info pps_ktimer_info = {
.name = "ktimer",
.path = "",
.mode = PPS_CAPTUREASSERT | PPS_OFFSETASSERT |
PPS_ECHOASSERT |
PPS_CANWAIT | PPS_TSFMT_TSPEC,
.owner = THIS_MODULE,
};
/*
* Module staff
*/
static void __exit pps_ktimer_exit(void)
{
dev_info(pps->dev, "ktimer PPS source unregistered\n");
del_timer_sync(&ktimer);
pps_unregister_source(pps);
}
static int __init pps_ktimer_init(void)
{
pps = pps_register_source(&pps_ktimer_info,
PPS_CAPTUREASSERT | PPS_OFFSETASSERT);
if (pps == NULL) {
pr_err("cannot register PPS source\n");
return -ENOMEM;
}
setup_timer(&ktimer, pps_ktimer_event, 0);
mod_timer(&ktimer, jiffies + HZ);
dev_info(pps->dev, "ktimer PPS source registered\n");
return 0;
}
module_init(pps_ktimer_init);
module_exit(pps_ktimer_exit);
MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
MODULE_DESCRIPTION("dummy PPS source by using a kernel timer (just for debug)");
MODULE_LICENSE("GPL");

View file

@ -0,0 +1,163 @@
/*
* pps-ldisc.c -- PPS line discipline
*
*
* Copyright (C) 2008 Rodolfo Giometti <giometti@linux.it>
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h>
#include <linux/serial_core.h>
#include <linux/tty.h>
#include <linux/pps_kernel.h>
#include <linux/bug.h>
#define PPS_TTY_MAGIC 0x0001
static void pps_tty_dcd_change(struct tty_struct *tty, unsigned int status)
{
struct pps_device *pps;
struct pps_event_time ts;
pps_get_ts(&ts);
pps = pps_lookup_dev(tty);
/*
* This should never fail, but the ldisc locking is very
* convoluted, so don't crash just in case.
*/
if (WARN_ON_ONCE(pps == NULL))
return;
/* Now do the PPS event report */
pps_event(pps, &ts, status ? PPS_CAPTUREASSERT :
PPS_CAPTURECLEAR, NULL);
dev_dbg(pps->dev, "PPS %s at %lu\n",
status ? "assert" : "clear", jiffies);
}
static int (*alias_n_tty_open)(struct tty_struct *tty);
static int pps_tty_open(struct tty_struct *tty)
{
struct pps_source_info info;
struct tty_driver *drv = tty->driver;
int index = tty->index + drv->name_base;
struct pps_device *pps;
int ret;
info.owner = THIS_MODULE;
info.dev = NULL;
snprintf(info.name, PPS_MAX_NAME_LEN, "%s%d", drv->driver_name, index);
snprintf(info.path, PPS_MAX_NAME_LEN, "/dev/%s%d", drv->name, index);
info.mode = PPS_CAPTUREBOTH | \
PPS_OFFSETASSERT | PPS_OFFSETCLEAR | \
PPS_CANWAIT | PPS_TSFMT_TSPEC;
pps = pps_register_source(&info, PPS_CAPTUREBOTH | \
PPS_OFFSETASSERT | PPS_OFFSETCLEAR);
if (pps == NULL) {
pr_err("cannot register PPS source \"%s\"\n", info.path);
return -ENOMEM;
}
pps->lookup_cookie = tty;
/* Now open the base class N_TTY ldisc */
ret = alias_n_tty_open(tty);
if (ret < 0) {
pr_err("cannot open tty ldisc \"%s\"\n", info.path);
goto err_unregister;
}
dev_info(pps->dev, "source \"%s\" added\n", info.path);
return 0;
err_unregister:
pps_unregister_source(pps);
return ret;
}
static void (*alias_n_tty_close)(struct tty_struct *tty);
static void pps_tty_close(struct tty_struct *tty)
{
struct pps_device *pps = pps_lookup_dev(tty);
alias_n_tty_close(tty);
if (WARN_ON(!pps))
return;
dev_info(pps->dev, "removed\n");
pps_unregister_source(pps);
}
static struct tty_ldisc_ops pps_ldisc_ops;
/*
* Module stuff
*/
static int __init pps_tty_init(void)
{
int err;
/* Inherit the N_TTY's ops */
n_tty_inherit_ops(&pps_ldisc_ops);
/* Save N_TTY's open()/close() methods */
alias_n_tty_open = pps_ldisc_ops.open;
alias_n_tty_close = pps_ldisc_ops.close;
/* Init PPS_TTY data */
pps_ldisc_ops.owner = THIS_MODULE;
pps_ldisc_ops.magic = PPS_TTY_MAGIC;
pps_ldisc_ops.name = "pps_tty";
pps_ldisc_ops.dcd_change = pps_tty_dcd_change;
pps_ldisc_ops.open = pps_tty_open;
pps_ldisc_ops.close = pps_tty_close;
err = tty_register_ldisc(N_PPS, &pps_ldisc_ops);
if (err)
pr_err("can't register PPS line discipline\n");
else
pr_info("PPS line discipline registered\n");
return err;
}
static void __exit pps_tty_cleanup(void)
{
int err;
err = tty_unregister_ldisc(N_PPS);
if (err)
pr_err("can't unregister PPS line discipline\n");
else
pr_info("PPS line discipline removed\n");
}
module_init(pps_tty_init);
module_exit(pps_tty_cleanup);
MODULE_ALIAS_LDISC(N_PPS);
MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
MODULE_DESCRIPTION("PPS TTY device driver");
MODULE_LICENSE("GPL");

View file

@ -0,0 +1,250 @@
/*
* pps_parport.c -- kernel parallel port PPS client
*
*
* Copyright (C) 2009 Alexander Gordeev <lasaine@lvk.cs.msu.su>
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* TODO:
* implement echo over SEL pin
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/irqnr.h>
#include <linux/time.h>
#include <linux/slab.h>
#include <linux/parport.h>
#include <linux/pps_kernel.h>
#define DRVDESC "parallel port PPS client"
/* module parameters */
#define CLEAR_WAIT_MAX 100
#define CLEAR_WAIT_MAX_ERRORS 5
static unsigned int clear_wait = 100;
MODULE_PARM_DESC(clear_wait,
"Maximum number of port reads when polling for signal clear,"
" zero turns clear edge capture off entirely");
module_param(clear_wait, uint, 0);
/* internal per port structure */
struct pps_client_pp {
struct pardevice *pardev; /* parport device */
struct pps_device *pps; /* PPS device */
unsigned int cw; /* port clear timeout */
unsigned int cw_err; /* number of timeouts */
};
static inline int signal_is_set(struct parport *port)
{
return (port->ops->read_status(port) & PARPORT_STATUS_ACK) != 0;
}
/* parport interrupt handler */
static void parport_irq(void *handle)
{
struct pps_event_time ts_assert, ts_clear;
struct pps_client_pp *dev = handle;
struct parport *port = dev->pardev->port;
unsigned int i;
unsigned long flags;
/* first of all we get the time stamp... */
pps_get_ts(&ts_assert);
if (dev->cw == 0)
/* clear edge capture disabled */
goto out_assert;
/* try capture the clear edge */
/* We have to disable interrupts here. The idea is to prevent
* other interrupts on the same processor to introduce random
* lags while polling the port. Reading from IO port is known
* to take approximately 1us while other interrupt handlers can
* take much more potentially.
*
* Interrupts won't be disabled for a long time because the
* number of polls is limited by clear_wait parameter which is
* kept rather low. So it should never be an issue.
*/
local_irq_save(flags);
/* check the signal (no signal means the pulse is lost this time) */
if (!signal_is_set(port)) {
local_irq_restore(flags);
dev_err(dev->pps->dev, "lost the signal\n");
goto out_assert;
}
/* poll the port until the signal is unset */
for (i = dev->cw; i; i--)
if (!signal_is_set(port)) {
pps_get_ts(&ts_clear);
local_irq_restore(flags);
dev->cw_err = 0;
goto out_both;
}
local_irq_restore(flags);
/* timeout */
dev->cw_err++;
if (dev->cw_err >= CLEAR_WAIT_MAX_ERRORS) {
dev_err(dev->pps->dev, "disabled clear edge capture after %d"
" timeouts\n", dev->cw_err);
dev->cw = 0;
dev->cw_err = 0;
}
out_assert:
/* fire assert event */
pps_event(dev->pps, &ts_assert,
PPS_CAPTUREASSERT, NULL);
return;
out_both:
/* fire assert event */
pps_event(dev->pps, &ts_assert,
PPS_CAPTUREASSERT, NULL);
/* fire clear event */
pps_event(dev->pps, &ts_clear,
PPS_CAPTURECLEAR, NULL);
return;
}
static void parport_attach(struct parport *port)
{
struct pps_client_pp *device;
struct pps_source_info info = {
.name = KBUILD_MODNAME,
.path = "",
.mode = PPS_CAPTUREBOTH | \
PPS_OFFSETASSERT | PPS_OFFSETCLEAR | \
PPS_ECHOASSERT | PPS_ECHOCLEAR | \
PPS_CANWAIT | PPS_TSFMT_TSPEC,
.owner = THIS_MODULE,
.dev = NULL
};
device = kzalloc(sizeof(struct pps_client_pp), GFP_KERNEL);
if (!device) {
pr_err("memory allocation failed, not attaching\n");
return;
}
device->pardev = parport_register_device(port, KBUILD_MODNAME,
NULL, NULL, parport_irq, PARPORT_FLAG_EXCL, device);
if (!device->pardev) {
pr_err("couldn't register with %s\n", port->name);
goto err_free;
}
if (parport_claim_or_block(device->pardev) < 0) {
pr_err("couldn't claim %s\n", port->name);
goto err_unregister_dev;
}
device->pps = pps_register_source(&info,
PPS_CAPTUREBOTH | PPS_OFFSETASSERT | PPS_OFFSETCLEAR);
if (device->pps == NULL) {
pr_err("couldn't register PPS source\n");
goto err_release_dev;
}
device->cw = clear_wait;
port->ops->enable_irq(port);
pr_info("attached to %s\n", port->name);
return;
err_release_dev:
parport_release(device->pardev);
err_unregister_dev:
parport_unregister_device(device->pardev);
err_free:
kfree(device);
}
static void parport_detach(struct parport *port)
{
struct pardevice *pardev = port->cad;
struct pps_client_pp *device;
/* FIXME: oooh, this is ugly! */
if (strcmp(pardev->name, KBUILD_MODNAME))
/* not our port */
return;
device = pardev->private;
port->ops->disable_irq(port);
pps_unregister_source(device->pps);
parport_release(pardev);
parport_unregister_device(pardev);
kfree(device);
}
static struct parport_driver pps_parport_driver = {
.name = KBUILD_MODNAME,
.attach = parport_attach,
.detach = parport_detach,
};
/* module staff */
static int __init pps_parport_init(void)
{
int ret;
pr_info(DRVDESC "\n");
if (clear_wait > CLEAR_WAIT_MAX) {
pr_err("clear_wait value should be not greater"
" then %d\n", CLEAR_WAIT_MAX);
return -EINVAL;
}
ret = parport_register_driver(&pps_parport_driver);
if (ret) {
pr_err("unable to register with parport\n");
return ret;
}
return 0;
}
static void __exit pps_parport_exit(void)
{
parport_unregister_driver(&pps_parport_driver);
}
module_init(pps_parport_init);
module_exit(pps_parport_exit);
MODULE_AUTHOR("Alexander Gordeev <lasaine@lvk.cs.msu.su>");
MODULE_DESCRIPTION(DRVDESC);
MODULE_LICENSE("GPL");