How to Enable UART in MT7620 Using Device Tree - embedded-linux

I have platform with MT7620 in MIPS arch. On Platform is instaled OpenWRT. I also use Image Builder to create firmware. Now I whant to enable UART interface in my platform. I think that I must add inode to DT in mt7620.dts file but I do not know what must be the correct syntax. My propozition is below. I also need that UART worked as ttyS0 and console I whant to assigned to ttyS1
So, in file mt7620.dts I whant to add this
chosen {
bootargs = "console=ttyS1,15200";
};
uart#500 {
compatible = "ralink,mt7620a-uart", "ralink,rt2880-uart", "ns16550a";
reg = <0x500 0x100>;
interrupt-parent = <&intc>;
interrupts = <5>;
reg-shift = <2>;
pinctrl-names = "default";
pinctrl-0 = <&uartf_pins>;
status = "ok";
};
Please tell me whether above syntax is correct ?
Main library (dtsi) its following inode UART
uart#500 {
compatible = "ralink,mt7620a-uart", "ralink,rt2880-uart", "ns16550a";
reg = <0x500 0x100>;
resets = <&rstctrl 12>;
reset-names = "uart";
interrupt-parent = <&intc>;
interrupts = <5>;
reg-shift = <2>;
status = "disabled";
};
EITD
The answer is simply. It should be add inode to *.dts
uart#500
{
status = "okay"
}
That is all, because all parameters have been define in *.dtsi file.

Related

Adding custom LCD to the SAMA5D2 XULT

I`m using the Atmel KMS/DRM LCD driver to make it work a custom LCD (ST5651CB + ST5021CB) that I have at home from another project that I wanted to use. So, in order to speed up the development strategy I have divided the problem into several parts which are detailed below.
I have started by integrating the TSC2007 touchscreen driver with successful results, as voltage fluctuations are detected on the screen when it is touched, according to the normal operation after the inclusion of the relevant node in the corresponding i2c bus.
Subsequently, the node for the backlight has been included, making use of the pwm-backlight kernel driver. Also in this case it is fully functional, being able to activate or deactivate it on demand, as well as change the brightness levels (which have been previously defined with the values that oscillate in the interval [0,255]).
Once this has been done, the timing analysis of the panel in SYNC mode has been undertaken using the ST5651CB specification in which this is detailed, to populate the node that makes use of the simple-panel driver of the kernel (to which the backlight previously discussed has been assigned).
(root node)
....
/* Screen brightness */
backlight: backlight {
compatible = "pwm-backlight";
pwms = <&hlcdc_pwm 0 50000 0>;
brightness-levels = <0 4 8 16 32 64 128 255>;
default-brightness-level = <7>;
status = "okay";
};
/* ST5651CB + ST5021CB TFT LCD */
panel: panel {
compatible = "simple-panel";
backlight = <&backlight>;
width-mm = <155>; /* Active area (W) 154.21 */
height-mm = <86>; /* Active area (H) 85.92 */
#address-cells = <1>;
#size-cells = <0>;
status = "okay";
/* SYNC mode */
panel-timing {
clock-frequency = <65000000>; /* Panel clock (Hz) */
hactive = <1024>; /* Active frame width (px) */
vactive = <768>; /* Active frame height (px) */
hfront-porch = <160>; /* Horizontal front porch timing (px) */
hsync-len = <160>; /* HSD blanking (px) */
hback-porch = <160>; /* Horizontal back porch timing (px) */
vfront-porch = <15>; /* Vertical front porch timing (lines) */
vsync-len = <23>; /* VSD blanking (lines) */
vback-porch = <15>; /* Vertical back porch timing (lines) */
pixelclk-active = <0>; /* Data driving on falling edge */
hsync-active = <0>; /* Horizontal sync pulse (low) */
vsync-active = <0>; /* Vertical sync pulse (low) */
de-active = <0>; /* Data enable (low) */
};
port#0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <0>;
panel_input: endpoint#0 {
reg = <0>;
remote-endpoint = <&hlcdc_panel_output>;
};
};
};
...
Also in the kernel argument line (using U-Boot bootargs) I`m specifying the mode by supplying video=Unknown-1:1024x768-16
Finally, and I have conglomerated each of these parts to achieve the final goal, populating the hlcdc node in the device tree and having the LCD functional.
(apb node)
...
hlcdc: hlcdc#f0000000 {
u-boot,dm-pre-reloc;
status = "okay";
hlcdc-display-controller {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_lcd_base &pinctrl_lcd_rgb666 &pinctrl_lcd_reset>;
port#0 {
#address-cells = <1>;
#size-cells = <0>;
hlcdc_panel_output: endpoint#0 {
reg = <0>;
remote-endpoint = <&panel_input>;
};
};
};
hlcdc_pwm: hlcdc-pwm {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_lcd_pwm>;
#pwm-cells = <3>;
};
};
...
The problem is that this strategy does not seem to work because, as mentioned above, because I only have the backlight and the touchscreen functional, but nothing is displayed on the screen.
The question is basically if this guide to integrate a custom LCD in linux is correct or if it has been wrong somewhere.

