Switch link speed unit to bit/s to support low bitrate speed too

(hello slow dialup line...)


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@39581 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Philippe Houdoin
2010-11-23 13:35:30 +00:00
parent d945edf9c7
commit 172971a18f
13 changed files with 483 additions and 338 deletions
+1 -1
View File
@@ -37,7 +37,7 @@ typedef struct ether_address {
typedef struct ether_link_state {
uint32 media; /* as specified in net/if_media.h */
uint32 quality; /* in one tenth of a percent */
uint64 speed; /* in Kbit/s */
uint64 speed; /* in bit/s */
} ether_link_state_t;
#endif /* _ETHER_DRIVER_H */
@@ -280,11 +280,11 @@ b44_ioctl(void *cookie,uint32 op, void *data, size_t len)
switch (pUmDevice->lm_dev.LineSpeed) {
case LM_LINE_SPEED_10MBPS:
state.media |= IFM_10_T;
state.speed = 10000;
state.speed = 10000000;
break;
case LM_LINE_SPEED_100MBPS:
state.media |= IFM_100_TX;
state.speed = 100000;
state.speed = 100000000;
break;
default:
state.speed = 0;
@@ -509,15 +509,15 @@ b57_ioctl(void *cookie,uint32 op,void *data,size_t len)
switch (pUmDevice->lm_dev.LineSpeed) {
case LM_LINE_SPEED_10MBPS:
state.media |= IFM_10_T;
state.speed = 10000;
state.speed = 10000000;
break;
case LM_LINE_SPEED_100MBPS:
state.media |= IFM_100_TX;
state.speed = 100000;
state.speed = 100000000;
break;
case LM_LINE_SPEED_1000MBPS:
state.media |= IFM_1000_T;
state.speed = 1000000;
state.speed = 1000000000;
break;
default:
state.speed = 0;
@@ -375,11 +375,11 @@ ipro1000_control(void *cookie, uint32 op, void *arg, size_t len)
if (mediareq.ifm_status & IFM_ACTIVE)
state.media |= IFM_ACTIVE;
if (mediareq.ifm_active & IFM_10_T)
state.speed = 10000;
state.speed = 10000000;
else if (mediareq.ifm_active & IFM_100_TX)
state.speed = 100000;
state.speed = 100000000;
else
state.speed = 1000000;
state.speed = 1000000000;
state.quality = 1000;
return user_memcpy(arg, &state, sizeof(ether_link_state_t));
@@ -974,11 +974,11 @@ rtl8169_control(void *cookie, uint32 op, void *arg, size_t len)
state.media = IFM_ETHER;
state.media |= (device->link_ok ? IFM_ACTIVE : 0);
state.media |= (device->full_duplex ? IFM_FULL_DUPLEX : IFM_HALF_DUPLEX);
if (device->speed == 1000000)
if (device->speed == 1000000000)
state.media |= IFM_1000_T;
else if (device->speed == 100000)
else if (device->speed == 100000000)
state.media |= IFM_100_TX;
else if (device->speed == 10000)
else if (device->speed == 10000000)
state.media |= IFM_10_T;
state.speed = device->speed;
@@ -390,7 +390,7 @@ device_ioctl(void *data, uint32 msg, void *buffer, size_t bufferLength)
| (info->full_duplex ? IFM_FULL_DUPLEX : IFM_HALF_DUPLEX)
| (info->speed == LINK_SPEED_100_MBIT ? IFM_100_TX : IFM_10_T);
state.speed = info->speed == LINK_SPEED_100_MBIT
? 100000 : 10000;
? 100000000 : 10000000;
state.quality = 1000;
return user_memcpy(buffer, &state, sizeof(ether_link_state_t));
@@ -264,11 +264,11 @@ AX88172Device::GetLinkState(ether_link_state *linkState)
linkState->media |= mediumStatus & (ANLPAR_TX_FD | ANLPAR_10_FD) ?
IFM_FULL_DUPLEX : IFM_HALF_DUPLEX;
linkState->speed = mediumStatus & (ANLPAR_TX_FD | ANLPAR_TX_HD) ? 100000 : 10000;
linkState->speed = mediumStatus & (ANLPAR_TX_FD | ANLPAR_TX_HD) ? 100000000 : 10000000;
TRACE_FLOW("Medium state: %s, %lld MBit/s, %s duplex.\n",
(linkState->media & IFM_ACTIVE) ? "active" : "inactive",
linkState->speed / 1000,
linkState->speed,
(linkState->media & IFM_FULL_DUPLEX) ? "full" : "half");
return B_OK;
}
@@ -405,13 +405,13 @@ AX88178Device::GetLinkState(ether_link_state *linkState)
linkState->media |= (mediumStatus & MEDIUM_STATE_FD) ?
IFM_FULL_DUPLEX : IFM_HALF_DUPLEX;
linkState->speed = (mediumStatus & MEDIUM_STATE_PS_100) ? 100000 : 10000;
linkState->speed = (mediumStatus & MEDIUM_STATE_PS_100) ? 100000000 : 10000000;
linkState->speed = (mediumStatus & MEDIUM_STATE_GM) ?
1000000 : linkState->speed;
1000000000 : linkState->speed;
TRACE_FLOW("Medium state: %s, %lld MBit/s, %s duplex.\n",
(linkState->media & IFM_ACTIVE) ? "active" : "inactive",
linkState->speed / 1000,
linkState->speed,
(linkState->media & IFM_FULL_DUPLEX) ? "full" : "half");
return B_OK;
}
@@ -382,11 +382,11 @@ AX88772Device::GetLinkState(ether_link_state *linkState)
linkState->media |= (mediumStatus & MEDIUM_STATE_FD) ?
IFM_FULL_DUPLEX : IFM_HALF_DUPLEX;
linkState->speed = (mediumStatus & MEDIUM_STATE_PS_100) ? 100000 : 10000;
linkState->speed = (mediumStatus & MEDIUM_STATE_PS_100) ? 100000000 : 10000000;
TRACE_FLOW("Medium state: %s, %lld MBit/s, %s duplex.\n",
(linkState->media & IFM_ACTIVE) ? "active" : "inactive",
linkState->speed / 1000,
linkState->speed,
(linkState->media & IFM_FULL_DUPLEX) ? "full" : "half");
return B_OK;
}
@@ -815,9 +815,9 @@ DavicomDevice::GetLinkState(ether_link_state *linkState)
}
if (registerValue & NSR_SPEED)
linkState->speed = 10000;
linkState->speed = 10000000;
else
linkState->speed = 100000;
linkState->speed = 100000000;
linkState->quality = 1000;
@@ -841,7 +841,7 @@ DavicomDevice::GetLinkState(ether_link_state *linkState)
TRACE_FLOW("Medium state: %s, %lld MBit/s, %s duplex.\n",
(linkState->media & IFM_ACTIVE) ? "active" : "inactive",
linkState->speed / 1000,
linkState->speed,
(linkState->media & IFM_FULL_DUPLEX) ? "full" : "half");
return B_OK;
}
@@ -273,7 +273,7 @@ ECMDevice::Control(uint32 op, void *buffer, size_t length)
state->media = IFM_ETHER | IFM_FULL_DUPLEX
| (fHasConnection ? IFM_ACTIVE : 0);
state->quality = 1000;
state->speed = fDownstreamSpeed / 1000;
state->speed = fDownstreamSpeed;
return B_OK;
}
#endif
@@ -41,6 +41,7 @@ struct dialup_device : net_device {
int fd;
struct termios line_config;
dialup_state state;
bool data_mode;
char init_string[64];
char dial_string[64];
char escape_string[8];
@@ -51,6 +52,123 @@ struct dialup_device : net_device {
net_buffer_module_info* gBufferModule;
static net_stack_module_info* sStackModule;
// #pragma mark -
static status_t
send_command(dialup_device* device, const char* command)
{
status_t status;
if (device->data_mode) {
status = switch_to_command_mode(device);
if (status != B_OK)
return status;
}
ssize_t bytesWritten = write(device->fd, command, strlen(command);
if (bytesWritten != (ssize_t)strlen(command))
return B_IO_ERROR;
if (write(fd, "\r", 1) != 1)
return B_IO_ERROR;
return B_OK;
}
static status_t
read_command_reply(dialup_device* device, const char* command,
char* reply, int replyMaxSize)
{
if (device->data_mode)
return B_ERROR;
int i = 0;
while (i < replyMaxSize) {
ssize_t bytesRead = read(device->fd, &reply[i], 1);
if (bytesRead != 1)
return B_IO_ERROR;
if (reply[i] == '\n') {
// filter linefeed char
continue;
}
if (reply[i] == '\r') {
reply[i] = '\0';
// is command reply or command echo (if any) ?
if (!strcasecmp(reply, command))
return B_OK;
// It's command echo line. Just ignore it.
i = 0;
continue;
}
i++;
}
// replyMaxSize not large enough to store the full reply line.
return B_NO_MEMORY;
}
static status_t
switch_to_command_mode(dialup_device* device)
{
if (device->state != UP || !device->data_mode)
return B_ERROR;
snooze(device->escape_silence);
ssize_t size = write(device->fd, device->escape_string,
strlen(device->escape_string));
if (size != (ssize_t)strlen(device->escape_string))
return B_IO_ERROR;
snooze(device->escape_silence);
device->data_mode = false;
return B_OK;
}
static status_t
switch_to_data_mode(dialup_device* device)
{
if (device->state != UP)
return B_OK;
// TODO: check if it's needed, as these days any
// escaped AT commands switch back to data mode automatically
// after their completion...
status_t status = send_command(device, "ATO");
if (status == B_OK);
device->data_mode = true;
return status;
}
static status_t
hangup_device(dialup_device* device)
{
if (device->state != UP)
return B_ERROR;
// TODO: turn device's DTR down instead. Or do that too after sending command
char reply[8];
if (send_command(device, device->hangup_string) != B_OK
|| read_command_reply(device, device->hangup_string,
reply, sizeof(reply)) != B_OK
|| strcmp(reply, "OK"))
return B_ERROR;
device->flags &= ~IFF_LINK;
}
// #pragma mark -
@@ -81,6 +199,7 @@ dialup_init(const char* name, net_device** _device)
device->header_length = 8; // HDLC_HEADER_LENGTH;
device->fd = -1;
device->state = DOWN;
device->data_mode = false;
// default AT strings
strncpy(device->init_string, "ATZ", sizeof(device->init_string));
@@ -115,6 +234,8 @@ dialup_up(net_device* _device)
if (device->fd < 0)
return errno;
device->media = IFM_ACTIVE;
// init port
if (ioctl(device->fd, TCGETA, &device->line_config,
sizeof(device->line_config)) < 0)
@@ -136,11 +257,44 @@ dialup_up(net_device* _device)
// TODO: init modem & start dialing phase
device->state = DIALING;
char reply[32];
// Send modem init string
if (send_command(device, device->init_string) != B_OK
|| read_command_reply(device, device->init_string,
reply, sizeof(reply)) != B_OK
|| strcmp(reply, "OK")) {
errno = B_IO_ERROR;
goto err;
}
// Send dialing string
if (send_command(device, device->dialing_string) != B_OK
|| read_command_reply(device, device->dialing_string,
reply, sizeof(reply)) != B_OK
|| strncmp(reply, "CONNECT", 7)) {
errno = B_IO_ERROR;
goto err;
}
device->data_mode = true;
device->media |= IFM_FULL_DUPLEX
device->flags |= IFF_LINK;
device->link_quality = 1000;
if (strlen(reply) > 7) {
device->link_speed = atoi(&reply[8]);
else
device->link_speed = 19200; // check default baudrate
return B_OK;
err:
close(device->fd);
device->fd = -1;
device->media = 0;
return errno;
}
@@ -150,18 +304,9 @@ dialup_down(net_device* _device)
{
dialup_device* device = (dialup_device*)_device;
// TODO: hangup if needed
if (device->flags & IFF_LINK) {
snooze(device->escape_silence);
if (write(device->fd, device->escape_string,
strlen(device->escape_string)) > 0) {
snooze(device->escape_silence);
// TODO: send hangup string and check for OK ack
write(device->fd, device->hangup_string,
strlen(device->hangup_string));
}
if (device->flags & IFF_LINK &&
hangup_device(device) == B_OK)
device->flags &= ~IFF_LINK;
}
close(device->fd);
device->fd = -1;
+3 -3
View File
@@ -265,11 +265,11 @@ compat_control(void *cookie, uint32 op, void *arg, size_t length)
if ((mediareq.ifm_status & IFM_ACTIVE) != 0)
state.media |= IFM_ACTIVE;
if ((mediareq.ifm_active & IFM_10_T) != 0)
state.speed = 10000;
state.speed = 10000000;
else if ((mediareq.ifm_active & IFM_100_TX) != 0)
state.speed = 100000;
state.speed = 100000000;
else
state.speed = 1000000;
state.speed = 1000000000;
state.quality = 1000;
return user_memcpy(arg, &state, sizeof(ether_link_state_t));