mirror of
https://github.com/linux-msm/cdba.git
synced 2026-02-25 13:11:56 -08:00
Merge pull request #72 from lumag/laurent
laurent: driver for KernelChip Laurent family of relays
This commit is contained in:
13
config-samples/sample12.yaml
Normal file
13
config-samples/sample12.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
---
|
||||
devices:
|
||||
- board: myboard
|
||||
name: "My Board"
|
||||
description: |
|
||||
My Awesome board
|
||||
console: /dev/ttyABC0
|
||||
fastboot: cacafada
|
||||
fastboot_set_active: true
|
||||
fastboot_key_timeout: 2
|
||||
laurent:
|
||||
server: laurent.lan
|
||||
relay: 5
|
||||
1
device.h
1
device.h
@@ -105,6 +105,7 @@ extern const struct control_ops ftdi_gpio_ops;
|
||||
extern const struct control_ops local_gpio_ops;
|
||||
extern const struct control_ops external_ops;
|
||||
extern const struct control_ops qcomlt_dbg_ops;
|
||||
extern const struct control_ops laurent_ops;
|
||||
|
||||
extern const struct console_ops conmux_console_ops;
|
||||
extern const struct console_ops console_ops;
|
||||
|
||||
@@ -115,6 +115,11 @@ static void parse_board(struct device_parser *dp)
|
||||
if (dev->control_options)
|
||||
set_control_ops(dev, &ftdi_gpio_ops);
|
||||
continue;
|
||||
} else if (!strcmp(key, "laurent")) {
|
||||
dev->control_options = laurent_ops.parse_options(dp);
|
||||
if (dev->control_options)
|
||||
set_control_ops(dev, &laurent_ops);
|
||||
continue;
|
||||
}
|
||||
|
||||
device_parser_expect(dp, YAML_SCALAR_EVENT, value, TOKEN_LENGTH);
|
||||
|
||||
197
drivers/laurent.c
Normal file
197
drivers/laurent.c
Normal file
@@ -0,0 +1,197 @@
|
||||
/*
|
||||
* Copyright (c) 2024, Linaro Ltd.
|
||||
* All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* Driver for KernelChip Laurent family of Ethernet-controlled relay arrays.
|
||||
*/
|
||||
#define _GNU_SOURCE
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <err.h>
|
||||
#include <netdb.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <yaml.h>
|
||||
|
||||
#include "cdba-server.h"
|
||||
#include "device.h"
|
||||
#include "device_parser.h"
|
||||
|
||||
struct laurent_options {
|
||||
const char *server;
|
||||
const char *password;
|
||||
unsigned int relay;
|
||||
};
|
||||
|
||||
struct laurent {
|
||||
struct laurent_options *options;
|
||||
|
||||
struct addrinfo addr;
|
||||
};
|
||||
|
||||
#define DEFAULT_PASSWORD "Laurent"
|
||||
#define TOKEN_LENGTH 128
|
||||
|
||||
void *laurent_parse_options(struct device_parser *dp)
|
||||
{
|
||||
struct laurent_options *options;
|
||||
char value[TOKEN_LENGTH];
|
||||
char key[TOKEN_LENGTH];
|
||||
|
||||
options = calloc(1, sizeof(*options));
|
||||
options->password = DEFAULT_PASSWORD;
|
||||
|
||||
device_parser_accept(dp, YAML_MAPPING_START_EVENT, NULL, 0);
|
||||
while (device_parser_accept(dp, YAML_SCALAR_EVENT, key, TOKEN_LENGTH)) {
|
||||
if (!device_parser_accept(dp, YAML_SCALAR_EVENT, value, TOKEN_LENGTH))
|
||||
errx(1, "%s: expected value for \"%s\"", __func__, key);
|
||||
|
||||
if (!strcmp(key, "server"))
|
||||
options->server = strdup(value);
|
||||
else if (!strcmp(key, "password"))
|
||||
options->password = strdup(value);
|
||||
else if (!strcmp(key, "relay"))
|
||||
options->relay = strtoul(value, NULL, 0);
|
||||
else
|
||||
errx(1, "%s: unknown option \"%s\"", __func__, key);
|
||||
}
|
||||
|
||||
device_parser_expect(dp, YAML_MAPPING_END_EVENT, NULL, 0);
|
||||
|
||||
if (!options->server)
|
||||
errx(1, "%s: server hostname not specified", __func__);
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
static void laurent_resolve(struct laurent *laurent)
|
||||
{
|
||||
struct addrinfo hints = {};
|
||||
struct addrinfo *result, *rp;
|
||||
|
||||
int ret;
|
||||
|
||||
hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_flags = AI_PASSIVE;
|
||||
hints.ai_protocol = 0;
|
||||
hints.ai_canonname = NULL;
|
||||
hints.ai_addr = NULL;
|
||||
hints.ai_next = NULL;
|
||||
|
||||
ret = getaddrinfo(laurent->options->server, "80", &hints, &result);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(ret));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
for (rp = result; rp != NULL; rp = rp->ai_next) {
|
||||
int fd = socket(rp->ai_family, rp->ai_socktype,
|
||||
rp->ai_protocol);
|
||||
if (fd == -1)
|
||||
continue;
|
||||
|
||||
if (connect(fd, rp->ai_addr, rp->ai_addrlen) == 0) {
|
||||
close(fd);
|
||||
break;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
if (rp == NULL)
|
||||
errx(1, "Could not resolve / connect to the controller\n");
|
||||
|
||||
laurent->addr = *rp;
|
||||
laurent->addr.ai_addr = malloc(rp->ai_addrlen);
|
||||
memcpy(laurent->addr.ai_addr, rp->ai_addr,rp->ai_addrlen);
|
||||
|
||||
freeaddrinfo(result); /* No longer needed */
|
||||
}
|
||||
|
||||
static void *laurent_open(struct device *dev)
|
||||
{
|
||||
struct laurent *laurent;
|
||||
|
||||
laurent = calloc(1, sizeof(*laurent));
|
||||
|
||||
laurent->options = dev->control_options;
|
||||
|
||||
laurent_resolve(laurent);
|
||||
|
||||
return laurent;
|
||||
}
|
||||
|
||||
static int laurent_power(struct device *dev, bool on)
|
||||
{
|
||||
struct laurent *laurent = dev->cdb;
|
||||
char buf[BUFSIZ];
|
||||
int fd, ret, len, off;
|
||||
|
||||
fd = socket(laurent->addr.ai_family, laurent->addr.ai_socktype,
|
||||
laurent->addr.ai_protocol);
|
||||
if (fd == -1) {
|
||||
warn("failed to open socket\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = connect(fd, laurent->addr.ai_addr, laurent->addr.ai_addrlen);
|
||||
if (ret == -1) {
|
||||
warn("failed to connect\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "GET /cmd.cgi?psw=%s&cmd=REL,%u,%d HTTP/1.0\r\n\r\n",
|
||||
laurent->options->password,
|
||||
laurent->options->relay,
|
||||
on);
|
||||
if (len < 0) {
|
||||
warn("asprintf failed\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
for (off = 0; off != len; ) {
|
||||
ret = send(fd, buf + off, len - off, 0);
|
||||
if (ret == -1) {
|
||||
warn("failed to send\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
off += ret;
|
||||
}
|
||||
|
||||
/* Dump controller response to stderr */
|
||||
while (true) {
|
||||
ret = recv(fd, buf, sizeof(buf), 0);
|
||||
if (ret == -1) {
|
||||
warn("failed to recv\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!ret)
|
||||
break;
|
||||
|
||||
write(STDERR_FILENO, buf, ret);
|
||||
}
|
||||
|
||||
write(STDERR_FILENO, "\n", 1);
|
||||
|
||||
shutdown(fd, SHUT_RDWR);
|
||||
close(fd);
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
shutdown(fd, SHUT_RDWR);
|
||||
close(fd);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
const struct control_ops laurent_ops = {
|
||||
.parse_options = laurent_parse_options,
|
||||
.open = laurent_open,
|
||||
.power = laurent_power,
|
||||
};
|
||||
@@ -70,6 +70,7 @@ drivers_srcs = ['drivers/alpaca.c',
|
||||
'drivers/conmux.c',
|
||||
'drivers/external.c',
|
||||
'drivers/ftdi-gpio.c',
|
||||
'drivers/laurent.c',
|
||||
'drivers/local-gpio.c',
|
||||
'drivers/qcomlt_dbg.c',
|
||||
]
|
||||
|
||||
17
schema.yaml
17
schema.yaml
@@ -142,6 +142,23 @@ properties:
|
||||
patternProperties:
|
||||
"^power|fastboot_key|power_key|usb_disconnect$":
|
||||
$ref: "#/$defs/local_gpio"
|
||||
|
||||
laurent:
|
||||
description: KernelChip Laurent relays
|
||||
type: object
|
||||
unevaluatedItems: false
|
||||
properties:
|
||||
server:
|
||||
type: string
|
||||
relay:
|
||||
type: integer
|
||||
password:
|
||||
description: password to access the relays, defaults to 'Laurent'
|
||||
type: string
|
||||
required:
|
||||
- server
|
||||
- relay
|
||||
|
||||
required:
|
||||
- board
|
||||
- name
|
||||
|
||||
Reference in New Issue
Block a user