How to describe correctly GPIO in dts-file to power it off in the "Suspend-to-RAM" mode?

I have GPIO-expnader tca6424 on my board. Pin 17 supplies another chips. I need to power off this chips in the "suspend-to-RAM" mode. I described it in dts file:
hu_u1740: tca6424_hu_u1740#22 {
compatible = "ti,tca6424";
reg = <0x22>;
gpio-controller;
#gpio-cells = <2>;
regulator#17 {
regulator-min-microvolt = <33000000>;
regulator-max-microvolt = <3300000>;
regulator-always-on;
regulator-name = "pw_bt";
enable-active-high;
regulator-state-mem {
regulator-off-in-suspend;
};
};
};
I tried pin 17 as regulator but it doesn't work. If is there ready way or i should write own driver?

Create multiple ramdisk KMDF

I have a question about the KMDF Ramdisk sample of Microsoft.
How do create more than one ramdisk device? How will the PnP manager know to call EvtDeviceAdd and can I control how many times it is called?
WdfDeviceCreate() is used to create ramdisk device in RamDiskEvtDeviceAdd(), but I can not install more than one instance of this ramdisk driver.
NTSTATUS
RamDiskEvtDeviceAdd(
IN WDFDRIVER Driver,
IN PWDFDEVICE_INIT DeviceInit
) {
WDF_OBJECT_ATTRIBUTES deviceAttributes;
NTSTATUS status;
WDFDEVICE device;
WDF_OBJECT_ATTRIBUTES queueAttributes;
WDF_IO_QUEUE_CONFIG ioQueueConfig;
PDEVICE_EXTENSION pDeviceExtension;
PQUEUE_EXTENSION pQueueContext = NULL;
WDFQUEUE queue;
DECLARE_CONST_UNICODE_STRING(ntDeviceName, NT_DEVICE_NAME);
DECLARE_CONST_UNICODE_STRING(MY_SDDL_STRING, L"D:P(A;;GA;;;SY)(A;;GA;;;BA)(A;;GA;;;WD)(A;;GA;;;RC)");
PAGED_CODE();
UNREFERENCED_PARAMETER(Driver);
// Set name
status = WdfDeviceInitAssignName(DeviceInit, &ntDeviceName);
if (!NT_SUCCESS(status)) {
return status;
}
// Set permission
status = WdfDeviceInitAssignSDDLString(DeviceInit, &MY_SDDL_STRING);
if (!NT_SUCCESS(status)) {
return status;
}
WdfDeviceInitSetDeviceType(DeviceInit, FILE_DEVICE_DISK);
WdfDeviceInitSetIoType(DeviceInit, WdfDeviceIoDirect);
WdfDeviceInitSetExclusive(DeviceInit, FALSE);
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&deviceAttributes, DEVICE_EXTENSION);
deviceAttributes.EvtCleanupCallback = RamDiskEvtDeviceContextCleanup;
status = WdfDeviceCreate(&DeviceInit, &deviceAttributes, &device);
if (!NT_SUCCESS(status)) {
return status;
}
pDeviceExtension = DeviceGetExtension(device);
WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE (
&ioQueueConfig,
WdfIoQueueDispatchSequential
);
ioQueueConfig.EvtIoDeviceControl = RamDiskEvtIoDeviceControl;
ioQueueConfig.EvtIoRead = RamDiskEvtIoRead;
ioQueueConfig.EvtIoWrite = RamDiskEvtIoWrite;
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&queueAttributes, QUEUE_EXTENSION);
__analysis_assume(ioQueueConfig.EvtIoStop != 0);
status = WdfIoQueueCreate( device,
&ioQueueConfig,
&queueAttributes,
&queue );
__analysis_assume(ioQueueConfig.EvtIoStop == 0);
if (!NT_SUCCESS(status)) {
return status;
}
// Context is the Queue handle
pQueueContext = QueueGetExtension(queue);
// Set the context for our default queue as our device extension.
pQueueContext->DeviceExtension = pDeviceExtension;
// Now do any RAM-Disk specific initialization
pDeviceExtension->DiskRegInfo.DriveLetter.Buffer =
(PWSTR) &pDeviceExtension->DriveLetterBuffer;
pDeviceExtension->DiskRegInfo.DriveLetter.MaximumLength =
sizeof(pDeviceExtension->DriveLetterBuffer);
// Get the disk parameters from the registry
RamDiskQueryDiskRegParameters(
WdfDriverGetRegistryPath(WdfDeviceGetDriver(device)),
&pDeviceExtension->DiskRegInfo
);
// Allocate memory for the disk image.
pDeviceExtension->DiskImage = ExAllocatePoolWithTag(
NonPagedPool,
pDeviceExtension->DiskRegInfo.DiskSize,
RAMDISK_TAG
);
if (pDeviceExtension->DiskImage) {
UNICODE_STRING deviceName;
UNICODE_STRING win32Name;
RamDiskFormatDisk(pDeviceExtension);
status = STATUS_SUCCESS;
// Now try to create a symbolic link for the drive letter.
RtlInitUnicodeString(&win32Name, DOS_DEVICE_NAME);
RtlInitUnicodeString(&deviceName, NT_DEVICE_NAME);
pDeviceExtension->SymbolicLink.Buffer = (PWSTR)
&pDeviceExtension->DosDeviceNameBuffer;
pDeviceExtension->SymbolicLink.MaximumLength =
sizeof(pDeviceExtension->DosDeviceNameBuffer);
pDeviceExtension->SymbolicLink.Length = win32Name.Length;
RtlCopyUnicodeString(&pDeviceExtension->SymbolicLink, &win32Name);
RtlAppendUnicodeStringToString(&pDeviceExtension->SymbolicLink,
&pDeviceExtension->DiskRegInfo.DriveLetter);
status = WdfDeviceCreateSymbolicLink(device,
&pDeviceExtension->SymbolicLink);
}
return status;
Please help me! Thanks
I understand this is an old post, but since there are no useful answers, I thought I might add my thoughts.
EvtDeviceAdd is called by the KMDF framework when a device matches a hardware ID that your INF supports. (https://msdn.microsoft.com/en-us/library/windows/hardware/ff541693%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396).
According to the VirtualVolume documentation (https://code.msdn.microsoft.com/windowshardware/VirtualVolume-83334efd), the only way to create a device is to call devcon install virtvol.inf virtvol.
You can make multiple RAMDisks by calling devcon install multiple times.

Print labels via a redirected printer

My task is to print labels via a thermal printer. To this purpose a string of tspl(programming language that the printer understands) commands is generated and sent to the printer. The latter is done in C# with the following method taken from the microsoft example "How to send raw data to a printer by using Visual C# .NET"
public static bool SendBytesToPrinter(string szPrinterName, IntPtr pBytes, Int32 dwCount)
{
Int32 dwError = 0, dwWritten = 0;
IntPtr hPrinter = new IntPtr(0);
DOCINFOA di = new DOCINFOA();
bool bSuccess = false; // Assume failure unless you specifically succeed.
di.pDocName = "My C#.NET RAW Document";
di.pDataType = "RAW";
// Open the printer.
if (OpenPrinter(szPrinterName.Normalize(), out hPrinter, IntPtr.Zero))
{
// Start a document.
if (StartDocPrinter(hPrinter, 1, di))
{
// Start a page.
if (StartPagePrinter(hPrinter))
{
// Write your bytes.
bSuccess = WritePrinter(hPrinter, pBytes, dwCount, out dwWritten);
EndPagePrinter(hPrinter);
}
EndDocPrinter(hPrinter);
}
ClosePrinter(hPrinter);
}
// If you did not succeed, GetLastError may give more information
// about why not.
if (bSuccess == false)
{
dwError = Marshal.GetLastWin32Error();
MessageBox.Show("Error " + dwError);
}
return bSuccess;
}
The actual printer is selected in a PrintDialog
private void button2_Click(object sender, EventArgs e)
{
string s = "CLS\nPRINT 1\n"; // device-dependent string, need a FormFeed?
// Allow the user to select a printer.
PrintDialog pd = new PrintDialog();
pd.PrinterSettings = new PrinterSettings();
if (DialogResult.OK == pd.ShowDialog(this))
{
// Send a printer-specific to the printer.
RawPrinterHelper.SendStringToPrinter(pd.PrinterSettings.PrinterName, s);
}
}
In my working environment everything works fine. The environment is a LAN consisting of 3 computers and 1 shared thermal printer:
PC_with_printer - it runs on Windows 7 and has the printer connected to it via USB
PC_aware - it runs on Win 8 and knows about the shared printer
PC_unaware - it runs on WinXP and doens't have the shared printer installed
From PC_aware I connect to PC_unaware via rdp and the printer appears in the list of printers as redirected. Then I run my application , choose the redirected printer and get my empty label printed. So far so good.
Problems begin when I replace PC_unaware with another computer. It runs on Windows Server 2008 R2 and is not in our LAN. Let's call it SERVER. So I carry out the same experiment:
From PC_aware I connect to SERVER via rdp using its public ip address
My thermal printer appears in "Printers and Devices" as "TSC_TDP-244 (redirected 20)"
I go to the printer's properties and click Print Test Page, and it gets printed
I run my app and the printer doesn't print anything.
I have checked return values of all winapi functions that are used in SendBytesToPrinter method (OpenPrinter,StartDocPrinter, StartPagePrinter, WritePrinter,EndPagePrinter,EndDocPrinter, ClosePrinter), and none of them indicates an error. Any idea why it happens and how it may be fixed?
PRINTER_DEFAULTS pd;
pd.DesiredAccess = PRINTER_ACCESS_USE;
pd.pDatatype = NULL;
pd.pDevMode = NULL;
if (!OpenPrinter(szPrinterName, &hPrinter, &pd))
return false;

Looking for a reliable mapping of Forms.Screen.DeviceName to Monitor EDID info

I'm developing an application which will display information derived from the EDID blocks (monitor model, ID, S/N, etc.) on a dialog on the corresponding monitor.
This code works for finding the EDID information for displays. It extracts the EDID information by enumerating the DISPLAY keys under HKLM\SYSTEM\CurrentControlSet\Enum\DISPLAY\[Monitor]\[PnPID]\Device Parameters\EDID.
Update: The above code is relying on "side effects" of PnP use of the registry. I am now using the SetupAPI to enumerate monitors, which correctly handles monitors being attached/removed (unlike the code from the link above.)
I am trying to correlate each Screen in Windows.Forms.Screen.AllScreens[] (\\.\DISPLAY1, \\.\DISPLAY2, etc.) with the entries returned from the above registry inspection.
Note: In the code block below, DisplayDetails.GetMonitorDetails() has now been replaced with more robust registry enumeration code using the SetupAPI, but the data returned is the same.
e.g.
private void Form1_Load(object sender, EventArgs e)
{
Console.WriteLine("Polling displays on {0}:", System.Environment.MachineName);
int i = 0;
foreach ( DisplayDetails dd in DisplayDetails.GetMonitorDetails())
{
Console.WriteLine( "Info: Model: {0}, MonitorID: {1}, PnPID: {2}, Serial#:{3}", dd.Model, dd.MonitorID, dd.PnPID, dd.SerialNumber );
Console.WriteLine( "Does this correlate to Screen: {0}?", Screen.AllScreens[i++].DeviceName );
}
}
Output:
Info: Model: DELL P2411H, MonitorID: DELA06E, PnPID: 5&2e2fefea&0&UID1078018, Serial#:F8NDP0C...PU
Does this correlate to Screen: \\.\DISPLAY1?
Info: Model: DELL P2411H, MonitorID: DELA06E, PnPID: 5&2e2fefea&0&UID1078019, Serial#:F8NDP0C...AU
Does this correlate to Screen: \\.\DISPLAY2?
Answer: NO
In testing, I've found these don't reliably correlate (I have a system in which the first display enumerated is \\.\DISPLAY2).
My Question:
Is there a way to reliably get the EDID information for a given Forms.Screen? I can get the EDID block, but have found no path to correlate this up to the UI top-level Form. Prompting the user is undesirable, as in my use case the two (or more) monitors will likely be the same model and resolution, and only differ by a few digits in the S/N.
I've looked for paths following the Forms.Screen API, Win32 EnumDisplay, other registry GUIDs (PnP and driver-related), but haven't found any promising paths.
I have also investigated the WMI Win32_DesktopMonitor API (Windows 7), however it doesn't appear to have any more information that would help me correlate it to the Windows.Forms.Screen.AllScreens[] entries.
I suspect if there is a way to do this, it's through the SetupAPI, however I haven't found it yet.
A method to resolve the GDI to SetupAPI is available in the EnumDisplayDevices API. If you pass in the EDD_GET_DEVICE_INTERFACE_NAME in for dwFlags, the monitor enumeration will return DeviceID information of the form:
Monitor 0 info:
DeviceName: \\.\DISPLAY1
MonitorInfo: Dell P2411H(Digital)
DeviceID: \\?\DISPLAY#DELA06E#5&2e2fefea&0&UID1078018#{e6f07b5f-ee97-4a90-b076-3
3f57bf4eaa7}
Monitor 1 info:
DeviceName: \\.\DISPLAY2
MonitorInfo: Dell P2411H(Digital)
DeviceID: \\?\DISPLAY#DELA06E#5&2e2fefea&0&UID1078019#{e6f07b5f-ee97-4a90-b076-3
3f57bf4eaa7}
The DeviceID fields now match the results from the didd.DevicePath, as retrieved in the C# fragment below:
Guid MonitorGUID = new Guid(Win32.GUID_DEVINTERFACE_MONITOR);
// We start at the "root" of the device tree and look for all
// devices that match the interface GUID of a monitor
IntPtr h = Win32.SetupDiGetClassDevs(ref MonitorGUID, IntPtr.Zero, IntPtr.Zero, (uint)(Win32.DIGCF_PRESENT | Win32.DIGCF_DEVICEINTERFACE));
if (h.ToInt64() != Win32.INVALID_HANDLE_VALUE)
{
bool Success = true;
uint i = 0;
while (Success)
{
// create a Device Interface Data structure
Win32.SP_DEVICE_INTERFACE_DATA dia = new Win32.SP_DEVICE_INTERFACE_DATA();
dia.cbSize = (uint)Marshal.SizeOf(dia);
// start the enumeration
Success = Win32.SetupDiEnumDeviceInterfaces(h, IntPtr.Zero, ref MonitorGUID, i, ref dia);
if (Success)
{
// build a DevInfo Data structure
Win32.SP_DEVINFO_DATA da = new Win32.SP_DEVINFO_DATA();
da.cbSize = (uint)Marshal.SizeOf(da);
// build a Device Interface Detail Data structure
Win32.SP_DEVICE_INTERFACE_DETAIL_DATA didd = new Win32.SP_DEVICE_INTERFACE_DETAIL_DATA();
didd.cbSize = (uint)(4 + Marshal.SystemDefaultCharSize); // trust me :)
// now we can get some more detailed information
uint nRequiredSize = 0;
uint nBytes = Win32.BUFFER_SIZE;
if (Win32.SetupDiGetDeviceInterfaceDetail(h, ref dia, ref didd, nBytes, out nRequiredSize, ref da))
{
// Now we get the InstanceID
IntPtr ptrInstanceBuf = Marshal.AllocHGlobal((int)nBytes);
Win32.CM_Get_Device_ID(da.DevInst, ptrInstanceBuf, (int)nBytes, 0);
string InstanceID = Marshal.PtrToStringAuto(ptrInstanceBuf);
Console.WriteLine("InstanceID: {0}", InstanceID );
Marshal.FreeHGlobal(ptrInstanceBuf);
Console.WriteLine("DevicePath: {0}", didd.DevicePath );
}
i++;
}
}
}
Win32.SetupDiDestroyDeviceInfoList(h);
}
Sample Output:
InstanceID: DISPLAY\DELA06E\5&2E2FEFEA&0&UID1078018
DevicePath: \\?\display#dela06e#5&2e2fefea&0&uid1078018#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}
The DeviceName from the original EnumDisplayDevices matches the Forms.Screen.DeviceName property.
With these two pieces of information, it is now possible to read the EDID block during the SetupDIEnumDeviceInterface traversal using a fragment like the below:
private static byte[] GetMonitorEDID(IntPtr pDevInfoSet, SP_DEVINFO_DATA deviceInfoData)
{
IntPtr hDeviceRegistryKey = SetupDiOpenDevRegKey(pDevInfoSet, ref deviceInfoData,
DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_QUERY_VALUE);
if (hDeviceRegistryKey == IntPtr.Zero)
{
throw new Exception("Failed to open a registry key for device-specific configuration information");
}
IntPtr ptrBuff = Marshal.AllocHGlobal((int)256);
try
{
RegistryValueKind lpRegKeyType = RegistryValueKind.Binary;
int length = 256;
uint result = RegQueryValueEx(hDeviceRegistryKey, "EDID", 0, ref lpRegKeyType, ptrBuff, ref length);
if (result != 0)
{
throw new Exception("Can not read registry value EDID for device " + deviceInfoData.ClassGuid);
}
}
finally
{
RegCloseKey(hDeviceRegistryKey);
}
byte[] edidBlock = new byte[256];
Marshal.Copy(ptrBuff, edidBlock, 0, 256);
Marshal.FreeHGlobal(ptrBuff);
return edidBlock;
}
Which, finally, can be parsed for the VESA descriptor blocks, as shown in the DisplayDetails.GetMonitorDetails() method in this code.

Resources