In a modern operating system, device drivers serve two purposes:
- They are an abstraction layer
- They move potentially dangerous operations out of user code and into trusted system services
It is important to remember these two purposes when you consider what is and isn't either necessary or advisable when you consider using device drivers. Now, breaking down your question into details:
if your application wants to communicate with some device, it cannot communicate directly with the port that your device is connected to
Right. This is because of the "potentially dangerous operations" part. Communicating with a serial port, depending on the exact hardware you're running on, requires:
- either sending or requesting data on the "IO" signals of the processor or writing or reading from specific memory locations that are associated with the port
- intercepting interrupt signals from the port to let you know when data is available, when its internal buffer is empty, etc.
Typically, these resources are shared between multiple ports, so if your process could do either of these directly, it would be able to interfere with any other process that might be using other ports. Therefore, an intermediary is required that will make sure it only performs actions that won't cause problems with other parts of the system. The device driver is such an intermediary.
But rather, you should create a device driver that is allowed to communicate with the serial port, and then your application will communicate with the device driver.
This is not usually necessary. Operating systems are supplied with serial port drivers, so you don't need to create one yourself. In general, user applications should never need to supply device drivers: device drivers are a system function that are associated with the hardware they run on, not the applications that want to use it. This relates to the "abstraction layer" purpose: there are multiple types of serial port, and the device driver knows in detail how to talk to the actual type that your computer has installed. Your application only needs to know how to talk to the device driver, and your operating system provides a standard interface that allows that without needing to know which exact driver is in use.
Now my question is: when the device driver is sending data to the serial port, does it send the data directly to the serial port, or does the serial port itself have a device driver, and to send data to the serial port, your device driver have to send data to the device driver for the serial port.
This isn't usually necessary. You only need one device driver in order to achieve both purposes:
- The device driver is installed with the system so it can vary depending on what hardware is available, providing abstraction
- The device driver is part of the operating system, and is trusted by the kernel not to allow applications to interfere with each others' operations
That said, there is one case that is similar to the situation you describe, where you may want to have an application-specific device driver which sends data to the hardware-specific device driver. That is if you have a device that you connect to the computer via a serial port, but which you want the application to logically consider as separate to the serial port -- perhaps because you may want to be able to produce a range of devices that have the same behaviour, but maybe there's a serial port version, a USB version, a parallel port version, etc. In that case, it may be worth creating a second driver that provides a second abstraction layer (in this case abstracting the details of how the external device is connected rather than how the port it is connected to works). One example of this (now somewhat relegated to history, thankfully) is the way you used to be able to get mice that connected via serial ports. These would have a driver that implemented the standard mouse protocols and which talked to the serial port driver to actually communicate.