1# SPDX-License-Identifier: GPL-2.0
2# Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
3
4import os.path
5import pytest
6import re
7
8def in_tree(response, name, uclass, drv, depth, last_child):
9	lines = [x.strip() for x in response.splitlines()]
10	leaf = ''
11	if depth != 0:
12		leaf = '   ' + '    ' * (depth - 1) ;
13		if not last_child:
14			leaf = leaf + r'\|'
15		else:
16                        leaf = leaf + '`'
17
18	leaf = leaf + '-- ' + name
19	line = (r' *{:10.10} *[0-9]*  \[ [ +] \]   {:20.20}  [` |]{}$'
20	        .format(uclass, drv, leaf))
21	prog = re.compile(line)
22	for l in lines:
23		if prog.match(l):
24			return True
25	return False
26
27
28@pytest.mark.buildconfigspec('cmd_bind')
29def test_bind_unbind_with_node(u_boot_console):
30
31	tree = u_boot_console.run_command('dm tree')
32	assert in_tree(tree, 'bind-test', 'simple_bus', 'simple_bus', 0, True)
33	assert in_tree(tree, 'bind-test-child1', 'phy', 'phy_sandbox', 1, False)
34	assert in_tree(tree, 'bind-test-child2', 'simple_bus', 'simple_bus', 1, True)
35
36	#Unbind child #1. No error expected and all devices should be there except for bind-test-child1
37	response = u_boot_console.run_command('unbind  /bind-test/bind-test-child1')
38	assert response == ''
39	tree = u_boot_console.run_command('dm tree')
40	assert in_tree(tree, 'bind-test', 'simple_bus', 'simple_bus', 0, True)
41	assert 'bind-test-child1' not in tree
42	assert in_tree(tree, 'bind-test-child2', 'simple_bus', 'simple_bus', 1, True)
43
44	#bind child #1. No error expected and all devices should be there
45	response = u_boot_console.run_command('bind  /bind-test/bind-test-child1 phy_sandbox')
46	assert response == ''
47	tree = u_boot_console.run_command('dm tree')
48	assert in_tree(tree, 'bind-test', 'simple_bus', 'simple_bus', 0, True)
49	assert in_tree(tree, 'bind-test-child1', 'phy', 'phy_sandbox', 1, True)
50	assert in_tree(tree, 'bind-test-child2', 'simple_bus', 'simple_bus', 1, False)
51
52	#Unbind child #2. No error expected and all devices should be there except for bind-test-child2
53	response = u_boot_console.run_command('unbind  /bind-test/bind-test-child2')
54	assert response == ''
55	tree = u_boot_console.run_command('dm tree')
56	assert in_tree(tree, 'bind-test', 'simple_bus', 'simple_bus', 0, True)
57	assert in_tree(tree, 'bind-test-child1', 'phy', 'phy_sandbox', 1, True)
58	assert 'bind-test-child2' not in tree
59
60
61	#Bind child #2. No error expected and all devices should be there
62	response = u_boot_console.run_command('bind /bind-test/bind-test-child2 simple_bus')
63	assert response == ''
64	tree = u_boot_console.run_command('dm tree')
65	assert in_tree(tree, 'bind-test', 'simple_bus', 'simple_bus', 0, True)
66	assert in_tree(tree, 'bind-test-child1', 'phy', 'phy_sandbox', 1, False)
67	assert in_tree(tree, 'bind-test-child2', 'simple_bus', 'simple_bus', 1, True)
68
69	#Unbind parent. No error expected. All devices should be removed and unbound
70	response = u_boot_console.run_command('unbind  /bind-test')
71	assert response == ''
72	tree = u_boot_console.run_command('dm tree')
73	assert 'bind-test' not in tree
74	assert 'bind-test-child1' not in tree
75	assert 'bind-test-child2' not in tree
76
77	#try binding invalid node with valid driver
78	response = u_boot_console.run_command('bind  /not-a-valid-node simple_bus')
79	assert response != ''
80	tree = u_boot_console.run_command('dm tree')
81	assert 'not-a-valid-node' not in tree
82
83	#try binding valid node with invalid driver
84	response = u_boot_console.run_command('bind  /bind-test not_a_driver')
85	assert response != ''
86	tree = u_boot_console.run_command('dm tree')
87	assert 'bind-test' not in tree
88
89	#bind /bind-test. Device should come up as well as its children
90	response = u_boot_console.run_command('bind  /bind-test simple_bus')
91	assert response == ''
92	tree = u_boot_console.run_command('dm tree')
93	assert in_tree(tree, 'bind-test', 'simple_bus', 'simple_bus', 0, True)
94	assert in_tree(tree, 'bind-test-child1', 'phy', 'phy_sandbox', 1, False)
95	assert in_tree(tree, 'bind-test-child2', 'simple_bus', 'simple_bus', 1, True)
96
97	response = u_boot_console.run_command('unbind  /bind-test')
98	assert response == ''
99
100def get_next_line(tree, name):
101	treelines = [x.strip() for x in tree.splitlines() if x.strip()]
102	child_line = ''
103	for idx, line in enumerate(treelines):
104		if ('-- ' + name) in line:
105			try:
106				child_line = treelines[idx+1]
107			except:
108				pass
109			break
110	return child_line
111
112@pytest.mark.buildconfigspec('cmd_bind')
113def test_bind_unbind_with_uclass(u_boot_console):
114	#bind /bind-test
115	response = u_boot_console.run_command('bind  /bind-test simple_bus')
116	assert response == ''
117
118	#make sure bind-test-child2 is there and get its uclass/index pair
119	tree = u_boot_console.run_command('dm tree')
120	child2_line = [x.strip() for x in tree.splitlines() if '-- bind-test-child2' in x]
121	assert len(child2_line) == 1
122
123	child2_uclass = child2_line[0].split()[0]
124	child2_index = int(child2_line[0].split()[1])
125
126	#bind simple_bus as a child of bind-test-child2
127	response = u_boot_console.run_command('bind  {} {} simple_bus'.format(child2_uclass, child2_index, 'simple_bus'))
128
129	#check that the child is there and its uclass/index pair is right
130	tree = u_boot_console.run_command('dm tree')
131
132	child_of_child2_line = get_next_line(tree, 'bind-test-child2')
133	assert child_of_child2_line
134	child_of_child2_index = int(child_of_child2_line.split()[1])
135	assert in_tree(tree, 'simple_bus', 'simple_bus', 'simple_bus', 2, True)
136	assert child_of_child2_index == child2_index + 1
137
138	#unbind the child and check it has been removed
139	response = u_boot_console.run_command('unbind  simple_bus {}'.format(child_of_child2_index))
140	assert response == ''
141	tree = u_boot_console.run_command('dm tree')
142	assert in_tree(tree, 'bind-test-child2', 'simple_bus', 'simple_bus', 1, True)
143	assert not in_tree(tree, 'simple_bus', 'simple_bus', 'simple_bus', 2, True)
144	child_of_child2_line = get_next_line(tree, 'bind-test-child2')
145	assert child_of_child2_line == ''
146
147	#bind simple_bus as a child of bind-test-child2
148	response = u_boot_console.run_command('bind  {} {} simple_bus'.format(child2_uclass, child2_index, 'simple_bus'))
149
150	#check that the child is there and its uclass/index pair is right
151	tree = u_boot_console.run_command('dm tree')
152	treelines = [x.strip() for x in tree.splitlines() if x.strip()]
153
154	child_of_child2_line = get_next_line(tree, 'bind-test-child2')
155	assert child_of_child2_line
156	child_of_child2_index = int(child_of_child2_line.split()[1])
157	assert in_tree(tree, 'simple_bus', 'simple_bus', 'simple_bus', 2, True)
158	assert child_of_child2_index == child2_index + 1
159
160	#unbind the child and check it has been removed
161	response = u_boot_console.run_command('unbind  {} {} simple_bus'.format(child2_uclass, child2_index, 'simple_bus'))
162	assert response == ''
163
164	tree = u_boot_console.run_command('dm tree')
165	assert in_tree(tree, 'bind-test-child2', 'simple_bus', 'simple_bus', 1, True)
166
167	child_of_child2_line = get_next_line(tree, 'bind-test-child2')
168	assert child_of_child2_line == ''
169
170	#unbind the child again and check it doesn't change the tree
171	tree_old = u_boot_console.run_command('dm tree')
172	response = u_boot_console.run_command('unbind  {} {} simple_bus'.format(child2_uclass, child2_index, 'simple_bus'))
173	tree_new = u_boot_console.run_command('dm tree')
174
175	assert response == ''
176	assert tree_old == tree_new
177
178	response = u_boot_console.run_command('unbind  /bind-test')
179	assert response == ''
180