usbfs_driver structure was initialized at https://elixir.bootlin.com/linux/latest/source/drivers/usb/core/devio.c#L748 as shown below.
struct usb_driver usbfs_driver = {
.name = "usbfs",
.probe = driver_probe,
.disconnect = driver_disconnect,
.suspend = driver_suspend,
.resume = driver_resume,
.supports_autosuspend = 1,
};
All functions used to initialize the above structure are dummy functions.
As per comment before driver_probe(https://elixir.bootlin.com/linux/latest/source/drivers/usb/core/devio.c#L683),
user space driver will take care of claiming the interface. But user space drivers also needs device file to access the device, Will the usbfs driver creates the device files for each connected device.
What is the use of this usbfs driver in the USB subsystem?
Related
I'm trying to query a list of supported modes from a video adapter driver:
// IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES - Retrieve the count of modes on the display adapter
// Input-Buffer: none
// Output-Buffer: VIDEO_NUM_MODES
VIDEO_NUM_MODES videoNumModes{};
// Send the IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES control code directly to the device driver
ULONG bytesReturned{};
if (::DeviceIoControl(
hDevice, // Handle to the display adapter device
IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES, // IOCTL code
nullptr, 0, // No input param struct
&videoNumModes, sizeof videoNumModes, // Address/size of output param struct
&bytesReturned, // Bytes returned in the output param struct
nullptr)) // Optional OVERLAPPED structure
{
// Allocate a buffer to receive the array of supported modes
const auto bufferSizeInBytes = videoNumModes.NumModes * videoNumModes.ModeInformationLength;
pVideoModeInfo = new VIDEO_MODE_INFORMATION[videoNumModes.NumModes];
// IOCTL_VIDEO_QUERY_AVAIL_MODES - Retrieve the array of supported modes
// Input-Buffer: none
// Output-Buffer: <allocated buffer>
// Send the IOCTL_VIDEO_QUERY_AVAIL_MODES control code directly to the device driver
if (::DeviceIoControl(
hDevice,
IOCTL_VIDEO_QUERY_AVAIL_MODES,
nullptr, 0,
pVideoModeInfo, bufferSizeInBytes,
&bytesReturned,
nullptr))
I get FALSE back on the first DeviceIoControl call with LastError set to ERROR_INVALID_FUNCTION (0x1).
I use this same code successfully to call custom IOCTL stuff in my drivers, so I'm confident that the implementation itself is sound. However, when I open a handle to the device, I'm supposed to use a string containing information about both the device and the interface I'm going to use. I defined the GUID for my custom IOCTL interface, and I use something like the following to send custom IOCTL commands:
hDevice = ::CreateFileW(L"\\\\?\\ROOT#DISPLAY#0000#{5f2f2b485bbd-5201-f1f9-4520-30f4bf353599}", ...);
But the documentation for IOCTL_VIDEO_QUERY_NUM_AVAIL_MODES and IOCTL_VIDEO_QUERY_AVAIL_MODES doesn't mention which interface (GUID) they're a part of.
I assumed that I had to open the adapter device with the GUID_DEVINTERFACE_DISPLAY_ADAPTER interface, but I'm getting Incorrect Function on the first DeviceIoControl call. Same result if I open the adapter or one of its monitors with GUID_DEVINTERFACE_MONITOR.
I've searched online for any code examples, but all I find are from the driver side, responding to the query.
The display adapter driver that I'm issuing this against is an IddCx driver, if that helps. Any clues?
I am writing a network driver for Windows. I want to do something like the pseudocode below:
Init_interface_link_status = disconnected (Equivalent to DOWN in Linux)
Repeat using delayed workitem:
if (condition is true)
interface_link_status = connected (UP)
break
else
interface_link_status = disconnected (DOWN)
All this happens inside the driver code.
I am using Windows Driver Samples as reference. I have found something that looks promising: https://github.com/microsoft/Windows-driver-samples/blob/master/network/ndis/netvmini/6x/adapter.c#L353
AdapterGeneral.MediaConnectState = HWGetMediaConnectStatus(Adapter);
I can set this MediaConnectSate to MediaConnectStateDisconnected here and the driver initialises in Disconnected state which is what I want.
But I can't find a way to change this state elsewhere after the driver is initialised.
Found inspiration from a proprietary network driver code.
This function turns interface on/off:
VOID NSUChangeAdapterLinkState(
_In_ PMP_ADAPTER Adapter,
_In_ BOOLEAN TurnInterfaceUP)
/*++
Routine Description:
Change Adapter Link's state. This is equivalent to doing ifup/ifdown on Linux.
Arguments:
Adapter - Pointer to our adapter
TurnInterfaceUP - Pass TRUE to turn interface UP, FALSE to turn DOWN
Return Value:
None
--*/
{
NDIS_LINK_STATE LinkState;
NDIS_STATUS_INDICATION StatusIndication;
RtlZeroMemory(&LinkState, sizeof(LinkState));
LinkState.Header.Revision = NDIS_LINK_STATE_REVISION_1;
LinkState.Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
LinkState.Header.Size = NDIS_SIZEOF_LINK_STATE_REVISION_1;
if (TurnInterfaceUP)
{
LinkState.MediaConnectState = MediaConnectStateConnected;
MP_CLEAR_FLAG(Adapter, fMP_DISCONNECTED);
} else
{
LinkState.MediaConnectState = MediaConnectStateDisconnected;
MP_SET_FLAG(Adapter, fMP_DISCONNECTED);
}
LinkState.RcvLinkSpeed = Adapter->ulLinkRecvSpeed;
LinkState.XmitLinkSpeed = Adapter->ulLinkSendSpeed;
LinkState.MediaDuplexState = MediaDuplexStateFull;
RtlZeroMemory(&StatusIndication, sizeof(StatusIndication));
StatusIndication.Header.Type = NDIS_OBJECT_TYPE_STATUS_INDICATION;
StatusIndication.Header.Revision = NDIS_STATUS_INDICATION_REVISION_1;
StatusIndication.Header.Size = NDIS_SIZEOF_STATUS_INDICATION_REVISION_1;
StatusIndication.SourceHandle = Adapter->AdapterHandle;
StatusIndication.StatusCode = NDIS_STATUS_LINK_STATE;
StatusIndication.StatusBuffer = &LinkState;
StatusIndication.StatusBufferSize = sizeof(NDIS_LINK_STATE);
NdisMIndicateStatusEx(Adapter->AdapterHandle, &StatusIndication);
}
I am currently writing a device tree node to configure SCISIS752 Dual Channel UART with I2C which is connected to the slave address 0x4d. I am also using a clock of 1.8432MHz. The IRQ pin of SCISIS752 is attached to an IO Expander GPIO which is gpiopin 456 in my case.
I am using yocto to create the linux distro. My linux kernel version 4.18.25-yocto-standard
My dts configuration:
/dts-v1/;
#include "am33xx.dtsi"
#include "am335x-bone-common.dtsi"
#include "am335x-boneblack-common.dtsi"
/ {
model = "TI AM335x BeagleBone Black";
compatible = "ti,am335x-bone-black", "ti,am335x-bone", "ti,am33xx";
};
&am33xx_pinmux {
pinctrl-0 = <&gpio_pins>;
i2c1_pins_default: i2c1_pins_default {
pinctrl-single,pins = <
AM33XX_IOPAD(0x984, PIN_INPUT_PULLUP | MUX_MODE3) /* (D15) uart1_txd.I2C1_SCL */
AM33XX_IOPAD(0x980, PIN_INPUT_PULLUP | MUX_MODE3) /* (D16) uart1_rxd.I2C1_SDA */
>;};
&i2c1 {
pinctrl-names = "default";
pinctrl-0 = <&i2c1_pins_default>;
status = "okay";
clock-frequency = <400000>;
pcf8574a_38: pcf8574a#38 {
compatible = "nxp,pcf8574a";
reg = <0x38>;
gpio-controller;
#gpio-cells = <2>;
};
sc16is752#4d {
compatible = "nxp,sc16is752";
reg = <0x4d>;
clocks = <&sc16is752_clk>;
interrupt-parent = <&gpio3>;
interrupts = <7 2>;
gpio-controller;
#gpio-cells = <2>;
sc16is752_clk: sc16is752_clk {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <1843200>;
};};
};
I am confused on setting the values of interrupt-parent and interrupts to make this configuration work.
I cannot see your entire device tree, nor do I know what kernel you are running... so I can't point to where your exact problem is. But I can provide some guidance in troubleshooting...
First, it appears you've copied your node from the kernel documentation in Documentation/devicetree/bindings/serial/nxp,sc16is7xx.txt. That is a point of reference, but it's simply meant to illustrate.
There is nothing magical about the device tree. It is parsed by drivers in the kernel to describe the electrical configuration. Which means, anytime you're not sure how something works, all you need to do is look at the driver to see how it parses it.
I happen to have the 4.19.0 source code on me. I found your NXP driver in drivers/tty/serial/sc16is7xx.c. I confirmed through the compatible list that it supports nxp,sc16is752.
Start at the probe sc16is7xx_i2c_probe() where the driver is entered and you will immediately see that an IRQ value is being passed in through the i2c_client structure and then setup by the call to devm_request_irq() in sc16is7xx_probe(). This means that the interrupt DT properties aren't processed in this driver. They are passed to it.
You then need to read: https://www.kernel.org/doc/Documentation/devicetree/bindings/interrupt-controller/interrupts.txt to understand how interrupt controllers work. Does your &gpio3 meet the requirements? Is it configured as an interrupt controller? Does the it even exist?
One of Linux kernel training courses task is to add sysfs support to one of previously written device drivers. I choose my ds1307 rtc driver and want to add device attributes, not to replace rtc device ones.
But I am not sure that my solution is correct.
At the time when the probe function is called i2c client device is already created, so that any manipulation on device attributes will cause race condition.
Thus I decide to add my attributes to rtc device before device registration. I just count default rtc attribute groups, allocate new array with one extra position for my attribute group and replace rtc device groups pointer with allocated array.
static int ds1307x_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct device *dev;
const struct attribute_group **grp, **ngrp;
struct rtc_device *rtc;
int ret, cnt;
/* device presence check code skipped */
dev = &client->dev;
rtc = devm_rtc_allocate_device(dev);
if (!rtc)
return -ENOMEM;
dev = &rtc->dev;
grp = dev->groups;
if (!grp) {
/* no default groups, just use own groups array */
dev->groups = ds1307x_groups;
} else {
/* copy rtc groups array, add own group at end */
cnt = 0;
while (grp[cnt])
++cnt;
ngrp = devm_kmalloc(&rtc->dev, (cnt+2) * sizeof(*ngrp),
GFP_KERNEL);
if (!ngrp)
return -ENOMEM;
memcpy(ngrp, grp, cnt * sizeof(*ngrp));
ngrp[cnt] = &ds1307x_group;
ngrp[cnt+1] = NULL;
dev->groups = ngrp;
}
rtc->uie_unsupported = 1;
rtc->ops = &ds1307x_ops;
ret = rtc_register_device(rtc);
/* remaining of code skipped */
}
Attribute group ds1307x_control with attributes clock_halt and out_ctrl appears in rtc0 device directory among standard rtc class attributes:
~ # ls /sys/class/rtc/rtc0/
date ds1307x_control name subsystem
dev hctosys power time
device max_user_freq since_epoch uevent
~ # ls /sys/class/rtc/rtc0/ds1307x_control/
clock_halt out_ctrl
This solution works for me and I hope it is good enough for training courses.
But what about real life? Are there any hidden problems?
the device driver I'm working on is implementing a virtual device. The logic
is as follows:
static struct net_device_ops virt_net_ops = {
.ndo_init = virt_net_init,
.ndo_open = virt_net_open,
.ndo_stop = virt_net_stop,
.ndo_do_ioctl = virt_net_ioctl,
.ndo_get_stats = virt_net_get_stats,
.ndo_start_xmit = virt_net_start_xmit,
};
...
struct net_device *dev;
struct my_dev *virt;
dev = alloc_netdev(..);
/* check for NULL */
virt = netdev_priv(dev);
dev->netdev_ops = &virt_net_ops;
SET_ETHTOOL_OPS(dev, &virt_ethtool_ops);
dev_net_set(dev, net);
virt->magic = MY_VIRT_DEV_MAGIC;
ret = register_netdev(dev);
if (ret) {
printk("register_netdev failed\n");
free_netdev(dev);
return ret;
}
...
What happens is that somewhere somehow the pointer net_device_ops in
'net_dev' gets corrupted, i.e.
1) create the device the first time (allocated net_dev, init the fields
including net_device_ops,which is
initialized with a static structure containing function pointers), register
the device with the kernel invoking register_netdev() - OK
2) attempt to create the device with the same name again, repeat the above
steps, call register_netdev() which will return negative and we
free_netdev(dev) and return error to the caller.
And between these two events the pointer to net_device_ops has changed,
although nowhere in the code it is done explicitly except the initialization
phase.
The kernel version is 2.6.31.8, platform MIPS. Communication channel between the user space and the kernel is implemented via netlink sockets.
Could anybody suggest what possibly can go wrong?
Appreciate any advices, thanks.
Mark
"The bug is somewhere else. "
The second device should not interact with the existing one. If you register_netdev with an existing name, nevertheless the ndo_init virtual function is called first before the condition is detected and -EEXIST is returned. Maybe your init function does something nasty involving some global variables. (For example, does the code assume there is one device, and stash a global pointer to it during initialization?)