1 // SPDX-License-Identifier: BSD-2-Clause
3 * Copyright (C) 2020 Andre Heider <a.heider@gmail.com>
16 #include "dsl_cpe_control.h"
17 #include <drv_dsl_cpe_api_ioctl.h>
18 #ifdef INCLUDE_DSL_CPE_API_VRX
19 #include <drv_mei_cpe_interface.h>
22 #define U16(v1, v2) ( \
23 ((uint16_t)(v1) << 8) | \
26 #define U32(v1, v2, v3, v4) ( \
27 ((uint32_t)(v1) << 24) | \
28 ((uint32_t)(v2) << 16) | \
29 ((uint32_t)(v3) << 8) | \
32 #define STR_CASE(id, text) \
37 #define STR_CASE_MAP(id, text, number) \
43 #define IOCTL(type, request) \
45 memset(&out, 0, sizeof(type)); \
46 if (ioctl(fd, request, &out)) \
49 #define IOCTL_DIR(type, request, dir) \
51 memset(&out, 0, sizeof(type)); \
52 out.nDirection = dir; \
53 if (ioctl(fd, request, &out)) \
56 #define IOCTL_DIR_DELT(type, request, dir, delt) \
58 memset(&out, 0, sizeof(type)); \
59 out.nDirection = dir; \
60 out.nDeltDataType = delt; \
61 if (ioctl(fd, request, &out)) \
108 /* These values are exported via ubus and backwards compability
112 LSTATE_MAP_UNKNOWN
= -1,
113 LSTATE_MAP_NOT_INITIALIZED
,
114 LSTATE_MAP_EXCEPTION
,
117 LSTATE_MAP_HANDSHAKE
,
118 LSTATE_MAP_FULL_INIT
,
119 LSTATE_MAP_SHOWTIME_NO_SYNC
,
120 LSTATE_MAP_SHOWTIME_TC_SYNC
,
124 /* These values are exported via ubus and backwards compability
128 PSTATE_MAP_UNKNOWN
= -2,
136 /* These values are exported via ubus and backwards compability
140 RAMODE_MAP_UNKNOWN
= -1,
144 RAMODE_MAP_DYNAMIC_SOS
,
147 static DSL_CPE_ThreadCtrl_t thread
;
148 static struct ubus_context
*ctx
;
149 static struct blob_buf b
;
151 static inline void m_null() {
152 blobmsg_add_field(&b
, BLOBMSG_TYPE_UNSPEC
, "", NULL
, 0);
155 static inline void m_double(const char *id
, double value
) {
156 blobmsg_add_double(&b
, id
, value
);
159 static inline void m_bool(const char *id
, bool value
) {
160 blobmsg_add_u8(&b
, id
, value
);
163 static inline void m_u32(const char *id
, uint32_t value
) {
164 blobmsg_add_u64(&b
, id
, value
);
167 static inline void m_str(const char *id
, const char *value
) {
168 blobmsg_add_string(&b
, id
, value
);
171 static inline void m_db(const char *id
, int value
, int invalid
) {
172 if (value
!= invalid
)
173 m_double(id
, (double)value
/ 10);
176 static inline void m_array(const char *id
, const uint8_t *value
, size_t len
) {
177 void *c
= blobmsg_open_array(&b
, id
);
179 for (size_t i
= 0; i
< len
; ++i
)
180 blobmsg_add_u16(&b
, "", value
[i
]);
182 blobmsg_close_array(&b
, c
);
185 static inline void m_array_u16(const char *id
, const uint16_t *value
, size_t len
) {
186 void *c
= blobmsg_open_array(&b
, id
);
188 for (size_t i
= 0; i
< len
; ++i
)
189 blobmsg_add_u16(&b
, "", value
[i
]);
191 blobmsg_close_array(&b
, c
);
194 static void m_vendor(const char *id
, const uint8_t *value
) {
196 if (U16(value
[0], value
[1]) != 0xb500)
199 const char *str
= NULL
;
200 switch (U32(value
[2], value
[3], value
[4], value
[5])) {
201 STR_CASE(0x414C4342, "Alcatel")
202 STR_CASE(0x414E4456, "Analog Devices")
203 STR_CASE(0x4244434D, "Broadcom")
204 STR_CASE(0x43454E54, "Centillium")
205 STR_CASE(0x4753504E, "Globespan")
206 STR_CASE(0x494B4E53, "Ikanos")
207 STR_CASE(0x4946544E, "Infineon")
208 STR_CASE(0x54535443, "Texas Instruments")
209 STR_CASE(0x544D4D42, "Thomson MultiMedia Broadband")
210 STR_CASE(0x5443544E, "Trend Chip Technologies")
211 STR_CASE(0x53544D49, "ST Micro")
217 if ((value
[6] == 0) && (value
[7] == 0)) {
223 sprintf(buf
, "%s %d.%d", str
, value
[6], value
[7]);
229 annex_t
get_annex(const uint8_t *xtse
) {
230 if ((xtse
[0] & XTSE_1_01_A_T1_413
) ||
231 (xtse
[0] & XTSE_1_03_A_1_NO
) ||
232 (xtse
[0] & XTSE_1_04_A_1_O
) ||
233 (xtse
[1] & XTSE_2_01_A_2_NO
) ||
234 (xtse
[2] & XTSE_3_03_A_3_NO
) ||
235 (xtse
[2] & XTSE_3_04_A_3_O
) ||
236 (xtse
[3] & XTSE_4_01_A_4_NO
) ||
237 (xtse
[3] & XTSE_4_02_A_4_O
) ||
238 (xtse
[5] & XTSE_6_01_A_5_NO
) ||
239 (xtse
[5] & XTSE_6_02_A_5_O
) ||
240 (xtse
[7] & XTSE_8_01_A
))
243 if ((xtse
[0] & XTSE_1_05_B_1_NO
) ||
244 (xtse
[0] & XTSE_1_06_B_1_O
) ||
245 (xtse
[1] & XTSE_2_02_B_2_O
) ||
246 (xtse
[2] & XTSE_3_05_B_3_NO
) ||
247 (xtse
[2] & XTSE_3_06_B_3_O
) ||
248 (xtse
[5] & XTSE_6_03_B_5_NO
) ||
249 (xtse
[5] & XTSE_6_04_B_5_O
) ||
250 (xtse
[7] & XTSE_8_02_B
))
253 if ((xtse
[0] & XTSE_1_02_C_TS_101388
) ||
254 (xtse
[0] & XTSE_1_07_C_1_NO
) ||
255 (xtse
[0] & XTSE_1_08_C_1_O
) ||
256 (xtse
[1] & XTSE_2_03_C_2_NO
) ||
257 (xtse
[1] & XTSE_2_04_C_2_O
) ||
258 (xtse
[7] & XTSE_8_03_C
))
261 if ((xtse
[3] & XTSE_4_05_I_3_NO
) ||
262 (xtse
[3] & XTSE_4_06_I_3_O
) ||
263 (xtse
[4] & XTSE_5_01_I_4_NO
) ||
264 (xtse
[4] & XTSE_5_02_I_4_O
) ||
265 (xtse
[5] & XTSE_6_07_I_5_NO
) ||
266 (xtse
[5] & XTSE_6_08_I_5_O
))
269 if ((xtse
[3] & XTSE_4_07_J_3_NO
) ||
270 (xtse
[3] & XTSE_4_08_J_3_O
) ||
271 (xtse
[6] & XTSE_7_01_J_5_NO
) ||
272 (xtse
[6] & XTSE_7_02_J_5_O
))
275 if ((xtse
[4] & XTSE_5_03_L_3_NO
) ||
276 (xtse
[4] & XTSE_5_04_L_3_NO
) ||
277 (xtse
[4] & XTSE_5_05_L_3_O
) ||
278 (xtse
[4] & XTSE_5_06_L_3_O
))
281 if ((xtse
[4] & XTSE_5_07_M_3_NO
) ||
282 (xtse
[4] & XTSE_5_08_M_3_O
) ||
283 (xtse
[6] & XTSE_7_03_M_5_NO
) ||
284 (xtse
[6] & XTSE_7_04_M_5_O
))
287 return ANNEX_UNKNOWN
;
290 static standard_t
get_standard(const uint8_t *xtse
) {
291 if (xtse
[0] & XTSE_1_01_A_T1_413
)
294 if (xtse
[0] & XTSE_1_02_C_TS_101388
)
295 return STD_TS_101_388
;
297 if ((xtse
[0] & XTSE_1_03_A_1_NO
) ||
298 (xtse
[0] & XTSE_1_04_A_1_O
) ||
299 (xtse
[0] & XTSE_1_05_B_1_NO
) ||
300 (xtse
[0] & XTSE_1_06_B_1_O
) ||
301 (xtse
[0] & XTSE_1_07_C_1_NO
) ||
302 (xtse
[0] & XTSE_1_08_C_1_O
))
305 if ((xtse
[1] & XTSE_2_01_A_2_NO
) ||
306 (xtse
[1] & XTSE_2_02_B_2_O
) ||
307 (xtse
[1] & XTSE_2_03_C_2_NO
) ||
308 (xtse
[1] & XTSE_2_04_C_2_O
))
311 if ((xtse
[2] & XTSE_3_03_A_3_NO
) ||
312 (xtse
[2] & XTSE_3_04_A_3_O
) ||
313 (xtse
[2] & XTSE_3_05_B_3_NO
) ||
314 (xtse
[2] & XTSE_3_06_B_3_O
) ||
315 (xtse
[3] & XTSE_4_05_I_3_NO
) ||
316 (xtse
[3] & XTSE_4_06_I_3_O
) ||
317 (xtse
[3] & XTSE_4_07_J_3_NO
) ||
318 (xtse
[3] & XTSE_4_08_J_3_O
) ||
319 (xtse
[4] & XTSE_5_03_L_3_NO
) ||
320 (xtse
[4] & XTSE_5_04_L_3_NO
) ||
321 (xtse
[4] & XTSE_5_05_L_3_O
) ||
322 (xtse
[4] & XTSE_5_06_L_3_O
) ||
323 (xtse
[4] & XTSE_5_07_M_3_NO
) ||
324 (xtse
[4] & XTSE_5_08_M_3_O
))
327 if ((xtse
[3] & XTSE_4_01_A_4_NO
) ||
328 (xtse
[3] & XTSE_4_02_A_4_O
) ||
329 (xtse
[4] & XTSE_5_01_I_4_NO
) ||
330 (xtse
[4] & XTSE_5_02_I_4_O
))
333 if ((xtse
[5] & XTSE_6_01_A_5_NO
) ||
334 (xtse
[5] & XTSE_6_02_A_5_O
) ||
335 (xtse
[5] & XTSE_6_03_B_5_NO
) ||
336 (xtse
[5] & XTSE_6_04_B_5_O
) ||
337 (xtse
[5] & XTSE_6_07_I_5_NO
) ||
338 (xtse
[5] & XTSE_6_08_I_5_O
) ||
339 (xtse
[6] & XTSE_7_01_J_5_NO
) ||
340 (xtse
[6] & XTSE_7_02_J_5_O
) ||
341 (xtse
[6] & XTSE_7_03_M_5_NO
) ||
342 (xtse
[6] & XTSE_7_04_M_5_O
))
345 if (xtse
[7] & XTSE_8_08
)
348 if ((xtse
[7] & XTSE_8_01_A
) ||
349 (xtse
[7] & XTSE_8_02_B
) ||
350 (xtse
[7] & XTSE_8_03_C
))
356 static void version_information(int fd
) {
357 IOCTL(DSL_VersionInformation_t
, DSL_FIO_VERSION_INFORMATION_GET
)
359 m_str("api_version", out
.data
.DSL_DriverVersionApi
);
360 m_str("firmware_version", out
.data
.DSL_ChipSetFWVersion
);
361 m_str("chipset", out
.data
.DSL_ChipSetType
);
362 m_str("driver_version", out
.data
.DSL_DriverVersionMeiBsp
);
365 static void line_state(int fd
) {
366 IOCTL(DSL_LineState_t
, DSL_FIO_LINE_STATE_GET
)
368 int map
= LSTATE_MAP_UNKNOWN
;
370 switch (out
.data
.nLineState
) {
371 STR_CASE_MAP(DSL_LINESTATE_NOT_INITIALIZED
, "Not initialized", LSTATE_MAP_NOT_INITIALIZED
)
372 STR_CASE_MAP(DSL_LINESTATE_EXCEPTION
, "Exception", LSTATE_MAP_EXCEPTION
)
373 STR_CASE(DSL_LINESTATE_NOT_UPDATED
, "Not updated")
374 STR_CASE(DSL_LINESTATE_IDLE_REQUEST
, "Idle request")
375 STR_CASE_MAP(DSL_LINESTATE_IDLE
, "Idle", LSTATE_MAP_IDLE
)
376 STR_CASE(DSL_LINESTATE_SILENT_REQUEST
, "Silent request")
377 STR_CASE_MAP(DSL_LINESTATE_SILENT
, "Silent", LSTATE_MAP_SILENT
)
378 STR_CASE_MAP(DSL_LINESTATE_HANDSHAKE
, "Handshake", LSTATE_MAP_HANDSHAKE
)
379 STR_CASE(DSL_LINESTATE_BONDING_CLR
, "Bonding CLR")
380 STR_CASE_MAP(DSL_LINESTATE_FULL_INIT
, "Full init", LSTATE_MAP_FULL_INIT
)
381 STR_CASE(DSL_LINESTATE_SHORT_INIT_ENTRY
, "Short init entry")
382 STR_CASE(DSL_LINESTATE_DISCOVERY
, "Discovery")
383 STR_CASE(DSL_LINESTATE_TRAINING
, "Training")
384 STR_CASE(DSL_LINESTATE_ANALYSIS
, "Analysis")
385 STR_CASE(DSL_LINESTATE_EXCHANGE
, "Exchange")
386 STR_CASE_MAP(DSL_LINESTATE_SHOWTIME_NO_SYNC
, "Showtime without TC-Layer sync", LSTATE_MAP_SHOWTIME_NO_SYNC
)
387 STR_CASE_MAP(DSL_LINESTATE_SHOWTIME_TC_SYNC
, "Showtime with TC-Layer sync", LSTATE_MAP_SHOWTIME_TC_SYNC
)
388 STR_CASE(DSL_LINESTATE_FASTRETRAIN
, "Fastretrain")
389 STR_CASE(DSL_LINESTATE_LOWPOWER_L2
, "Lowpower L2")
390 STR_CASE(DSL_LINESTATE_LOOPDIAGNOSTIC_ACTIVE
, "Loopdiagnostic active")
391 STR_CASE(DSL_LINESTATE_LOOPDIAGNOSTIC_DATA_EXCHANGE
, "Loopdiagnostic data exchange")
392 STR_CASE(DSL_LINESTATE_LOOPDIAGNOSTIC_DATA_REQUEST
, "Loopdiagnostic data request")
393 STR_CASE(DSL_LINESTATE_LOOPDIAGNOSTIC_COMPLETE
, "Loopdiagnostic complete")
394 STR_CASE_MAP(DSL_LINESTATE_RESYNC
, "Resync", LSTATE_MAP_RESYNC
)
395 STR_CASE(DSL_LINESTATE_TEST
, "Test")
396 STR_CASE(DSL_LINESTATE_TEST_LOOP
, "Test loop")
397 STR_CASE(DSL_LINESTATE_TEST_REVERB
, "Test reverb")
398 STR_CASE(DSL_LINESTATE_TEST_MEDLEY
, "Test medley")
399 STR_CASE(DSL_LINESTATE_TEST_SHOWTIME_LOCK
, "Showtime lock")
400 STR_CASE(DSL_LINESTATE_TEST_QUIET
, "Quiet")
401 STR_CASE(DSL_LINESTATE_LOWPOWER_L3
, "Lowpower L3")
402 #ifndef INCLUDE_DSL_CPE_API_DANUBE
403 STR_CASE(DSL_LINESTATE_DISABLED
, "Disabled")
404 STR_CASE(DSL_LINESTATE_T1413
, "T1413")
405 STR_CASE(DSL_LINESTATE_ORDERLY_SHUTDOWN_REQUEST
, "Orderly shutdown request")
406 STR_CASE(DSL_LINESTATE_ORDERLY_SHUTDOWN
, "Orderly shutdown")
407 STR_CASE(DSL_LINESTATE_TEST_FILTERDETECTION_ACTIVE
, "Test filterdetection active")
408 STR_CASE(DSL_LINESTATE_TEST_FILTERDETECTION_COMPLETE
, "Test filterdetection complete")
418 if (map
!= LSTATE_MAP_UNKNOWN
)
419 m_u32("state_num", map
);
421 m_bool("up", out
.data
.nLineState
== DSL_LINESTATE_SHOWTIME_TC_SYNC
);
424 static void pm_channel_counters_showtime(int fd
) {
425 IOCTL_DIR(DSL_PM_ChannelCounters_t
, DSL_FIO_PM_CHANNEL_COUNTERS_SHOWTIME_GET
, DSL_NEAR_END
);
427 m_u32("uptime", out
.interval
.nElapsedTime
);
430 static void g997_line_inventory(int fd
) {
431 IOCTL_DIR(DSL_G997_LineInventory_t
, DSL_FIO_G997_LINE_INVENTORY_GET
, DSL_DOWNSTREAM
)
433 m_array("vendor_id", out
.data
.G994VendorID
, DSL_G997_LI_MAXLEN_VENDOR_ID
);
434 m_vendor("vendor", out
.data
.G994VendorID
);
435 m_array("system_vendor_id", out
.data
.SystemVendorID
, DSL_G997_LI_MAXLEN_VENDOR_ID
);
436 m_vendor("system_vendor", out
.data
.SystemVendorID
);
437 m_array("version", out
.data
.VersionNumber
, DSL_G997_LI_MAXLEN_VERSION
);
438 m_array("serial", out
.data
.SerialNumber
, DSL_G997_LI_MAXLEN_SERIAL
);
441 static void pilot_tones_status(int fd
) {
442 #ifndef INCLUDE_DSL_CPE_API_DANUBE
443 IOCTL(DSL_PilotTonesStatus_t
, DSL_FIO_PILOT_TONES_STATUS_GET
);
445 m_array_u16("pilot_tones", out
.data
.nPilotTone
, out
.data
.nNumData
);
449 static void band_border_status(int fd
, DSL_AccessDir_t direction
) {
450 IOCTL(DSL_BandBorderStatus_t
, DSL_FIO_BAND_BORDER_STATUS_GET
);
454 c
= blobmsg_open_array(&b
, "limits");
456 for (size_t i
= 0; i
< out
.data
.nNumData
; i
++) {
457 c2
= blobmsg_open_table(&b
, "");
458 blobmsg_add_u16(&b
, "first", out
.data
.nBandLimits
[i
].nFirstToneIndex
);
459 blobmsg_add_u16(&b
, "last", out
.data
.nBandLimits
[i
].nLastToneIndex
);
460 blobmsg_close_table(&b
, c2
);
463 blobmsg_close_array(&b
, c
);
466 static void g977_get_bit_allocation(int fd
, DSL_AccessDir_t direction
) {
467 IOCTL_DIR(DSL_G997_BitAllocationNsc_t
, DSL_FIO_G997_BIT_ALLOCATION_NSC_GET
, direction
);
469 // create default value to obtain consistent JSON structure
470 m_u32("groupsize", 1);
471 m_u32("groups", out
.data
.bitAllocationNsc
.nNumData
);
472 m_array("data", out
.data
.bitAllocationNsc
.nNSCData
, out
.data
.bitAllocationNsc
.nNumData
);
475 static void g977_get_snr(int fd
, DSL_AccessDir_t direction
) {
476 IOCTL_DIR_DELT(DSL_G997_DeltSnr_t
, DSL_FIO_G997_DELT_SNR_GET
, direction
, DSL_DELT_DATA_SHOWTIME
);
478 m_u32("groupsize", out
.data
.nGroupSize
);
479 m_u32("groups", out
.data
.deltSnr
.nNumData
);
481 void *c
= blobmsg_open_array(&b
, "data");
484 for (uint16_t i
= 0 ; i
< out
.data
.deltSnr
.nNumData
; i
++)
485 if (out
.data
.deltSnr
.nNSCData
[i
] != 255 && out
.data
.deltSnr
.nNSCData
[i
] != 0)
486 m_double("", -32 + (double)out
.data
.deltSnr
.nNSCData
[i
] / 2);
490 blobmsg_close_array(&b
, c
);
493 static void g977_get_qln(int fd
, DSL_AccessDir_t direction
) {
494 IOCTL_DIR_DELT(DSL_G997_DeltQln_t
, DSL_FIO_G997_DELT_QLN_GET
, direction
, DSL_DELT_DATA_SHOWTIME
);
496 m_u32("groupsize", out
.data
.nGroupSize
);
497 m_u32("groups", out
.data
.deltQln
.nNumData
);
499 void *c
= blobmsg_open_array(&b
, "data");
501 // QLN -150 ... -23 dBm/Hz
502 for (uint16_t i
= 0 ; i
< out
.data
.deltQln
.nNumData
; i
++)
503 if (out
.data
.deltQln
.nNSCData
[i
] != 255 && out
.data
.deltQln
.nNSCData
[i
] != 0)
504 m_double("", -23 - (double)out
.data
.deltQln
.nNSCData
[i
] / 2);
508 blobmsg_close_array(&b
, c
);
511 static void g977_get_hlog(int fd
, DSL_AccessDir_t direction
) {
512 IOCTL_DIR_DELT(DSL_G997_DeltHlog_t
, DSL_FIO_G997_DELT_HLOG_GET
, direction
, DSL_DELT_DATA_SHOWTIME
);
514 m_u32("groupsize", out
.data
.nGroupSize
);
515 m_u32("groups", out
.data
.deltHlog
.nNumData
);
517 void *c
= blobmsg_open_array(&b
, "data");
519 // HLOG +6 ... -96 dB
520 for (uint16_t i
= 0 ; i
< out
.data
.deltHlog
.nNumData
; i
++)
521 if (out
.data
.deltHlog
.nNSCData
[i
] != 1023 && out
.data
.deltHlog
.nNSCData
[i
] != 0)
522 m_double("", 6 - (double)out
.data
.deltHlog
.nNSCData
[i
] / 10);
526 blobmsg_close_array(&b
, c
);
529 static void g997_power_management_status(int fd
) {
530 IOCTL(DSL_G997_PowerManagementStatus_t
, DSL_FIO_G997_POWER_MANAGEMENT_STATUS_GET
)
532 int map
= PSTATE_MAP_UNKNOWN
;
534 switch (out
.data
.nPowerManagementStatus
) {
535 STR_CASE_MAP(DSL_G997_PMS_NA
, "Power management state is not available", PSTATE_MAP_NA
)
536 STR_CASE_MAP(DSL_G997_PMS_L0
, "L0 - Synchronized", PSTATE_MAP_L0
)
537 STR_CASE_MAP(DSL_G997_PMS_L1
, "L1 - Power Down Data transmission (G.992.2)", PSTATE_MAP_L1
)
538 STR_CASE_MAP(DSL_G997_PMS_L2
, "L2 - Power Down Data transmission (G.992.3 and G.992.4)", PSTATE_MAP_L2
)
539 STR_CASE_MAP(DSL_G997_PMS_L3
, "L3 - No power", PSTATE_MAP_L3
)
546 m_str("power_state", str
);
548 if (map
!= PSTATE_MAP_UNKNOWN
)
549 m_u32("power_state_num", map
);
552 static void g997_xtu_system_enabling(int fd
, standard_t
*standard
) {
553 IOCTL(DSL_G997_XTUSystemEnabling_t
, DSL_FIO_G997_XTU_SYSTEM_ENABLING_STATUS_GET
)
555 m_array("xtse", out
.data
.XTSE
, DSL_G997_NUM_XTSE_OCTETS
);
558 switch (get_annex(out
.data
.XTSE
)) {
559 STR_CASE(ANNEX_A
, "A")
560 STR_CASE(ANNEX_B
, "B")
561 STR_CASE(ANNEX_C
, "C")
562 STR_CASE(ANNEX_I
, "I")
563 STR_CASE(ANNEX_J
, "J")
564 STR_CASE(ANNEX_L
, "L")
565 STR_CASE(ANNEX_M
, "M")
573 *standard
= get_standard(out
.data
.XTSE
);
576 STR_CASE(STD_T1_413
, "T1.413")
577 STR_CASE(STD_TS_101_388
, "TS 101 388")
578 STR_CASE(STD_G_992_1
, "G.992.1")
579 STR_CASE(STD_G_992_2
, "G.992.2")
580 STR_CASE(STD_G_992_3
, "G.992.3")
581 STR_CASE(STD_G_992_4
, "G.992.4")
582 STR_CASE(STD_G_992_5
, "G.992.5")
583 STR_CASE(STD_G_993_1
, "G.993.1")
584 STR_CASE(STD_G_993_2
, "G.993.2")
590 m_str("standard", str
);
593 static void get_vector_status(int fd
, vector_t
*status
) {
594 *status
= VECTOR_UNKNOWN
;
596 #ifdef INCLUDE_DSL_CPE_API_VRX
600 IOCTL(IOCTL_MEI_dsmStatus_t
, FIO_MEI_DSM_STATUS_GET
);
602 switch (out
.eVectorStatus
) {
603 case e_MEI_VECTOR_STAT_OFF
:
604 *status
= VECTOR_OFF
;
606 case e_MEI_VECTOR_STAT_ON_DS
:
607 *status
= VECTOR_ON_DS
;
609 case e_MEI_VECTOR_STAT_ON_DS_US
:
610 *status
= VECTOR_ON_DS_US
;
618 static void vector_erb(int fd
) {
619 #ifdef INCLUDE_DSL_CPE_API_VRX
623 IOCTL(IOCTL_MEI_dsmStatistics_t
, FIO_MEI_DSM_STATISTICS_GET
);
625 m_u32("sent", out
.n_processed
);
626 m_u32("discarded", out
.n_fw_dropped_size
+ out
.n_mei_dropped_size
+ out
.n_mei_dropped_no_pp_cb
+ out
.n_pp_dropped
);
630 static void band_plan_status(int fd
, profile_t
*profile
) {
631 #if (INCLUDE_DSL_CPE_API_VDSL_SUPPORT == 1)
632 IOCTL(DSL_BandPlanStatus_t
, DSL_FIO_BAND_PLAN_STATUS_GET
)
634 switch (out
.data
.nProfile
) {
636 *profile
= PROFILE_8A
;
639 *profile
= PROFILE_8B
;
642 *profile
= PROFILE_8C
;
645 *profile
= PROFILE_8D
;
647 case DSL_PROFILE_12A
:
648 *profile
= PROFILE_12A
;
650 case DSL_PROFILE_12B
:
651 *profile
= PROFILE_12B
;
653 case DSL_PROFILE_17A
:
654 *profile
= PROFILE_17A
;
656 case DSL_PROFILE_30A
:
657 *profile
= PROFILE_30A
;
659 case DSL_PROFILE_35B
:
660 *profile
= PROFILE_35B
;
663 *profile
= PROFILE_UNKNOWN
;
669 STR_CASE(PROFILE_8A
, "8a")
670 STR_CASE(PROFILE_8B
, "8b")
671 STR_CASE(PROFILE_8C
, "8c")
672 STR_CASE(PROFILE_8D
, "8d")
673 STR_CASE(PROFILE_12A
, "12a")
674 STR_CASE(PROFILE_12B
, "12b")
675 STR_CASE(PROFILE_17A
, "17a")
676 STR_CASE(PROFILE_30A
, "30a")
677 STR_CASE(PROFILE_35B
, "35b")
683 m_str("profile", str
);
687 static void line_feature_config(int fd
, DSL_AccessDir_t direction
, bool *retx
) {
688 IOCTL_DIR(DSL_LineFeature_t
, DSL_FIO_LINE_FEATURE_STATUS_GET
, direction
)
690 m_bool("trellis", out
.data
.bTrellisEnable
);
691 m_bool("bitswap", out
.data
.bBitswapEnable
);
692 m_bool("retx", out
.data
.bReTxEnable
);
693 m_bool("virtual_noise", out
.data
.bVirtualNoiseSupport
);
695 *retx
= out
.data
.bReTxEnable
;
698 static void g997_rate_adaptation_status(int fd
, DSL_AccessDir_t direction
) {
699 #ifndef INCLUDE_DSL_CPE_API_DANUBE
700 IOCTL_DIR(DSL_G997_RateAdaptationStatus_t
, DSL_FIO_G997_RATE_ADAPTATION_STATUS_GET
, direction
);
702 int map
= RAMODE_MAP_UNKNOWN
;
704 switch (out
.data
.RA_MODE
) {
705 STR_CASE_MAP(DSL_G997_RA_MODE_MANUAL
, "Manual", RAMODE_MAP_MANUAL
)
706 STR_CASE_MAP(DSL_G997_RA_MODE_AT_INIT
, "At initialization", RAMODE_MAP_AT_INIT
)
707 STR_CASE_MAP(DSL_G997_RA_MODE_DYNAMIC
, "Dynamic", RAMODE_MAP_DYNAMIC
)
708 STR_CASE_MAP(DSL_G997_RA_MODE_DYNAMIC_SOS
, "Dynamic with SOS", RAMODE_MAP_DYNAMIC_SOS
)
715 m_str("ra_mode", str
);
717 if (map
!= PSTATE_MAP_UNKNOWN
)
718 m_u32("ra_mode_num", map
);
722 static void g997_channel_status(int fd
, DSL_AccessDir_t direction
) {
723 IOCTL_DIR(DSL_G997_ChannelStatus_t
, DSL_FIO_G997_CHANNEL_STATUS_GET
, direction
);
725 m_u32("interleave_delay", out
.data
.ActualInterleaveDelay
* 10);
726 m_double("inp", (double)out
.data
.ActualImpulseNoiseProtection
/ 10);
727 #ifndef INCLUDE_DSL_CPE_API_DANUBE
728 // prefer ACTNDR, see comments in drv_dsl_cpe_api_g997.h
729 m_u32("data_rate", out
.data
.ActualNetDataRate
);
731 m_u32("data_rate", out
.data
.ActualDataRate
);
735 static void g997_line_status(int fd
, DSL_AccessDir_t direction
) {
736 IOCTL_DIR_DELT(DSL_G997_LineStatus_t
, DSL_FIO_G997_LINE_STATUS_GET
, direction
, DSL_DELT_DATA_SHOWTIME
);
738 // invalid value indicators taken from drv_dsl_cpe_api_g997.h
739 m_db("latn", out
.data
.LATN
, 1271);
740 m_db("satn", out
.data
.SATN
, 1271);
741 m_db("snr", out
.data
.SNR
, -641);
742 m_db("actps", out
.data
.ACTPS
, -901);
743 m_db("actatp", out
.data
.ACTATP
, -512);
744 m_u32("attndr", out
.data
.ATTNDR
);
747 static void pm_retx_counters_showtime(int fd
, DSL_XTUDir_t direction
) {
748 #ifdef INCLUDE_DSL_CPE_PM_RETX_COUNTERS
749 IOCTL_DIR(DSL_PM_ReTxCounters_t
, DSL_FIO_PM_RETX_COUNTERS_SHOWTIME_GET
, direction
);
751 m_u32("mineftr", out
.data
.nEftrMin
);
755 #ifndef INCLUDE_DSL_CPE_API_DANUBE
756 static void olr_statistics(int fd
, DSL_AccessDir_t direction
) {
757 IOCTL_DIR(DSL_OlrStatistics_t
, DSL_FIO_OLR_STATISTICS_GET
, direction
)
759 void *c
= blobmsg_open_table(&b
, "bitswap");
760 m_u32("requested", out
.data
.nBitswapRequested
+ out
.data
.nBitswapRequested
);
761 m_u32("executed", out
.data
.nBitswapExecuted
);
762 m_u32("rejected", out
.data
.nBitswapRejected
);
763 m_u32("timeout", out
.data
.nBitswapTimeout
);
764 blobmsg_close_table(&b
, c
);
766 c
= blobmsg_open_table(&b
, "sra");
767 m_u32("requested", out
.data
.nSraRequested
);
768 m_u32("executed", out
.data
.nSraExecuted
);
769 m_u32("rejected", out
.data
.nSraRejected
);
770 m_u32("timeout", out
.data
.nSraTimeout
);
771 blobmsg_close_table(&b
, c
);
773 c
= blobmsg_open_table(&b
, "sos");
774 m_u32("requested", out
.data
.nSosRequested
);
775 m_u32("executed", out
.data
.nSosExecuted
);
776 m_u32("rejected", out
.data
.nSosRejected
);
777 m_u32("timeout", out
.data
.nSosTimeout
);
778 blobmsg_close_table(&b
, c
);
782 static void pm_line_sec_counters_total(int fd
, DSL_XTUDir_t direction
) {
783 IOCTL_DIR(DSL_PM_LineSecCountersTotal_t
, DSL_FIO_PM_LINE_SEC_COUNTERS_TOTAL_GET
, direction
)
785 m_u32("es", out
.data
.nES
);
786 m_u32("ses", out
.data
.nSES
);
787 m_u32("loss", out
.data
.nLOSS
);
788 m_u32("uas", out
.data
.nUAS
);
789 m_u32("lofs", out
.data
.nLOFS
);
790 #ifndef INCLUDE_DSL_CPE_API_DANUBE
791 m_u32("fecs", out
.data
.nFECS
);
795 static void pm_retx_counters_total(int fd
, DSL_XTUDir_t direction
) {
796 #ifdef INCLUDE_DSL_CPE_PM_RETX_COUNTERS
797 IOCTL_DIR(DSL_PM_ReTxCountersTotal_t
, DSL_FIO_PM_RETX_COUNTERS_TOTAL_GET
, direction
);
799 m_u32("leftrs", out
.data
.nLeftr
);
803 static void pm_channel_counters_total(int fd
, DSL_XTUDir_t direction
) {
804 IOCTL_DIR(DSL_PM_ChannelCountersTotal_t
, DSL_FIO_PM_CHANNEL_COUNTERS_TOTAL_GET
, direction
);
806 m_u32("cv_c", out
.data
.nCodeViolations
);
807 m_u32("fec_c", out
.data
.nFEC
);
810 static void pm_data_path_counters_total(int fd
, DSL_XTUDir_t direction
) {
811 IOCTL_DIR(DSL_PM_DataPathCountersTotal_t
, DSL_FIO_PM_DATA_PATH_COUNTERS_TOTAL_GET
, direction
);
813 m_u32("hec", out
.data
.nHEC
);
814 m_u32("ibe", out
.data
.nIBE
);
815 m_u32("crc_p", out
.data
.nCRC_P
);
816 m_u32("crcp_p", out
.data
.nCRCP_P
);
817 m_u32("cv_p", out
.data
.nCV_P
);
818 m_u32("cvp_p", out
.data
.nCVP_P
);
821 static void retx_statistics(int fd
, DSL_XTUDir_t direction
) {
822 #ifdef INCLUDE_DSL_CPE_PM_RETX_COUNTERS
823 #ifdef INCLUDE_DSL_CPE_PM_RETX_THRESHOLDS
824 IOCTL_DIR(DSL_ReTxStatistics_t
, DSL_FIO_RETX_STATISTICS_GET
, direction
);
826 m_u32("rx_corrupted", out
.data
.nRxCorruptedTotal
);
827 m_u32("rx_uncorrected_protected", out
.data
.nRxUncorrectedProtected
);
828 m_u32("rx_retransmitted", out
.data
.nRxRetransmitted
);
829 m_u32("rx_corrected", out
.data
.nRxCorrected
);
830 m_u32("tx_retransmitted", out
.data
.nTxRetransmitted
);
835 static void describe_mode(standard_t standard
, profile_t profile
, vector_t vector
) {
840 strcpy(buf
, "T1.413");
843 strcpy(buf
, "TS 101 388");
846 strcpy(buf
, "G.992.1 (ADSL)");
849 strcpy(buf
, "G.992.2 (ADSL lite)");
852 strcpy(buf
, "G.992.3 (ADSL2)");
855 strcpy(buf
, "G.992.4 (ADSL2 lite)");
858 strcpy(buf
, "G.992.5 (ADSL2+)");
861 strcpy(buf
, "G.993.1 (VDSL)");
864 strcpy(buf
, "G.993.2 (VDSL2");
868 strcat(buf
, ", Profile 8a");
871 strcat(buf
, ", Profile 8b");
874 strcat(buf
, ", Profile 8c");
877 strcat(buf
, ", Profile 8d");
880 strcat(buf
, ", Profile 12a");
883 strcat(buf
, ", Profile 12b");
886 strcat(buf
, ", Profile 17a");
889 strcat(buf
, ", Profile 30a");
892 strcat(buf
, ", Profile 35b");
900 strcat(buf
, ", with downstream vectoring");
902 case VECTOR_ON_DS_US
:
903 strcat(buf
, ", with down- and upstream vectoring");
918 static int line_statistics(struct ubus_context
*ctx
, struct ubus_object
*obj
,
919 struct ubus_request_data
*req
, const char *method
,
920 struct blob_attr
*msg
)
925 #ifndef INCLUDE_DSL_CPE_API_DANUBE
926 fd
= open(DSL_CPE_DEVICE_NAME
"/0", O_RDWR
, 0644);
928 fd
= open(DSL_CPE_DEVICE_NAME
, O_RDWR
, 0644);
931 return UBUS_STATUS_UNKNOWN_ERROR
;
933 blob_buf_init(&b
, 0);
935 pilot_tones_status(fd
);
937 c
= blobmsg_open_table(&b
, "bands");
938 c2
= blobmsg_open_table(&b
, "downstream");
939 band_border_status(fd
, DSL_DOWNSTREAM
);
940 blobmsg_close_table(&b
, c2
);
941 c2
= blobmsg_open_table(&b
, "upstream");
942 band_border_status(fd
, DSL_UPSTREAM
);
943 blobmsg_close_table(&b
, c2
);
944 blobmsg_close_table(&b
, c
);
946 c
= blobmsg_open_table(&b
, "bits");
947 c2
= blobmsg_open_table(&b
, "downstream");
948 g977_get_bit_allocation(fd
, DSL_DOWNSTREAM
);
949 blobmsg_close_table(&b
, c2
);
950 c2
= blobmsg_open_table(&b
, "upstream");
951 g977_get_bit_allocation(fd
, DSL_UPSTREAM
);
952 blobmsg_close_table(&b
, c2
);
953 blobmsg_close_table(&b
, c
);
955 c
= blobmsg_open_table(&b
, "snr");
956 c2
= blobmsg_open_table(&b
, "downstream");
957 g977_get_snr(fd
, DSL_DOWNSTREAM
);
958 blobmsg_close_table(&b
, c2
);
959 c2
= blobmsg_open_table(&b
, "upstream");
960 g977_get_snr(fd
, DSL_UPSTREAM
);
961 blobmsg_close_table(&b
, c2
);
962 blobmsg_close_table(&b
, c
);
964 c
= blobmsg_open_table(&b
, "qln");
965 c2
= blobmsg_open_table(&b
, "downstream");
966 g977_get_qln(fd
, DSL_DOWNSTREAM
);
967 blobmsg_close_table(&b
, c2
);
968 c2
= blobmsg_open_table(&b
, "upstream");
969 g977_get_qln(fd
, DSL_UPSTREAM
);
970 blobmsg_close_table(&b
, c2
);
971 blobmsg_close_table(&b
, c
);
973 c
= blobmsg_open_table(&b
, "hlog");
974 c2
= blobmsg_open_table(&b
, "downstream");
975 g977_get_hlog(fd
, DSL_DOWNSTREAM
);
976 blobmsg_close_table(&b
, c2
);
977 c2
= blobmsg_open_table(&b
, "upstream");
978 g977_get_hlog(fd
, DSL_UPSTREAM
);
979 blobmsg_close_table(&b
, c2
);
980 blobmsg_close_table(&b
, c
);
982 ubus_send_reply(ctx
, req
, b
.head
);
989 static int metrics(struct ubus_context
*ctx
, struct ubus_object
*obj
,
990 struct ubus_request_data
*req
, const char *method
,
991 struct blob_attr
*msg
)
995 standard_t standard
= STD_UNKNOWN
;
996 profile_t profile
= PROFILE_UNKNOWN
;
997 vector_t vector
= VECTOR_UNKNOWN
;
998 bool retx_up
= false, retx_down
= false;
1000 #ifndef INCLUDE_DSL_CPE_API_DANUBE
1001 fd
= open(DSL_CPE_DEVICE_NAME
"/0", O_RDWR
, 0644);
1003 fd
= open(DSL_CPE_DEVICE_NAME
, O_RDWR
, 0644);
1006 return UBUS_STATUS_UNKNOWN_ERROR
;
1008 #ifdef INCLUDE_DSL_CPE_API_VRX
1009 fd_mei
= open(DSL_CPE_DSL_LOW_DEV
"/0", O_RDWR
, 0644);
1014 blob_buf_init(&b
, 0);
1016 version_information(fd
);
1018 pm_channel_counters_showtime(fd
);
1020 c
= blobmsg_open_table(&b
, "atu_c");
1021 g997_line_inventory(fd
);
1022 blobmsg_close_table(&b
, c
);
1024 g997_power_management_status(fd
);
1025 g997_xtu_system_enabling(fd
, &standard
);
1027 if (standard
== STD_G_993_2
) {
1028 band_plan_status(fd
, &profile
);
1029 get_vector_status(fd_mei
, &vector
);
1032 describe_mode(standard
, profile
, vector
);
1034 c
= blobmsg_open_table(&b
, "upstream");
1037 m_bool("vector", false);
1039 case VECTOR_ON_DS_US
:
1040 m_bool("vector", true);
1045 line_feature_config(fd
, DSL_UPSTREAM
, &retx_up
);
1046 g997_rate_adaptation_status(fd
, DSL_UPSTREAM
);
1047 g997_channel_status(fd
, DSL_UPSTREAM
);
1048 g997_line_status(fd
, DSL_UPSTREAM
);
1050 pm_retx_counters_showtime(fd
, DSL_FAR_END
);
1051 blobmsg_close_table(&b
, c
);
1053 c
= blobmsg_open_table(&b
, "downstream");
1056 m_bool("vector", false);
1059 case VECTOR_ON_DS_US
:
1060 m_bool("vector", true);
1065 line_feature_config(fd
, DSL_DOWNSTREAM
, &retx_down
);
1066 g997_rate_adaptation_status(fd
, DSL_DOWNSTREAM
);
1067 g997_channel_status(fd
, DSL_DOWNSTREAM
);
1068 g997_line_status(fd
, DSL_DOWNSTREAM
);
1070 pm_retx_counters_showtime(fd
, DSL_NEAR_END
);
1071 blobmsg_close_table(&b
, c
);
1073 #ifndef INCLUDE_DSL_CPE_API_DANUBE
1074 c
= blobmsg_open_table(&b
, "olr");
1075 c2
= blobmsg_open_table(&b
, "downstream");
1076 olr_statistics(fd
, DSL_DOWNSTREAM
);
1077 blobmsg_close_table(&b
, c2
);
1078 c2
= blobmsg_open_table(&b
, "upstream");
1079 olr_statistics(fd
, DSL_UPSTREAM
);
1080 blobmsg_close_table(&b
, c2
);
1081 blobmsg_close_table(&b
, c
);
1084 c
= blobmsg_open_table(&b
, "errors");
1085 c2
= blobmsg_open_table(&b
, "near");
1086 pm_line_sec_counters_total(fd
, DSL_NEAR_END
);
1088 pm_retx_counters_total(fd
, DSL_NEAR_END
);
1089 pm_channel_counters_total(fd
, DSL_NEAR_END
);
1090 pm_data_path_counters_total(fd
, DSL_NEAR_END
);
1091 retx_statistics(fd
, DSL_NEAR_END
);
1092 blobmsg_close_table(&b
, c2
);
1094 c2
= blobmsg_open_table(&b
, "far");
1095 pm_line_sec_counters_total(fd
, DSL_FAR_END
);
1097 pm_retx_counters_total(fd
, DSL_FAR_END
);
1098 pm_channel_counters_total(fd
, DSL_FAR_END
);
1099 pm_data_path_counters_total(fd
, DSL_FAR_END
);
1100 retx_statistics(fd
, DSL_FAR_END
);
1101 blobmsg_close_table(&b
, c2
);
1102 blobmsg_close_table(&b
, c
);
1106 case VECTOR_ON_DS_US
:
1107 c
= blobmsg_open_table(&b
, "erb");
1109 blobmsg_close_table(&b
, c
);
1115 ubus_send_reply(ctx
, req
, b
.head
);
1124 static const struct ubus_method dsl_methods
[] = {
1125 UBUS_METHOD_NOARG("metrics", metrics
),
1126 UBUS_METHOD_NOARG("statistics", line_statistics
)
1129 static struct ubus_object_type dsl_object_type
=
1130 UBUS_OBJECT_TYPE("dsl", dsl_methods
);
1132 static struct ubus_object dsl_object
= {
1134 .type
= &dsl_object_type
,
1135 .methods
= dsl_methods
,
1136 .n_methods
= ARRAY_SIZE(dsl_methods
),
1139 static DSL_int_t
ubus_main(DSL_CPE_Thread_Params_t
*params
) {
1147 ctx
= ubus_connect(NULL
);
1151 if (ubus_add_object(ctx
, &dsl_object
)) {
1157 ubus_add_uloop(ctx
);
1159 DSL_CPE_ThreadInit(&thread
, "ubus", ubus_main
, DSL_CPE_PIPE_STACK_SIZE
, DSL_CPE_PIPE_PRIORITY
, 0, 0);
1162 void ubus_deinit() {
1169 DSL_CPE_ThreadShutdown(&thread
, 1000);