Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/net/caif/cfutill.c
15109 views
1
/*
2
* Copyright (C) ST-Ericsson AB 2010
3
* Author: Sjur Brendeland/[email protected]
4
* License terms: GNU General Public License (GPL) version 2
5
*/
6
7
#define pr_fmt(fmt) KBUILD_MODNAME ":%s(): " fmt, __func__
8
9
#include <linux/kernel.h>
10
#include <linux/types.h>
11
#include <linux/slab.h>
12
#include <linux/errno.h>
13
#include <net/caif/caif_layer.h>
14
#include <net/caif/cfsrvl.h>
15
#include <net/caif/cfpkt.h>
16
17
#define container_obj(layr) ((struct cfsrvl *) layr)
18
#define UTIL_PAYLOAD 0x00
19
#define UTIL_CMD_BIT 0x80
20
#define UTIL_REMOTE_SHUTDOWN 0x82
21
#define UTIL_FLOW_OFF 0x81
22
#define UTIL_FLOW_ON 0x80
23
24
static int cfutill_receive(struct cflayer *layr, struct cfpkt *pkt);
25
static int cfutill_transmit(struct cflayer *layr, struct cfpkt *pkt);
26
27
struct cflayer *cfutill_create(u8 channel_id, struct dev_info *dev_info)
28
{
29
struct cfsrvl *util = kmalloc(sizeof(struct cfsrvl), GFP_ATOMIC);
30
if (!util) {
31
pr_warn("Out of memory\n");
32
return NULL;
33
}
34
caif_assert(offsetof(struct cfsrvl, layer) == 0);
35
memset(util, 0, sizeof(struct cfsrvl));
36
cfsrvl_init(util, channel_id, dev_info, true);
37
util->layer.receive = cfutill_receive;
38
util->layer.transmit = cfutill_transmit;
39
snprintf(util->layer.name, CAIF_LAYER_NAME_SZ - 1, "util1");
40
return &util->layer;
41
}
42
43
static int cfutill_receive(struct cflayer *layr, struct cfpkt *pkt)
44
{
45
u8 cmd = -1;
46
struct cfsrvl *service = container_obj(layr);
47
caif_assert(layr != NULL);
48
caif_assert(layr->up != NULL);
49
caif_assert(layr->up->receive != NULL);
50
caif_assert(layr->up->ctrlcmd != NULL);
51
if (cfpkt_extr_head(pkt, &cmd, 1) < 0) {
52
pr_err("Packet is erroneous!\n");
53
cfpkt_destroy(pkt);
54
return -EPROTO;
55
}
56
57
switch (cmd) {
58
case UTIL_PAYLOAD:
59
return layr->up->receive(layr->up, pkt);
60
case UTIL_FLOW_OFF:
61
layr->ctrlcmd(layr, CAIF_CTRLCMD_FLOW_OFF_IND, 0);
62
cfpkt_destroy(pkt);
63
return 0;
64
case UTIL_FLOW_ON:
65
layr->ctrlcmd(layr, CAIF_CTRLCMD_FLOW_ON_IND, 0);
66
cfpkt_destroy(pkt);
67
return 0;
68
case UTIL_REMOTE_SHUTDOWN: /* Remote Shutdown Request */
69
pr_err("REMOTE SHUTDOWN REQUEST RECEIVED\n");
70
layr->ctrlcmd(layr, CAIF_CTRLCMD_REMOTE_SHUTDOWN_IND, 0);
71
service->open = false;
72
cfpkt_destroy(pkt);
73
return 0;
74
default:
75
cfpkt_destroy(pkt);
76
pr_warn("Unknown service control %d (0x%x)\n", cmd, cmd);
77
return -EPROTO;
78
}
79
}
80
81
static int cfutill_transmit(struct cflayer *layr, struct cfpkt *pkt)
82
{
83
u8 zero = 0;
84
struct caif_payload_info *info;
85
int ret;
86
struct cfsrvl *service = container_obj(layr);
87
caif_assert(layr != NULL);
88
caif_assert(layr->dn != NULL);
89
caif_assert(layr->dn->transmit != NULL);
90
if (!cfsrvl_ready(service, &ret))
91
return ret;
92
93
cfpkt_add_head(pkt, &zero, 1);
94
/* Add info for MUX-layer to route the packet out. */
95
info = cfpkt_info(pkt);
96
info->channel_id = service->layer.id;
97
/*
98
* To optimize alignment, we add up the size of CAIF header before
99
* payload.
100
*/
101
info->hdr_len = 1;
102
info->dev_info = &service->dev_info;
103
return layr->dn->transmit(layr->dn, pkt);
104
}
105
106