Big serial- and disk-redirection update from
Andreas Flick <Andreas.Flick@unicon-ka.de> git-svn-id: svn://svn.code.sf.net/p/rdesktop/code/trunk/rdesktop@794 423420c4-83ab-492f-b58f-81f9feb106b5
This commit is contained in:
parent
4ad6d8d4e0
commit
53eabea36f
@ -340,6 +340,7 @@ enum RDP_INPUT_DEVICE
|
||||
|
||||
/* NT status codes for RDPDR */
|
||||
#define STATUS_SUCCESS 0x00000000
|
||||
#define STATUS_NOT_IMPLEMENTED 0x00000001
|
||||
#define STATUS_PENDING 0x00000103
|
||||
|
||||
#define STATUS_NO_MORE_FILES 0x80000006
|
||||
@ -358,6 +359,7 @@ enum RDP_INPUT_DEVICE
|
||||
#define STATUS_FILE_IS_A_DIRECTORY 0xc00000ba
|
||||
#define STATUS_NOT_SUPPORTED 0xc00000bb
|
||||
#define STATUS_TIMEOUT 0xc0000102
|
||||
#define STATUS_NOTIFY_ENUM_DIR 0xc000010c
|
||||
#define STATUS_CANCELLED 0xc0000120
|
||||
|
||||
|
||||
@ -371,6 +373,8 @@ enum RDP_INPUT_DEVICE
|
||||
|
||||
#define FILE_DIRECTORY_FILE 0x00000001
|
||||
#define FILE_NON_DIRECTORY_FILE 0x00000040
|
||||
#define FILE_COMPLETE_IF_OPLOCKED 0x00000100
|
||||
#define FILE_DELETE_ON_CLOSE 0x00001000
|
||||
#define FILE_OPEN_FOR_FREE_SPACE_QUERY 0x00800000
|
||||
|
||||
/* RDP5 disconnect PDU */
|
||||
|
194
disk.c
194
disk.c
@ -81,6 +81,7 @@
|
||||
extern RDPDR_DEVICE g_rdpdr_device[];
|
||||
|
||||
FILEINFO g_fileinfo[MAX_OPEN_FILES];
|
||||
BOOL g_notify_stamp = False;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@ -90,6 +91,7 @@ typedef struct
|
||||
char type[256];
|
||||
} FsInfoType;
|
||||
|
||||
static NTSTATUS NotifyInfo(NTHANDLE handle, uint32 info_class, NOTIFY * p);
|
||||
|
||||
static time_t
|
||||
get_create_time(struct stat *st)
|
||||
@ -328,7 +330,7 @@ disk_create(uint32 device_id, uint32 accessmask, uint32 sharemode, uint32 create
|
||||
break;
|
||||
}
|
||||
|
||||
//printf("Open: \"%s\" flags: %u, accessmask: %u sharemode: %u create disp: %u\n", path, flags_and_attributes, accessmask, sharemode, create_disposition);
|
||||
//printf("Open: \"%s\" flags: %X, accessmask: %X sharemode: %X create disp: %X\n", path, flags_and_attributes, accessmask, sharemode, create_disposition);
|
||||
|
||||
// Get information about file and set that flag ourselfs
|
||||
if ((stat(path, &filestat) == 0) && (S_ISDIR(filestat.st_mode)))
|
||||
@ -424,9 +426,15 @@ disk_create(uint32 device_id, uint32 accessmask, uint32 sharemode, uint32 create
|
||||
|
||||
if (dirp)
|
||||
g_fileinfo[handle].pdir = dirp;
|
||||
else
|
||||
g_fileinfo[handle].pdir = NULL;
|
||||
|
||||
g_fileinfo[handle].device_id = device_id;
|
||||
g_fileinfo[handle].flags_and_attributes = flags_and_attributes;
|
||||
g_fileinfo[handle].accessmask = accessmask;
|
||||
strncpy(g_fileinfo[handle].path, path, 255);
|
||||
g_fileinfo[handle].delete_on_close = False;
|
||||
g_notify_stamp = True;
|
||||
|
||||
*phandle = handle;
|
||||
return STATUS_SUCCESS;
|
||||
@ -439,14 +447,41 @@ disk_close(NTHANDLE handle)
|
||||
|
||||
pfinfo = &(g_fileinfo[handle]);
|
||||
|
||||
if (pfinfo->flags_and_attributes & FILE_DIRECTORY_FILE)
|
||||
g_notify_stamp = True;
|
||||
|
||||
rdpdr_abort_io(handle, 0, STATUS_CANCELLED);
|
||||
|
||||
if (pfinfo->pdir)
|
||||
{
|
||||
closedir(pfinfo->pdir);
|
||||
//FIXME: Should check exit code
|
||||
if (closedir(pfinfo->pdir) < 0)
|
||||
{
|
||||
perror("closedir");
|
||||
return STATUS_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
if (pfinfo->delete_on_close)
|
||||
if (rmdir(pfinfo->path) < 0)
|
||||
{
|
||||
perror(pfinfo->path);
|
||||
return STATUS_ACCESS_DENIED;
|
||||
}
|
||||
pfinfo->delete_on_close = False;
|
||||
}
|
||||
else
|
||||
{
|
||||
close(handle);
|
||||
if (close(handle) < 0)
|
||||
{
|
||||
perror("close");
|
||||
return STATUS_INVALID_HANDLE;
|
||||
}
|
||||
if (pfinfo->delete_on_close)
|
||||
if (unlink(pfinfo->path) < 0)
|
||||
{
|
||||
perror(pfinfo->path);
|
||||
return STATUS_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
pfinfo->delete_on_close = False;
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
@ -477,7 +512,10 @@ disk_read(NTHANDLE handle, uint8 * data, uint32 length, uint32 offset, uint32 *
|
||||
switch (errno)
|
||||
{
|
||||
case EISDIR:
|
||||
return STATUS_FILE_IS_A_DIRECTORY;
|
||||
/* Implement 24 Byte directory read ??
|
||||
with STATUS_NOT_IMPLEMENTED server doesn't read again */
|
||||
/* return STATUS_FILE_IS_A_DIRECTORY; */
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
default:
|
||||
perror("read");
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
@ -600,10 +638,9 @@ disk_query_information(NTHANDLE handle, uint32 info_class, STREAM out)
|
||||
NTSTATUS
|
||||
disk_set_information(NTHANDLE handle, uint32 info_class, STREAM in, STREAM out)
|
||||
{
|
||||
uint32 length, file_attributes, ft_high, ft_low;
|
||||
uint32 length, file_attributes, ft_high, ft_low, delete_on_close;
|
||||
char newname[256], fullpath[256];
|
||||
struct fileinfo *pfinfo;
|
||||
|
||||
int mode;
|
||||
struct stat filestat;
|
||||
time_t write_time, change_time, access_time, mod_time;
|
||||
@ -611,6 +648,7 @@ disk_set_information(NTHANDLE handle, uint32 info_class, STREAM in, STREAM out)
|
||||
struct STATFS_T stat_fs;
|
||||
|
||||
pfinfo = &(g_fileinfo[handle]);
|
||||
g_notify_stamp = True;
|
||||
|
||||
switch (info_class)
|
||||
{
|
||||
@ -670,7 +708,7 @@ disk_set_information(NTHANDLE handle, uint32 info_class, STREAM in, STREAM out)
|
||||
printf("FileBasicInformation modification time %s",
|
||||
ctime(&tvs.modtime));
|
||||
#endif
|
||||
if (utime(pfinfo->path, &tvs))
|
||||
if (utime(pfinfo->path, &tvs) && errno != EPERM)
|
||||
return STATUS_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
@ -728,25 +766,16 @@ disk_set_information(NTHANDLE handle, uint32 info_class, STREAM in, STREAM out)
|
||||
FileDispositionInformation requests with
|
||||
DeleteFile set to FALSE should unschedule
|
||||
the delete. See
|
||||
http://www.osronline.com/article.cfm?article=245. Currently,
|
||||
we are deleting the file immediately. I
|
||||
guess this is a FIXME. */
|
||||
http://www.osronline.com/article.cfm?article=245. */
|
||||
|
||||
//in_uint32_le(in, delete_on_close);
|
||||
in_uint32_le(in, delete_on_close);
|
||||
|
||||
/* Make sure we close the file before
|
||||
unlinking it. Not doing so would trigger
|
||||
silly-delete if using NFS, which might fail
|
||||
on FAT floppies, for example. */
|
||||
disk_close(handle);
|
||||
|
||||
if ((pfinfo->flags_and_attributes & FILE_DIRECTORY_FILE)) // remove a directory
|
||||
if (delete_on_close ||
|
||||
(pfinfo->
|
||||
accessmask & (FILE_DELETE_ON_CLOSE | FILE_COMPLETE_IF_OPLOCKED)))
|
||||
{
|
||||
if (rmdir(pfinfo->path) < 0)
|
||||
return STATUS_ACCESS_DENIED;
|
||||
pfinfo->delete_on_close = True;
|
||||
}
|
||||
else if (unlink(pfinfo->path) < 0) // unlink a file
|
||||
return STATUS_ACCESS_DENIED;
|
||||
|
||||
break;
|
||||
|
||||
@ -763,7 +792,7 @@ disk_set_information(NTHANDLE handle, uint32 info_class, STREAM in, STREAM out)
|
||||
|
||||
/* prevents start of writing if not enough space left on device */
|
||||
if (STATFS_FN(g_rdpdr_device[pfinfo->device_id].local_path, &stat_fs) == 0)
|
||||
if (stat_fs.f_bsize * stat_fs.f_bfree < length)
|
||||
if (stat_fs.f_bfree * stat_fs.f_bsize < length)
|
||||
return STATUS_DISK_FULL;
|
||||
|
||||
if (ftruncate_growable(handle, length) != 0)
|
||||
@ -780,20 +809,129 @@ disk_set_information(NTHANDLE handle, uint32 info_class, STREAM in, STREAM out)
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
disk_check_notify(NTHANDLE handle)
|
||||
{
|
||||
struct fileinfo *pfinfo;
|
||||
NTSTATUS status = STATUS_PENDING;
|
||||
|
||||
NOTIFY notify;
|
||||
|
||||
pfinfo = &(g_fileinfo[handle]);
|
||||
if (!pfinfo->pdir)
|
||||
return STATUS_INVALID_DEVICE_REQUEST;
|
||||
|
||||
|
||||
|
||||
status = NotifyInfo(handle, pfinfo->info_class, ¬ify);
|
||||
|
||||
if (status != STATUS_PENDING)
|
||||
return status;
|
||||
|
||||
if (memcmp(&pfinfo->notify, ¬ify, sizeof(NOTIFY)))
|
||||
{
|
||||
//printf("disk_check_notify found changed event\n");
|
||||
memcpy(&pfinfo->notify, ¬ify, sizeof(NOTIFY));
|
||||
status = STATUS_NOTIFY_ENUM_DIR;
|
||||
}
|
||||
|
||||
return status;
|
||||
|
||||
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
disk_create_notify(NTHANDLE handle, uint32 info_class)
|
||||
{
|
||||
|
||||
struct fileinfo *pfinfo;
|
||||
NTSTATUS ret = STATUS_PENDING;
|
||||
|
||||
/* printf("start disk_create_notify info_class %X\n", info_class); */
|
||||
|
||||
pfinfo = &(g_fileinfo[handle]);
|
||||
pfinfo->info_class = info_class;
|
||||
|
||||
ret = NotifyInfo(handle, info_class, &pfinfo->notify);
|
||||
|
||||
if (info_class & 0x1000)
|
||||
{ /* ???? */
|
||||
if (ret == STATUS_PENDING)
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* printf("disk_create_notify: num_entries %d\n", pfinfo->notify.num_entries); */
|
||||
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
static NTSTATUS
|
||||
NotifyInfo(NTHANDLE handle, uint32 info_class, NOTIFY * p)
|
||||
{
|
||||
struct fileinfo *pfinfo;
|
||||
struct stat buf;
|
||||
struct dirent *dp;
|
||||
char *fullname;
|
||||
DIR *dpr;
|
||||
|
||||
pfinfo = &(g_fileinfo[handle]);
|
||||
if (fstat(handle, &buf) < 0)
|
||||
{
|
||||
perror("NotifyInfo");
|
||||
return STATUS_ACCESS_DENIED;
|
||||
}
|
||||
p->modify_time = buf.st_mtime;
|
||||
p->status_time = buf.st_ctime;
|
||||
p->num_entries = 0;
|
||||
p->total_time = 0;
|
||||
|
||||
|
||||
dpr = opendir(pfinfo->path);
|
||||
if (!dpr)
|
||||
{
|
||||
perror("NotifyInfo");
|
||||
return STATUS_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
|
||||
while ((dp = readdir(dpr)))
|
||||
{
|
||||
if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
|
||||
continue;
|
||||
p->num_entries++;
|
||||
fullname = xmalloc(strlen(pfinfo->path) + strlen(dp->d_name) + 2);
|
||||
sprintf(fullname, "%s/%s", pfinfo->path, dp->d_name);
|
||||
|
||||
if (!stat(fullname, &buf))
|
||||
{
|
||||
p->total_time += (buf.st_mtime + buf.st_ctime);
|
||||
}
|
||||
|
||||
xfree(fullname);
|
||||
}
|
||||
closedir(dpr);
|
||||
|
||||
return STATUS_PENDING;
|
||||
}
|
||||
|
||||
static FsInfoType *
|
||||
FsVolumeInfo(char *fpath)
|
||||
{
|
||||
|
||||
#ifdef HAVE_MNTENT_H
|
||||
FILE *fdfs;
|
||||
struct mntent *e;
|
||||
static FsInfoType info;
|
||||
#ifdef HAVE_MNTENT_H
|
||||
struct mntent *e;
|
||||
#endif
|
||||
|
||||
/* initialize */
|
||||
memset(&info, 0, sizeof(info));
|
||||
strcpy(info.label, "RDESKTOP");
|
||||
strcpy(info.type, "RDPFS");
|
||||
|
||||
#ifdef HAVE_MNTENT_H
|
||||
fdfs = setmntent(MNTENT_PATH, "r");
|
||||
if (!fdfs)
|
||||
return &info;
|
||||
@ -836,8 +974,6 @@ FsVolumeInfo(char *fpath)
|
||||
}
|
||||
endmntent(fdfs);
|
||||
#else
|
||||
static FsInfoType info;
|
||||
|
||||
/* initialize */
|
||||
memset(&info, 0, sizeof(info));
|
||||
strcpy(info.label, "RDESKTOP");
|
||||
|
3
proto.h
3
proto.h
@ -32,6 +32,8 @@ NTSTATUS disk_query_information(NTHANDLE handle, uint32 info_class, STREAM out);
|
||||
NTSTATUS disk_set_information(NTHANDLE handle, uint32 info_class, STREAM in, STREAM out);
|
||||
NTSTATUS disk_query_volume_information(NTHANDLE handle, uint32 info_class, STREAM out);
|
||||
NTSTATUS disk_query_directory(NTHANDLE handle, uint32 info_class, char *pattern, STREAM out);
|
||||
NTSTATUS disk_create_notify(NTHANDLE handle, uint32 info_class);
|
||||
NTSTATUS disk_check_notify(NTHANDLE handle);
|
||||
/* mppc.c */
|
||||
int mppc_expand(uint8 * data, uint32 clen, uint8 ctype, uint32 * roff, uint32 * rlen);
|
||||
/* ewmhints.c */
|
||||
@ -144,6 +146,7 @@ void sec_disconnect(void);
|
||||
/* serial.c */
|
||||
int serial_enum_devices(uint32 * id, char *optarg);
|
||||
BOOL serial_get_timeout(NTHANDLE handle, uint32 length, uint32 * timeout, uint32 * itv_timeout);
|
||||
BOOL serial_get_event(NTHANDLE handle, uint32 * result);
|
||||
/* tcp.c */
|
||||
STREAM tcp_init(uint32 maxlen);
|
||||
void tcp_send(STREAM s);
|
||||
|
193
rdpdr.c
193
rdpdr.c
@ -61,6 +61,7 @@ extern DEVICE_FNS printer_fns;
|
||||
extern DEVICE_FNS parallel_fns;
|
||||
extern DEVICE_FNS disk_fns;
|
||||
extern FILEINFO g_fileinfo[];
|
||||
extern BOOL g_notify_stamp;
|
||||
|
||||
static VCHANNEL *rdpdr_channel;
|
||||
|
||||
@ -323,8 +324,11 @@ rdpdr_send_completion(uint32 device, uint32 id, uint32 status, uint32 result, ui
|
||||
out_uint32_le(s, result);
|
||||
out_uint8p(s, buffer, length);
|
||||
s_mark_end(s);
|
||||
/* JIF
|
||||
hexdump(s->channel_hdr + 8, s->end - s->channel_hdr - 8); */
|
||||
/* JIF */
|
||||
#ifdef WITH_DEBUG_RDP5
|
||||
printf("--> rdpdr_send_completion\n");
|
||||
//hexdump(s->channel_hdr + 8, s->end - s->channel_hdr - 8);
|
||||
#endif
|
||||
channel_send(s, rdpdr_channel);
|
||||
}
|
||||
|
||||
@ -623,15 +627,25 @@ rdpdr_process_irp(STREAM s)
|
||||
case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
|
||||
|
||||
/* JIF
|
||||
unimpl("IRP major=0x%x minor=0x%x: IRP_MN_NOTIFY_CHANGE_DIRECTORY\n", major, minor); */
|
||||
status = STATUS_PENDING; // Don't send completion packet
|
||||
unimpl("IRP major=0x%x minor=0x%x: IRP_MN_NOTIFY_CHANGE_DIRECTORY\n", major, minor); */
|
||||
|
||||
in_uint32_le(s, info_level); // notify mask
|
||||
|
||||
g_notify_stamp = True;
|
||||
|
||||
status = disk_create_notify(file, info_level);
|
||||
result = 0;
|
||||
|
||||
if (status == STATUS_PENDING)
|
||||
add_async_iorequest(device, file, id, major, length,
|
||||
fns, 0, 0, NULL, 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
status = STATUS_INVALID_PARAMETER;
|
||||
/* JIF
|
||||
unimpl("IRP major=0x%x minor=0x%x\n", major, minor); */
|
||||
/* JIF */
|
||||
unimpl("IRP major=0x%x minor=0x%x\n", major, minor);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -659,6 +673,17 @@ rdpdr_process_irp(STREAM s)
|
||||
out.size = sizeof(buffer);
|
||||
status = fns->device_control(file, request, s, &out);
|
||||
result = buffer_len = out.p - out.data;
|
||||
|
||||
/* Serial SERIAL_WAIT_ON_MASK */
|
||||
if (status == STATUS_PENDING)
|
||||
{
|
||||
if (add_async_iorequest
|
||||
(device, file, id, major, length, fns, 0, 0, NULL, 0))
|
||||
{
|
||||
status = STATUS_PENDING;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
@ -827,25 +852,34 @@ rdpdr_add_fds(int *n, fd_set * rfds, fd_set * wfds, struct timeval *tv, BOOL * t
|
||||
reconnecting. FIXME: Real
|
||||
support for reconnects. */
|
||||
|
||||
if ((read(iorq->fd, &c, 0) != 0) && (errno == EBADF))
|
||||
break;
|
||||
|
||||
FD_SET(iorq->fd, rfds);
|
||||
*n = MAX(*n, iorq->fd);
|
||||
|
||||
// Check if io request timeout is smaller than current (but not 0).
|
||||
/* Check if io request timeout is smaller than current (but not 0). */
|
||||
if (iorq->timeout
|
||||
&& (select_timeout == 0
|
||||
|| iorq->timeout < select_timeout))
|
||||
{
|
||||
// Set new timeout
|
||||
/* Set new timeout */
|
||||
select_timeout = iorq->timeout;
|
||||
g_min_timeout_fd = iorq->fd; /* Remember fd */
|
||||
tv->tv_sec = select_timeout / 1000;
|
||||
tv->tv_usec = (select_timeout % 1000) * 1000;
|
||||
*timeout = True;
|
||||
break;
|
||||
}
|
||||
if (iorq->itv_timeout && iorq->partial_len > 0
|
||||
&& (select_timeout == 0
|
||||
|| iorq->itv_timeout < select_timeout))
|
||||
{
|
||||
/* Set new timeout */
|
||||
select_timeout = iorq->itv_timeout;
|
||||
g_min_timeout_fd = iorq->fd; /* Remember fd */
|
||||
tv->tv_sec = select_timeout / 1000;
|
||||
tv->tv_usec = (select_timeout % 1000) * 1000;
|
||||
*timeout = True;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case IRP_MJ_WRITE:
|
||||
@ -857,6 +891,11 @@ rdpdr_add_fds(int *n, fd_set * rfds, fd_set * wfds, struct timeval *tv, BOOL * t
|
||||
*n = MAX(*n, iorq->fd);
|
||||
break;
|
||||
|
||||
case IRP_MJ_DEVICE_CONTROL:
|
||||
if (select_timeout > 5)
|
||||
select_timeout = 5; /* serial event queue */
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -891,7 +930,7 @@ rdpdr_remove_iorequest(struct async_iorequest *prev, struct async_iorequest *ior
|
||||
|
||||
/* Check if select() returned with one of the rdpdr file descriptors, and complete io if it did */
|
||||
void
|
||||
rdpdr_check_fds(fd_set * rfds, fd_set * wfds, BOOL timed_out)
|
||||
_rdpdr_check_fds(fd_set * rfds, fd_set * wfds, BOOL timed_out)
|
||||
{
|
||||
NTSTATUS status;
|
||||
uint32 result = 0;
|
||||
@ -899,9 +938,53 @@ rdpdr_check_fds(fd_set * rfds, fd_set * wfds, BOOL timed_out)
|
||||
struct async_iorequest *iorq;
|
||||
struct async_iorequest *prev;
|
||||
uint32 req_size = 0;
|
||||
uint32 buffer_len;
|
||||
struct stream out;
|
||||
uint8 *buffer = NULL;
|
||||
|
||||
|
||||
if (timed_out)
|
||||
{
|
||||
/* check serial iv_timeout */
|
||||
|
||||
iorq = g_iorequest;
|
||||
prev = NULL;
|
||||
while (iorq != NULL)
|
||||
{
|
||||
if (iorq->fd == g_min_timeout_fd)
|
||||
{
|
||||
if ((iorq->partial_len > 0) &&
|
||||
(g_rdpdr_device[iorq->device].device_type ==
|
||||
DEVICE_TYPE_SERIAL))
|
||||
{
|
||||
|
||||
/* iv_timeout between 2 chars, send partial_len */
|
||||
//printf("RDPDR: IVT total %u bytes read of %u\n", iorq->partial_len, iorq->length);
|
||||
rdpdr_send_completion(iorq->device,
|
||||
iorq->id, STATUS_SUCCESS,
|
||||
iorq->partial_len,
|
||||
iorq->buffer, iorq->partial_len);
|
||||
iorq = rdpdr_remove_iorequest(prev, iorq);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
prev = iorq;
|
||||
if (iorq)
|
||||
iorq = iorq->next;
|
||||
|
||||
}
|
||||
|
||||
rdpdr_abort_io(g_min_timeout_fd, 0, STATUS_TIMEOUT);
|
||||
return;
|
||||
}
|
||||
@ -929,7 +1012,7 @@ rdpdr_check_fds(fd_set * rfds, fd_set * wfds, BOOL timed_out)
|
||||
iorq->buffer + iorq->partial_len,
|
||||
req_size, iorq->offset, &result);
|
||||
|
||||
if (result > 0)
|
||||
if ((long) result > 0)
|
||||
{
|
||||
iorq->partial_len += result;
|
||||
iorq->offset += result;
|
||||
@ -940,8 +1023,7 @@ rdpdr_check_fds(fd_set * rfds, fd_set * wfds, BOOL timed_out)
|
||||
/* only delete link if all data has been transfered */
|
||||
/* or if result was 0 and status success - EOF */
|
||||
if ((iorq->partial_len == iorq->length) ||
|
||||
(g_rdpdr_device[iorq->device].device_type ==
|
||||
DEVICE_TYPE_SERIAL) || (result == 0))
|
||||
(result == 0))
|
||||
{
|
||||
#if WITH_DEBUG_RDP5
|
||||
DEBUG(("RDPDR: AIO total %u bytes read of %u\n", iorq->partial_len, iorq->length));
|
||||
@ -972,7 +1054,7 @@ rdpdr_check_fds(fd_set * rfds, fd_set * wfds, BOOL timed_out)
|
||||
iorq->partial_len, req_size,
|
||||
iorq->offset, &result);
|
||||
|
||||
if (result > 0)
|
||||
if ((long) result > 0)
|
||||
{
|
||||
iorq->partial_len += result;
|
||||
iorq->offset += result;
|
||||
@ -998,6 +1080,23 @@ rdpdr_check_fds(fd_set * rfds, fd_set * wfds, BOOL timed_out)
|
||||
iorq = rdpdr_remove_iorequest(prev, iorq);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case IRP_MJ_DEVICE_CONTROL:
|
||||
if (serial_get_event(iorq->fd, &result))
|
||||
{
|
||||
buffer = (uint8 *) xrealloc((void *) buffer, 0x14);
|
||||
out.data = out.p = buffer;
|
||||
out.size = sizeof(buffer);
|
||||
out_uint32_le(&out, result);
|
||||
result = buffer_len = out.p - out.data;
|
||||
status = STATUS_SUCCESS;
|
||||
rdpdr_send_completion(iorq->device, iorq->id,
|
||||
status, result, buffer,
|
||||
buffer_len);
|
||||
xfree(buffer);
|
||||
iorq = rdpdr_remove_iorequest(prev, iorq);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1007,8 +1106,68 @@ rdpdr_check_fds(fd_set * rfds, fd_set * wfds, BOOL timed_out)
|
||||
iorq = iorq->next;
|
||||
}
|
||||
|
||||
/* Check notify */
|
||||
iorq = g_iorequest;
|
||||
prev = NULL;
|
||||
while (iorq != NULL)
|
||||
{
|
||||
if (iorq->fd != 0)
|
||||
{
|
||||
switch (iorq->major)
|
||||
{
|
||||
|
||||
case IRP_MJ_DIRECTORY_CONTROL:
|
||||
if (g_rdpdr_device[iorq->device].device_type ==
|
||||
DEVICE_TYPE_DISK)
|
||||
{
|
||||
|
||||
if (g_notify_stamp)
|
||||
{
|
||||
g_notify_stamp = False;
|
||||
status = disk_check_notify(iorq->fd);
|
||||
if (status != STATUS_PENDING)
|
||||
{
|
||||
rdpdr_send_completion(iorq->device,
|
||||
iorq->id,
|
||||
status, 0,
|
||||
NULL, 0);
|
||||
iorq = rdpdr_remove_iorequest(prev,
|
||||
iorq);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
prev = iorq;
|
||||
if (iorq)
|
||||
iorq = iorq->next;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
rdpdr_check_fds(fd_set * rfds, fd_set * wfds, BOOL timed_out)
|
||||
{
|
||||
fd_set dummy;
|
||||
|
||||
|
||||
FD_ZERO(&dummy);
|
||||
|
||||
|
||||
/* fist check event queue only,
|
||||
any serial wait event must be done before read block will be sent
|
||||
*/
|
||||
|
||||
_rdpdr_check_fds(&dummy, &dummy, False);
|
||||
_rdpdr_check_fds(rfds, wfds, timed_out);
|
||||
}
|
||||
|
||||
|
||||
/* Abort a pending io request for a given handle and major */
|
||||
BOOL
|
||||
rdpdr_abort_io(uint32 fd, uint32 major, NTSTATUS status)
|
||||
|
413
serial.c
413
serial.c
@ -5,6 +5,12 @@
|
||||
#include <sys/ioctl.h>
|
||||
#include "rdesktop.h"
|
||||
|
||||
#ifdef WITH_DEBUG_SERIAL
|
||||
#define DEBUG_SERIAL(args) printf args;
|
||||
#else
|
||||
#define DEBUG_SERIAL(args)
|
||||
#endif
|
||||
|
||||
#define FILE_DEVICE_SERIAL_PORT 0x1b
|
||||
|
||||
#define SERIAL_SET_BAUD_RATE 1
|
||||
@ -75,15 +81,39 @@
|
||||
#define SERIAL_EV_EVENT2 0x1000 // Provider specific event 2
|
||||
|
||||
/* Modem Status */
|
||||
#define SERIAL_MS_DTR 0x01
|
||||
#define SERIAL_MS_RTS 0x02
|
||||
#define SERIAL_MS_CTS 0x10
|
||||
#define SERIAL_MS_DSR 0x20
|
||||
#define SERIAL_MS_RNG 0x40
|
||||
#define SERIAL_MS_CAR 0x80
|
||||
|
||||
/* Handflow */
|
||||
#define SERIAL_DTR_CONTROL 0x01
|
||||
#define SERIAL_CTS_HANDSHAKE 0x08
|
||||
#define SERIAL_ERROR_ABORT 0x80000000
|
||||
|
||||
#define SERIAL_XON_HANDSHAKE 0x01
|
||||
#define SERIAL_XOFF_HANDSHAKE 0x02
|
||||
#define SERIAL_DSR_SENSITIVITY 0x40
|
||||
|
||||
#define SERIAL_CHAR_EOF 0
|
||||
#define SERIAL_CHAR_ERROR 1
|
||||
#define SERIAL_CHAR_BREAK 2
|
||||
#define SERIAL_CHAR_EVENT 3
|
||||
#define SERIAL_CHAR_XON 4
|
||||
#define SERIAL_CHAR_XOFF 5
|
||||
|
||||
#ifndef CRTSCTS
|
||||
#define CRTSCTS 0
|
||||
#endif
|
||||
|
||||
/* FIONREAD should really do the same thing as TIOCINQ, where it is
|
||||
* not available */
|
||||
#ifndef TIOCINQ
|
||||
#include <sys/filio.h>
|
||||
#define TIOCINQ FIONREAD
|
||||
#endif
|
||||
|
||||
extern RDPDR_DEVICE g_rdpdr_device[];
|
||||
|
||||
@ -188,9 +218,19 @@ get_termios(SERIAL_DEVICE * pser_inf, NTHANDLE serial_fd)
|
||||
case B115200:
|
||||
pser_inf->baud_rate = 115200;
|
||||
break;
|
||||
#endif
|
||||
#ifdef B230400
|
||||
case B230400:
|
||||
pser_inf->baud_rate = 230400;
|
||||
break;
|
||||
#endif
|
||||
#ifdef B460800
|
||||
case B460800:
|
||||
pser_inf->baud_rate = 460800;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
pser_inf->baud_rate = 0;
|
||||
pser_inf->baud_rate = 9600;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -218,7 +258,27 @@ get_termios(SERIAL_DEVICE * pser_inf, NTHANDLE serial_fd)
|
||||
break;
|
||||
}
|
||||
|
||||
pser_inf->rts = (ptermios->c_cflag & CRTSCTS) ? 1 : 0;
|
||||
if (ptermios->c_cflag & CRTSCTS)
|
||||
{
|
||||
pser_inf->control = SERIAL_DTR_CONTROL | SERIAL_CTS_HANDSHAKE | SERIAL_ERROR_ABORT;
|
||||
}
|
||||
else
|
||||
{
|
||||
pser_inf->control = SERIAL_DTR_CONTROL | SERIAL_ERROR_ABORT;
|
||||
}
|
||||
|
||||
pser_inf->xonoff = SERIAL_DSR_SENSITIVITY;
|
||||
if (ptermios->c_iflag & IXON)
|
||||
pser_inf->xonoff |= SERIAL_XON_HANDSHAKE;
|
||||
|
||||
if (ptermios->c_iflag & IXOFF)
|
||||
pser_inf->xonoff |= SERIAL_XOFF_HANDSHAKE;
|
||||
|
||||
pser_inf->chars[SERIAL_CHAR_XON] = ptermios->c_cc[VSTART];
|
||||
pser_inf->chars[SERIAL_CHAR_XOFF] = ptermios->c_cc[VSTOP];
|
||||
pser_inf->chars[SERIAL_CHAR_EOF] = ptermios->c_cc[VEOF];
|
||||
pser_inf->chars[SERIAL_CHAR_BREAK] = ptermios->c_cc[VINTR];
|
||||
pser_inf->chars[SERIAL_CHAR_ERROR] = ptermios->c_cc[VKILL];
|
||||
|
||||
return True;
|
||||
}
|
||||
@ -309,16 +369,31 @@ set_termios(SERIAL_DEVICE * pser_inf, NTHANDLE serial_fd)
|
||||
case 115200:
|
||||
speed = B115200;
|
||||
break;
|
||||
#endif
|
||||
#ifdef B230400
|
||||
case 230400:
|
||||
speed = B115200;
|
||||
break;
|
||||
#endif
|
||||
#ifdef B460800
|
||||
case 460800:
|
||||
speed = B115200;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
speed = B0;
|
||||
speed = B9600;
|
||||
break;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* on systems with separate ispeed and ospeed, we can remember the speed
|
||||
in ispeed while changing DTR with ospeed */
|
||||
cfsetispeed(pser_inf->ptermios, speed);
|
||||
cfsetospeed(pser_inf->ptermios, pser_inf->dtr ? speed : 0);
|
||||
#endif
|
||||
|
||||
ptermios->c_cflag &= ~CBAUD;
|
||||
ptermios->c_cflag |= speed;
|
||||
|
||||
ptermios->c_cflag &= ~(CSTOPB | PARENB | PARODD | CSIZE | CRTSCTS);
|
||||
switch (pser_inf->stop_bits)
|
||||
@ -326,6 +401,9 @@ set_termios(SERIAL_DEVICE * pser_inf, NTHANDLE serial_fd)
|
||||
case STOP_BITS_2:
|
||||
ptermios->c_cflag |= CSTOPB;
|
||||
break;
|
||||
default:
|
||||
ptermios->c_cflag &= ~CSTOPB;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (pser_inf->parity)
|
||||
@ -336,6 +414,9 @@ set_termios(SERIAL_DEVICE * pser_inf, NTHANDLE serial_fd)
|
||||
case ODD_PARITY:
|
||||
ptermios->c_cflag |= PARENB | PARODD;
|
||||
break;
|
||||
case NO_PARITY:
|
||||
ptermios->c_cflag &= ~(PARENB | PARODD);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (pser_inf->word_length)
|
||||
@ -354,8 +435,43 @@ set_termios(SERIAL_DEVICE * pser_inf, NTHANDLE serial_fd)
|
||||
break;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (pser_inf->rts)
|
||||
ptermios->c_cflag |= CRTSCTS;
|
||||
else
|
||||
ptermios->c_cflag &= ~CRTSCTS;
|
||||
#endif
|
||||
|
||||
if (pser_inf->control & SERIAL_CTS_HANDSHAKE)
|
||||
{
|
||||
ptermios->c_cflag |= CRTSCTS;
|
||||
}
|
||||
else
|
||||
{
|
||||
ptermios->c_cflag &= ~CRTSCTS;
|
||||
}
|
||||
|
||||
|
||||
if (pser_inf->xonoff & SERIAL_XON_HANDSHAKE)
|
||||
{
|
||||
ptermios->c_iflag |= IXON | IMAXBEL;
|
||||
}
|
||||
if (pser_inf->xonoff & SERIAL_XOFF_HANDSHAKE)
|
||||
{
|
||||
ptermios->c_iflag |= IXOFF | IMAXBEL;
|
||||
}
|
||||
|
||||
if ((pser_inf->xonoff & (SERIAL_XOFF_HANDSHAKE | SERIAL_XON_HANDSHAKE)) == 0)
|
||||
{
|
||||
ptermios->c_iflag &= ~IXON;
|
||||
ptermios->c_iflag &= ~IXOFF;
|
||||
}
|
||||
|
||||
ptermios->c_cc[VSTART] = pser_inf->chars[SERIAL_CHAR_XON];
|
||||
ptermios->c_cc[VSTOP] = pser_inf->chars[SERIAL_CHAR_XOFF];
|
||||
ptermios->c_cc[VEOF] = pser_inf->chars[SERIAL_CHAR_EOF];
|
||||
ptermios->c_cc[VINTR] = pser_inf->chars[SERIAL_CHAR_BREAK];
|
||||
ptermios->c_cc[VKILL] = pser_inf->chars[SERIAL_CHAR_ERROR];
|
||||
|
||||
tcsetattr(serial_fd, TCSANOW, ptermios);
|
||||
}
|
||||
@ -434,31 +550,31 @@ serial_create(uint32 device_id, uint32 access, uint32 share_mode, uint32 disposi
|
||||
g_rdpdr_device[device_id].handle = serial_fd;
|
||||
|
||||
/* some sane information */
|
||||
printf("INFO: SERIAL %s to %s\nINFO: speed %u baud, stop bits %u, parity %u, word length %u bits, dtr %u, rts %u\n", g_rdpdr_device[device_id].name, g_rdpdr_device[device_id].local_path, pser_inf->baud_rate, pser_inf->stop_bits, pser_inf->parity, pser_inf->word_length, pser_inf->dtr, pser_inf->rts);
|
||||
DEBUG_SERIAL(("INFO: SERIAL %s to %s\nINFO: speed %u baud, stop bits %u, parity %u, word length %u bits, dtr %u, rts %u\n", g_rdpdr_device[device_id].name, g_rdpdr_device[device_id].local_path, pser_inf->baud_rate, pser_inf->stop_bits, pser_inf->parity, pser_inf->word_length, pser_inf->dtr, pser_inf->rts));
|
||||
|
||||
printf("INFO: use stty to change settings\n");
|
||||
|
||||
/* ptermios->c_cflag = B115200 | CRTSCTS | CS8 | CLOCAL | CREAD;
|
||||
ptermios->c_cflag |= CREAD;
|
||||
ptermios->c_lflag |= ICANON;
|
||||
ptermios->c_iflag = IGNPAR | ICRNL;
|
||||
|
||||
tcsetattr(serial_fd, TCSANOW, ptermios);
|
||||
*/
|
||||
pser_inf->ptermios->c_iflag &=
|
||||
~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
|
||||
pser_inf->ptermios->c_oflag &= ~OPOST;
|
||||
pser_inf->ptermios->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
|
||||
pser_inf->ptermios->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN | XCASE);
|
||||
pser_inf->ptermios->c_cflag &= ~(CSIZE | PARENB);
|
||||
pser_inf->ptermios->c_cflag |= CS8;
|
||||
|
||||
tcsetattr(serial_fd, TCSANOW, pser_inf->ptermios);
|
||||
|
||||
pser_inf->event_txempty = 0;
|
||||
pser_inf->event_cts = 0;
|
||||
pser_inf->event_dsr = 0;
|
||||
pser_inf->event_rlsd = 0;
|
||||
pser_inf->event_pending = 0;
|
||||
|
||||
*handle = serial_fd;
|
||||
|
||||
/* all read and writes should be non blocking */
|
||||
if (fcntl(*handle, F_SETFL, O_NONBLOCK) == -1)
|
||||
perror("fcntl");
|
||||
|
||||
pser_inf->read_total_timeout_constant = 5;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
@ -468,6 +584,8 @@ serial_close(NTHANDLE handle)
|
||||
int i = get_device_index(handle);
|
||||
if (i >= 0)
|
||||
g_rdpdr_device[i].handle = 0;
|
||||
|
||||
rdpdr_abort_io(handle, 0, STATUS_TIMEOUT);
|
||||
close(handle);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
@ -478,6 +596,10 @@ serial_read(NTHANDLE handle, uint8 * data, uint32 length, uint32 offset, uint32
|
||||
long timeout;
|
||||
SERIAL_DEVICE *pser_inf;
|
||||
struct termios *ptermios;
|
||||
#ifdef WITH_DEBUG_SERIAL
|
||||
int bytes_inqueue;
|
||||
#endif
|
||||
|
||||
|
||||
timeout = 90;
|
||||
pser_inf = get_serial_info(handle);
|
||||
@ -511,10 +633,18 @@ serial_read(NTHANDLE handle, uint8 * data, uint32 length, uint32 offset, uint32
|
||||
}
|
||||
tcsetattr(handle, TCSANOW, ptermios);
|
||||
|
||||
#ifdef WITH_DEBUG_SERIAL
|
||||
ioctl(handle, TIOCINQ, &bytes_inqueue);
|
||||
DEBUG_SERIAL(("serial_read inqueue: %d expected %d\n", bytes_inqueue, length));
|
||||
#endif
|
||||
|
||||
*result = read(handle, data, length);
|
||||
|
||||
//hexdump(data, *read);
|
||||
#ifdef WITH_DEBUG_SERIAL
|
||||
DEBUG_SERIAL(("serial_read Bytes %d\n", *result));
|
||||
if (*result > 0)
|
||||
hexdump(data, *result);
|
||||
#endif
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
@ -522,16 +652,24 @@ serial_read(NTHANDLE handle, uint8 * data, uint32 length, uint32 offset, uint32
|
||||
static NTSTATUS
|
||||
serial_write(NTHANDLE handle, uint8 * data, uint32 length, uint32 offset, uint32 * result)
|
||||
{
|
||||
SERIAL_DEVICE *pser_inf;
|
||||
|
||||
pser_inf = get_serial_info(handle);
|
||||
|
||||
*result = write(handle, data, length);
|
||||
|
||||
if (*result > 0)
|
||||
pser_inf->event_txempty = *result;
|
||||
|
||||
DEBUG_SERIAL(("serial_write length %d, offset %d result %d\n", length, offset, *result));
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static NTSTATUS
|
||||
serial_device_control(NTHANDLE handle, uint32 request, STREAM in, STREAM out)
|
||||
{
|
||||
#if 0
|
||||
int flush_mask, purge_mask;
|
||||
#endif
|
||||
uint32 result, modemstate;
|
||||
uint8 immediate;
|
||||
SERIAL_DEVICE *pser_inf;
|
||||
@ -547,81 +685,134 @@ serial_device_control(NTHANDLE handle, uint32 request, STREAM in, STREAM out)
|
||||
request >>= 2;
|
||||
request &= 0xfff;
|
||||
|
||||
printf("SERIAL IOCTL %d\n", request);
|
||||
|
||||
switch (request)
|
||||
{
|
||||
case SERIAL_SET_BAUD_RATE:
|
||||
in_uint32_le(in, pser_inf->baud_rate);
|
||||
set_termios(pser_inf, handle);
|
||||
DEBUG_SERIAL(("serial_ioctl -> SERIAL_SET_BAUD_RATE %d\n", pser_inf->baud_rate));
|
||||
break;
|
||||
case SERIAL_GET_BAUD_RATE:
|
||||
out_uint32_le(out, pser_inf->baud_rate);
|
||||
DEBUG_SERIAL(("serial_ioctl -> SERIAL_GET_BAUD_RATE %d\n", pser_inf->baud_rate));
|
||||
break;
|
||||
case SERIAL_SET_QUEUE_SIZE:
|
||||
in_uint32_le(in, pser_inf->queue_in_size);
|
||||
in_uint32_le(in, pser_inf->queue_out_size);
|
||||
DEBUG_SERIAL(("serial_ioctl -> SERIAL_SET_QUEUE_SIZE in %d out %d\n",
|
||||
pser_inf->queue_in_size, pser_inf->queue_out_size));
|
||||
break;
|
||||
case SERIAL_SET_LINE_CONTROL:
|
||||
in_uint8(in, pser_inf->stop_bits);
|
||||
in_uint8(in, pser_inf->parity);
|
||||
in_uint8(in, pser_inf->word_length);
|
||||
set_termios(pser_inf, handle);
|
||||
DEBUG_SERIAL(("serial_ioctl -> SERIAL_SET_LINE_CONTROL stop %d parity %d word %d\n",
|
||||
pser_inf->stop_bits, pser_inf->parity, pser_inf->word_length));
|
||||
break;
|
||||
case SERIAL_GET_LINE_CONTROL:
|
||||
DEBUG_SERIAL(("serial_ioctl -> SERIAL_GET_LINE_CONTROL\n"));
|
||||
out_uint8(out, pser_inf->stop_bits);
|
||||
out_uint8(out, pser_inf->parity);
|
||||
out_uint8(out, pser_inf->word_length);
|
||||
break;
|
||||
case SERIAL_IMMEDIATE_CHAR:
|
||||
DEBUG_SERIAL(("serial_ioctl -> SERIAL_IMMEDIATE_CHAR\n"));
|
||||
in_uint8(in, immediate);
|
||||
serial_write(handle, &immediate, 1, 0, &result);
|
||||
break;
|
||||
case SERIAL_CONFIG_SIZE:
|
||||
DEBUG_SERIAL(("serial_ioctl -> SERIAL_CONFIG_SIZE\n"));
|
||||
out_uint32_le(out, 0);
|
||||
break;
|
||||
case SERIAL_GET_CHARS:
|
||||
out_uint8s(out, 6);
|
||||
DEBUG_SERIAL(("serial_ioctl -> SERIAL_GET_CHARS\n"));
|
||||
out_uint8a(out, pser_inf->chars, 6);
|
||||
break;
|
||||
case SERIAL_SET_CHARS:
|
||||
in_uint8s(in, 6);
|
||||
DEBUG_SERIAL(("serial_ioctl -> SERIAL_SET_CHARS\n"));
|
||||
in_uint8a(in, pser_inf->chars, 6);
|
||||
#ifdef WITH_DEBUG_SERIAL
|
||||
hexdump(pser_inf->chars, 6);
|
||||
#endif
|
||||
set_termios(pser_inf, handle);
|
||||
break;
|
||||
case SERIAL_GET_HANDFLOW:
|
||||
out_uint32_le(out, 0);
|
||||
out_uint32_le(out, 3); /* Xon/Xoff */
|
||||
out_uint32_le(out, 0);
|
||||
out_uint32_le(out, 0);
|
||||
DEBUG_SERIAL(("serial_ioctl -> SERIAL_GET_HANDFLOW\n"));
|
||||
get_termios(pser_inf, handle);
|
||||
out_uint32_le(out, pser_inf->control);
|
||||
out_uint32_le(out, pser_inf->xonoff); /* Xon/Xoff */
|
||||
out_uint32_le(out, pser_inf->onlimit);
|
||||
out_uint32_le(out, pser_inf->offlimit);
|
||||
break;
|
||||
case SERIAL_SET_HANDFLOW:
|
||||
in_uint8s(in, 16);
|
||||
in_uint32_le(in, pser_inf->control);
|
||||
in_uint32_le(in, pser_inf->xonoff);
|
||||
in_uint32_le(in, pser_inf->onlimit);
|
||||
in_uint32_le(in, pser_inf->offlimit);
|
||||
DEBUG_SERIAL(("serial_ioctl -> SERIAL_SET_HANDFLOW %x %x %x %x\n",
|
||||
pser_inf->control, pser_inf->xonoff, pser_inf->onlimit,
|
||||
pser_inf->onlimit));
|
||||
set_termios(pser_inf, handle);
|
||||
break;
|
||||
case SERIAL_SET_TIMEOUTS:
|
||||
in_uint8s(in, 20);
|
||||
in_uint32(in, pser_inf->read_interval_timeout);
|
||||
in_uint32(in, pser_inf->read_total_timeout_multiplier);
|
||||
in_uint32(in, pser_inf->read_total_timeout_constant);
|
||||
in_uint32(in, pser_inf->write_total_timeout_multiplier);
|
||||
in_uint32(in, pser_inf->write_total_timeout_constant);
|
||||
DEBUG_SERIAL(("serial_ioctl -> SERIAL_SET_TIMEOUTS read timeout %d %d %d\n",
|
||||
pser_inf->read_interval_timeout,
|
||||
pser_inf->read_total_timeout_multiplier,
|
||||
pser_inf->read_total_timeout_constant));
|
||||
break;
|
||||
case SERIAL_GET_TIMEOUTS:
|
||||
out_uint8s(out, 20);
|
||||
DEBUG_SERIAL(("serial_ioctl -> SERIAL_GET_TIMEOUTS read timeout %d %d %d\n",
|
||||
pser_inf->read_interval_timeout,
|
||||
pser_inf->read_total_timeout_multiplier,
|
||||
pser_inf->read_total_timeout_constant));
|
||||
|
||||
out_uint32(out, pser_inf->read_interval_timeout);
|
||||
out_uint32(out, pser_inf->read_total_timeout_multiplier);
|
||||
out_uint32(out, pser_inf->read_total_timeout_constant);
|
||||
out_uint32(out, pser_inf->write_total_timeout_multiplier);
|
||||
out_uint32(out, pser_inf->write_total_timeout_constant);
|
||||
break;
|
||||
case SERIAL_GET_WAIT_MASK:
|
||||
out_uint32(out, pser_inf->wait_mask);
|
||||
DEBUG_SERIAL(("serial_ioctl -> SERIAL_GET_WAIT_MASK %X\n", pser_inf->wait_mask);
|
||||
out_uint32(out, pser_inf->wait_mask));
|
||||
break;
|
||||
case SERIAL_SET_WAIT_MASK:
|
||||
in_uint32(in, pser_inf->wait_mask);
|
||||
DEBUG_SERIAL(("serial_ioctl -> SERIAL_SET_WAIT_MASK %X\n", pser_inf->wait_mask));
|
||||
break;
|
||||
case SERIAL_SET_DTR:
|
||||
DEBUG_SERIAL(("serial_ioctl -> SERIAL_SET_DTR\n"));
|
||||
ioctl(handle, TIOCMGET, &result);
|
||||
result |= TIOCM_DTR;
|
||||
ioctl(handle, TIOCMSET, &result);
|
||||
pser_inf->dtr = 1;
|
||||
set_termios(pser_inf, handle);
|
||||
break;
|
||||
case SERIAL_CLR_DTR:
|
||||
DEBUG_SERIAL(("serial_ioctl -> SERIAL_CLR_DTR\n"));
|
||||
ioctl(handle, TIOCMGET, &result);
|
||||
result &= ~TIOCM_DTR;
|
||||
ioctl(handle, TIOCMSET, &result);
|
||||
pser_inf->dtr = 0;
|
||||
set_termios(pser_inf, handle);
|
||||
break;
|
||||
case SERIAL_SET_RTS:
|
||||
DEBUG_SERIAL(("serial_ioctl -> SERIAL_SET_RTS\n"));
|
||||
ioctl(handle, TIOCMGET, &result);
|
||||
result |= TIOCM_RTS;
|
||||
ioctl(handle, TIOCMSET, &result);
|
||||
pser_inf->rts = 1;
|
||||
set_termios(pser_inf, handle);
|
||||
break;
|
||||
case SERIAL_CLR_RTS:
|
||||
DEBUG_SERIAL(("serial_ioctl -> SERIAL_CLR_RTS\n"));
|
||||
ioctl(handle, TIOCMGET, &result);
|
||||
result &= ~TIOCM_RTS;
|
||||
ioctl(handle, TIOCMSET, &result);
|
||||
pser_inf->rts = 0;
|
||||
set_termios(pser_inf, handle);
|
||||
break;
|
||||
case SERIAL_GET_MODEMSTATUS:
|
||||
modemstate = 0;
|
||||
@ -635,46 +826,76 @@ serial_device_control(NTHANDLE handle, uint32 request, STREAM in, STREAM out)
|
||||
modemstate |= SERIAL_MS_RNG;
|
||||
if (result & TIOCM_CAR)
|
||||
modemstate |= SERIAL_MS_CAR;
|
||||
if (result & TIOCM_DTR)
|
||||
modemstate |= SERIAL_MS_DTR;
|
||||
if (result & TIOCM_RTS)
|
||||
modemstate |= SERIAL_MS_RTS;
|
||||
#endif
|
||||
DEBUG_SERIAL(("serial_ioctl -> SERIAL_GET_MODEMSTATUS %X\n", modemstate));
|
||||
out_uint32_le(out, modemstate);
|
||||
break;
|
||||
case SERIAL_GET_COMMSTATUS:
|
||||
out_uint32_le(out, 0); /* Errors */
|
||||
out_uint32_le(out, 0); /* Hold reasons */
|
||||
out_uint32_le(out, 0); /* Amount in in queue */
|
||||
out_uint32_le(out, 0); /* Amount in out queue */
|
||||
|
||||
result = 0;
|
||||
ioctl(handle, TIOCINQ, &result);
|
||||
out_uint32_le(out, result); /* Amount in in queue */
|
||||
if (result)
|
||||
DEBUG_SERIAL(("serial_ioctl -> SERIAL_GET_COMMSTATUS in queue %d\n", result));
|
||||
|
||||
result = 0;
|
||||
ioctl(handle, TIOCOUTQ, &result);
|
||||
out_uint32_le(out, result); /* Amount in out queue */
|
||||
if (result)
|
||||
DEBUG_SERIAL(("serial_ioctl -> SERIAL_GET_COMMSTATUS out queue %d\n", result));
|
||||
|
||||
out_uint8(out, 0); /* EofReceived */
|
||||
out_uint8(out, 0); /* WaitForImmediate */
|
||||
break;
|
||||
#if 0
|
||||
case SERIAL_PURGE:
|
||||
printf("SERIAL_PURGE\n");
|
||||
in_uint32(in, purge_mask);
|
||||
if (purge_mask & 0x04)
|
||||
DEBUG_SERIAL(("serial_ioctl -> SERIAL_PURGE purge_mask %X\n", purge_mask));
|
||||
flush_mask = 0;
|
||||
if (purge_mask & SERIAL_PURGE_TXCLEAR)
|
||||
flush_mask |= TCOFLUSH;
|
||||
if (purge_mask & 0x08)
|
||||
if (purge_mask & SERIAL_PURGE_RXCLEAR)
|
||||
flush_mask |= TCIFLUSH;
|
||||
if (flush_mask != 0)
|
||||
tcflush(handle, flush_mask);
|
||||
if (purge_mask & 0x01)
|
||||
if (purge_mask & SERIAL_PURGE_TXABORT)
|
||||
rdpdr_abort_io(handle, 4, STATUS_CANCELLED);
|
||||
if (purge_mask & 0x02)
|
||||
if (purge_mask & SERIAL_PURGE_RXABORT)
|
||||
rdpdr_abort_io(handle, 3, STATUS_CANCELLED);
|
||||
break;
|
||||
case SERIAL_WAIT_ON_MASK:
|
||||
/* XXX implement me */
|
||||
out_uint32_le(out, pser_inf->wait_mask);
|
||||
DEBUG_SERIAL(("serial_ioctl -> SERIAL_WAIT_ON_MASK %X\n", pser_inf->wait_mask));
|
||||
pser_inf->event_pending = 1;
|
||||
if (serial_get_event(handle, &result))
|
||||
{
|
||||
DEBUG_SERIAL(("WAIT end event = %x\n", result));
|
||||
out_uint32_le(out, result);
|
||||
break;
|
||||
}
|
||||
return STATUS_PENDING;
|
||||
break;
|
||||
case SERIAL_SET_BREAK_ON:
|
||||
tcsendbreak(serial_fd, 0);
|
||||
DEBUG_SERIAL(("serial_ioctl -> SERIAL_SET_BREAK_ON\n"));
|
||||
tcsendbreak(handle, 0);
|
||||
break;
|
||||
case SERIAL_RESET_DEVICE:
|
||||
case SERIAL_SET_BREAK_OFF:
|
||||
case SERIAL_SET_XOFF:
|
||||
case SERIAL_SET_XON:
|
||||
/* ignore */
|
||||
DEBUG_SERIAL(("serial_ioctl -> SERIAL_RESET_DEVICE\n"));
|
||||
break;
|
||||
case SERIAL_SET_BREAK_OFF:
|
||||
DEBUG_SERIAL(("serial_ioctl -> SERIAL_SET_BREAK_OFF\n"));
|
||||
break;
|
||||
case SERIAL_SET_XOFF:
|
||||
DEBUG_SERIAL(("serial_ioctl -> SERIAL_SET_XOFF\n"));
|
||||
break;
|
||||
case SERIAL_SET_XON:
|
||||
DEBUG_SERIAL(("serial_ioctl -> SERIAL_SET_XON\n"));
|
||||
tcflow(handle, TCION);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
unimpl("SERIAL IOCTL %d\n", request);
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
@ -683,6 +904,100 @@ serial_device_control(NTHANDLE handle, uint32 request, STREAM in, STREAM out)
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
BOOL
|
||||
serial_get_event(NTHANDLE handle, uint32 * result)
|
||||
{
|
||||
int index;
|
||||
SERIAL_DEVICE *pser_inf;
|
||||
int bytes;
|
||||
BOOL ret = False;
|
||||
|
||||
*result = 0;
|
||||
index = get_device_index(handle);
|
||||
if (index < 0)
|
||||
return False;
|
||||
|
||||
pser_inf = (SERIAL_DEVICE *) g_rdpdr_device[index].pdevice_data;
|
||||
|
||||
|
||||
ioctl(handle, TIOCINQ, &bytes);
|
||||
|
||||
if (bytes > 0)
|
||||
{
|
||||
DEBUG_SERIAL(("serial_get_event Bytes %d\n", bytes));
|
||||
if (bytes > pser_inf->event_rlsd)
|
||||
{
|
||||
pser_inf->event_rlsd = bytes;
|
||||
if (pser_inf->wait_mask & SERIAL_EV_RLSD)
|
||||
{
|
||||
DEBUG_SERIAL(("Event -> SERIAL_EV_RLSD \n"));
|
||||
*result |= SERIAL_EV_RLSD;
|
||||
ret = True;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ((bytes > 1) && (pser_inf->wait_mask & SERIAL_EV_RXFLAG))
|
||||
{
|
||||
DEBUG_SERIAL(("Event -> SERIAL_EV_RXFLAG Bytes %d\n", bytes));
|
||||
*result |= SERIAL_EV_RXFLAG;
|
||||
ret = True;
|
||||
}
|
||||
if ((pser_inf->wait_mask & SERIAL_EV_RXCHAR))
|
||||
{
|
||||
DEBUG_SERIAL(("Event -> SERIAL_EV_RXCHAR Bytes %d\n", bytes));
|
||||
*result |= SERIAL_EV_RXCHAR;
|
||||
ret = True;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
pser_inf->event_rlsd = 0;
|
||||
}
|
||||
|
||||
|
||||
ioctl(handle, TIOCOUTQ, &bytes);
|
||||
if ((bytes == 0)
|
||||
&& (pser_inf->event_txempty > 0) && (pser_inf->wait_mask & SERIAL_EV_TXEMPTY))
|
||||
{
|
||||
|
||||
DEBUG_SERIAL(("Event -> SERIAL_EV_TXEMPTY\n"));
|
||||
*result |= SERIAL_EV_TXEMPTY;
|
||||
ret = True;
|
||||
}
|
||||
pser_inf->event_txempty = bytes;
|
||||
|
||||
|
||||
ioctl(handle, TIOCMGET, &bytes);
|
||||
if ((bytes & TIOCM_DSR) != pser_inf->event_dsr)
|
||||
{
|
||||
pser_inf->event_dsr = bytes & TIOCM_DSR;
|
||||
if (pser_inf->wait_mask & SERIAL_EV_DSR)
|
||||
{
|
||||
DEBUG_SERIAL(("event -> SERIAL_EV_DSR %s\n", (bytes & TIOCM_DSR) ? "ON" : "OFF"));
|
||||
*result |= SERIAL_EV_DSR;
|
||||
ret = True;
|
||||
}
|
||||
}
|
||||
|
||||
if ((bytes & TIOCM_CTS) != pser_inf->event_cts)
|
||||
{
|
||||
pser_inf->event_cts = bytes & TIOCM_CTS;
|
||||
if (pser_inf->wait_mask & SERIAL_EV_CTS)
|
||||
{
|
||||
DEBUG_SERIAL((" EVENT-> SERIAL_EV_CTS %s\n", (bytes & TIOCM_CTS) ? "ON" : "OFF"));
|
||||
*result |= SERIAL_EV_CTS;
|
||||
ret = True;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret)
|
||||
pser_inf->event_pending = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Read timeout for a given file descripter (device) when adding fd's to select() */
|
||||
BOOL
|
||||
serial_get_timeout(NTHANDLE handle, uint32 length, uint32 * timeout, uint32 * itv_timeout)
|
||||
|
16
types.h
16
types.h
@ -197,6 +197,7 @@ typedef struct rdpdr_serial_device_info
|
||||
{
|
||||
int dtr;
|
||||
int rts;
|
||||
uint32 control, xonoff, onlimit, offlimit;
|
||||
uint32 baud_rate,
|
||||
queue_in_size,
|
||||
queue_out_size,
|
||||
@ -206,7 +207,9 @@ typedef struct rdpdr_serial_device_info
|
||||
read_total_timeout_constant,
|
||||
write_total_timeout_multiplier, write_total_timeout_constant, posix_wait_mask;
|
||||
uint8 stop_bits, parity, word_length;
|
||||
uint8 chars[6];
|
||||
struct termios *ptermios, *pold_termios;
|
||||
int event_txempty, event_cts, event_dsr, event_rlsd, event_pending;
|
||||
}
|
||||
SERIAL_DEVICE;
|
||||
|
||||
@ -235,13 +238,24 @@ typedef struct rdpdr_printer_info
|
||||
}
|
||||
PRINTER;
|
||||
|
||||
typedef struct notify_data
|
||||
{
|
||||
time_t modify_time;
|
||||
time_t status_time;
|
||||
time_t total_time;
|
||||
unsigned int num_entries;
|
||||
}
|
||||
NOTIFY;
|
||||
|
||||
typedef struct fileinfo
|
||||
{
|
||||
uint32 device_id, flags_and_attributes;
|
||||
uint32 device_id, flags_and_attributes, accessmask;
|
||||
char path[256];
|
||||
DIR *pdir;
|
||||
struct dirent *pdirent;
|
||||
char pattern[64];
|
||||
BOOL delete_on_close;
|
||||
NOTIFY notify;
|
||||
uint32 info_class;
|
||||
}
|
||||
FILEINFO;
|
||||
|
9
xwin.c
9
xwin.c
@ -1435,12 +1435,9 @@ ui_select(int rdp_socket)
|
||||
error("select: %s\n", strerror(errno));
|
||||
|
||||
case 0:
|
||||
/* TODO: if tv.tv_sec just times out
|
||||
* we will segfault.
|
||||
* FIXME:
|
||||
*/
|
||||
//s_timeout = True;
|
||||
//rdpdr_check_fds(&rfds, &wfds, (BOOL) True);
|
||||
/* Abort serial read calls */
|
||||
if (s_timeout)
|
||||
rdpdr_check_fds(&rfds, &wfds, (BOOL) True);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user