summaryrefslogtreecommitdiff
path: root/io-module/mtac_eth.c
blob: 09b52ee4cf42d548206447866b08e2594c3563da (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
static char* eth_gpio_pin_name_by_attr_name(const char* name, int port) {
	log_error("attirbute name [%s] is invalid for ETH in port %d", name, port);
	return "";
}

// 1 vendor-id
// 1 product-id
// 1 device-id
// 1 hw-version
// NULL
static size_t ap_eth_attrs_size = 5;

static bool eth_setup(enum ap port) {
	int i;
	int port_index = port - 1;
	int index = 0;
	int count = 0;
	int ret;
	char buf[32];
	struct attribute **attrs;

	log_info("loading ETH accessory card in port %d", port);

	sprintf(buf, "ap%d", port);
	ap_subdirs[port_index] = kobject_create_and_add(buf, &mts_io_platform_device->dev.kobj);
	if (! ap_subdirs[port_index]) {
		log_error("kobject_create_and_add for ETH in port %d failed", port);
		return false;
	}

	// create the link to the apX directory this card is in
	// if we're in the first slot, we get plain "eth"
	// if we're in a different slot, we might need to use "eth-2" to differentiate
	if (port > 1) {
		for (i = 1; i < port; i++) {
			if (port_info[i - 1]) {
				if (strstr(port_info[i - 1]->product_id, PRODUCT_ID_MTAC_ETH)) {
					count++;
				}
			}
		}
	}
	if (count > 0) {
		sprintf(buf, "eth-%d", count + 1);
	} else {
		sprintf(buf, "eth");
	}
	ret = sysfs_create_link(ap_subdirs[port_index]->parent, ap_subdirs[port_index], buf);
	if (ret) {
		log_error("failed to link [%s] to [%s], %d", buf, ap_subdirs[port_index]->name, ret);
	}

	attrs = kzalloc(sizeof(struct attribute*) * ap_eth_attrs_size, GFP_KERNEL);
	if (! attrs) {
		log_error("failed to allocate attribute space for port %d", port);
		return false;
	}

	// add attributes for eeprom contents
	if (! ap_add_product_info_attributes(port, MTAC_ETH_0_0, attrs, &index)) {
		log_error("failed to add product info attributes for ETH in port %d", port);
		return false;
	}

	attrs[index] = NULL;

	ap_attr_groups[port_index].attrs = attrs;
	if (sysfs_create_group(ap_subdirs[port_index], &ap_attr_groups[port_index])) {
		log_error("sysfs_create_group failed for ETH in port %d", port);
		return false;
	}

	return true;
}

static bool eth_teardown(enum ap port) {
	int i;
	int port_index = port - 1;
	struct attribute **attrs = ap_attr_groups[port_index].attrs;

	log_info("unloading ETH accessory card in port %d", port);

	// clean up allocated memory for attributes
	for (i = 0; i < ap_eth_attrs_size; i++) {
		if (attrs[i]) {
			if (attrs[i]->name)
				kfree(attrs[i]->name);

			kfree(attrs[i]);
		}
	}

	kfree(attrs);

	// clean up our "apX/" kobject if it exists
	if (ap_subdirs[port_index]) {
		kobject_put(ap_subdirs[port_index]);
	}

	return true;
}

bool set_eth_info(struct ap_info* info) {
	snprintf(info->product_id, 32, "%s", PRODUCT_ID_MTAC_ETH);
	info->setup = &eth_setup;
	info->teardown = &eth_teardown;
	info->gpio_pin_name_by_attr_name = &eth_gpio_pin_name_by_attr_name;

	return true;
}